Hi,这个购物车是通过 koa后台读取json数据,前台通过vue,vuex写的前台,小伙伴们主要还是思路要清楚哦,下面先来看看这个小型案例的魔法吧!!!!!
- home.js
- 主要写的首页渲染,,以及添加购物车的功能点
<template>
<div class="home">
<header>首页</header>
<section>
<div class="cont">
<dl v-for="(item,index) in data" :key="index">
<dt><img :src="item.img" alt=""></dt>
<dd>
<p class="tit"><span>{{item.title}}</span><button @click="add(item)">来一份</button></p>
<p>{{item.intro}}</p>
<p>¥{{item.price}}元</p>
</dd>
</dl>
</div>
</section>
<Footer></Footer>
</div>
</template>
<script>
import Footer from "../components/footer"
import axios from 'axios'
import {mapState,mapMutations} from 'vuex'
export default {
props:{
},
components:{
Footer,
},
data(){
return {
data:[]
}
},
computed:{
...mapState(['adddata']),
},
methods:{
...mapMutations(['changedata']),
add(adddata){ //添加进入购物车
this.$router.push("/shopcar")
this.$store.commit('changedata',adddata)
}
},
created(){
axios.get('/api').then(res => {
this.data=res.data.message
})
},
}
</script>
<style scoped lang="">
.home{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
header{
height: 44px;
width: 100%;
background: salmon;
line-height: 44px;
text-align: center;
}
section{
flex:1;
overflow-y:auto;
}
.cont dl{
width: 100%;
display: flex;
padding: 8px;
}
dl dt{
width: 110px;
height: 110px;
background: skyblue;
flex-shrink: 0;
}
dl dt img{
height:100%;
width:100%;
}
dl dd{
flex: 1;
padding-left: 10px;
line-height: 2.2;
}
dl dd .tit{
display: flex;
justify-content: space-between;
padding-right: 25px;
}
dl dd .tit button{
border: none;
background: none;
outline: none;
color: rgb(6, 196, 202);
font-size:16px;
}
</style>
- shopcar.js
- 主要的功能是添加订单,以及其他的传参
<template>
<div class="shopcar">
<header>购物车</header>
<section>
<!--购物车 -->
<div class="content">
<div class="title" v-for="(item,index) in adddata" :key="index">
<div class="names">
<span>{{item.title}}</span>
<span>{{item.price}}</span>
</div>
<div class="btn">
<button @click="add(item.num-1,item.id)">-</button>
<span>{{item.num}}</span>
<button @click="add(item.num+1,item.id)">+</button>
</div>
</div>
<div class="allPrice">
<span>总价:{{allPrice}}元</span>
<span>总数:{{allNum}}</span>
</div>
</div>
<!-- 订单 -->
<div class="order">
<p>联系方式</p>
<div class="froms">
<p>姓名:<input type="text" placeholder="请输入姓名" name id v-model="name"></p>
<p>电话:<input type="text" placeholder="请输入电话" name id v-model="tel"></p>
<p>地址:<input type="text" placeholder="请输入地址" name id v-model="address"></p>
</div>
<div class="bottom">
<button @click="clearAll">清除购物车</button>
<button @click="goOrder(allPrice)">下单</button>
</div>
</div>
</section>
<Footer></Footer>
</div>
</template>
<script>
import Footer from "../components/footer"
import {mapActions,mapState,mapMutations} from "vuex"
export default {
props:{
},
components:{
Footer
},
data(){
return {
name:"",
tel:null,
address:""
}
},
computed:{
...mapState(["adddata","allPrice","allNum"])
},
methods:{
...mapMutations(["addOrderList","clearAll"]),
add(num,id){ //加减
if(num<=1){
num=1;
}
this.$store.commit("addnum",{num,id})
},
//清空购物车
clearAll(){
},
goOrder(allPrice){ //跳转到订单页面
//获取本地时间
let time=new Date().toLocaleString()
let res=this.adddata.filter(item=>item.num)
let orderArr=[];
let obj={}
res.map(item=>{
obj={
title:item.title,
num:item.num
}
orderArr.push(obj)
console.log(orderArr,"111")
})
//获取订单信息
let orderObj={
time:time,
orderArr:orderArr,
con: [{ con: this.name }, { con: this.tel }, { con: this.address }],
allPrice,
tit:"货到付款"
}
//添加订单
this.addOrderList(orderObj) //传参
this.$router.push("/order")
},
},
created(){
},
mounted(){
}
}
</script>
<style scoped lang="">
.shopcar{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
header{
height: 44px;
width: 100%;
background: salmon;
line-height: 44px;
text-align: center;
}
section{
flex:1;
overflow-y: auto;
}
section .title{
display: flex;
width:100%;
height:80px;
padding:0px 10px;
box-sizing:border-box;
align-items: center;
border-bottom:1px solid #ccc;
}
.title .names{
width:240px;;
height:80px;
line-height:80px;
}
.title .names span:nth-child(2){
margin-left:20px;
}
.btn{
flex:1;
height:80px;
line-height: 80px;
}
.btn button{
height: 24px;
width:24px;
margin:0px 6px;
}
.allPrice{
height: 40px;
width:100%;
line-height: 40px;
background:silver;
justify-content:space-around;
display: flex;
}
.order{
width:100%;
height:150px;
}
.order>p{
height: 40px;
text-indent: 12px;
line-height: 40px;
font-weight: bold;
color:deepskyblue;
}
.froms{
height: 120px;
width:100%;
}
.froms p{
width:100%;
height:35px;
margin-left:10px;
}
.froms p input{
width:75%;
height:30px;
margin-left:5%;
text-indent: 10px;
border:1px solid #ccc;
}
.bottom{
height:50px;
width:100%;
display: flex;
justify-content: space-around;
}
.bottom button{
height:40px;
width:110px;
background: skyblue;
color:#fff;
border:0;
font-size:16px;
}
</style>
- order.js
- 对订单页面的渲染
<template>
<div>
<header>订单</header>
<section>
<div class="content">
<div class="title" v-for="(item,index) in orderList" :key="index">
<p>订餐时间:{{item.time}}</p>
<h4 style="color:#f7883a">订餐内容<p v-for="(ite,ind) in item.orderArr" :key="ind"><span>{{ite.title}}</span><span>{{ite.num}}</span></p></h4>
<h4>订餐信息<p v-for="(val,k) in item.con" :key="k"><span>{{val.con}}</span><span>{{val.con}}</span><span>{{val.con}}</span></p></h4>
<p style="color:red">合计金额{{item.allPrice}}</p>
<p>支付状态:{{item.tit}}</p>
</div>
</div>
</section>
<Footer></Footer>
</div>
</template>
<script>
import Footer from "../components/footer"
import {mapActions,mapState,mapMutations} from "vuex"
export default {
props:{
},
components:{
Footer
},
data(){
return {
}
},
computed:{
...mapState(["orderList"])
},
}
</script>
<style scoped lang="">
div{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
header{
height: 44px;
width: 100%;
background: salmon;
line-height: 44px;
text-align: center;
}
section{
flex:1;
overflow-y: auto;
}
.title{
padding:15px 0px;
width:100%;
padding:0px 10px;
box-sizing: border-box;
border:1px solid #ccc;
margin-top:2px;
}
.title p{
line-height: 1.9;
}
</style>
- mine.js
<div>
<header>我的</header>
<section></section>
<Footer></Footer>
</div>
</template>
<script>
import Footer from "../components/footer"
export default {
props:{
},
components:{
Footer
},
data(){
return {
}
},
computed:{
},
methods:{
},
created(){
},
mounted(){
}
}
</script>
<style scoped lang="">
div{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
header{
height: 44px;
width: 100%;
background: salmon;
line-height: 44px;
text-align: center;
}
section{
flex:1;
overflow-y: auto;
}
</style>
store下面有三个文件
- index.js
- store下面的
index.js
需要在main.js
引入进去注册实例
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
import state from './car/state'
import mutations from './car/mutations.js'
export default new Vuex.Store({
mutations,
state,
})
- state.js
const state ={
adddata:[],
allPrice:0,
allNum:0,
orderList:[]
}
export default state;
- mutation.js
const mutations = {
changedata(state, value) {
//点击添加购物车
console.log(state.adddata, value);
if (state.adddata.length == 0) {
state.adddata.push(value);
} else {
let ind = state.adddata.findIndex(item => {
return item.id == value.id;
});
if (ind == -1) {
state.adddata.num = 1;
state.adddata.push(value);
} else {
state.adddata[ind].num++;
}
}
let sum = 0;
state.adddata.map(item => {
return sum += item.price * item.num;
});
state.allPrice=sum
//总数
let nums=0;
state.adddata.map((item,index)=>{
return nums+=item.num*1
})
state.allNum=nums
},
addnum(state, obj) {
//点击加减
let ind = state.adddata.findIndex(item => {
return item.id == obj.id;
});
state.adddata[ind].num = obj.num;
//总价
let sum = 0;
state.adddata.map(item => {
return sum += item.price * item.num;
});
state.allPrice=sum
let nums=0;
state.adddata.map((item,index)=>{
return nums+=item.num*1
})
state.allNum=nums
},
clearAll(state, obj1) {
state.adddata.splice(0);
state.allPrice = 0;
},
addOrderList(state,objs){
state.orderList.push(objs)
console.log(state.orderList,"qqqq")
}
};
export default mutations;
- router index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../views/home'
import Mine from '../views/mine'
import Order from "../views/order"
import Shopcar from "../views/shopcar"
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},{
path: '/mine',
name: 'Mine',
component: Mine
},{
path: '/order',
name: 'Order',
component: Order
},{
path: '/shopcar',
name: 'Shopcar',
component: Shopcar
}
]
})
- footer.js 封装的footer.js
<footer>
<router-link to="/">首页</router-link>
<router-link to="/shopcar">购物车</router-link>
<router-link to="/order">订单</router-link>
<router-link to="/mine">我的</router-link>
</footer>
- data.json
[
{
"id": 0,
"img":"/static/img/1 (1).jpg",
"title": "北京老杂酱面",
"intro": "苏格兰打卤面,大杯可乐",
"price": 24,
"num": 1
},
{
"id": 1,
"img":"/static/img/1 (3).jpg",
"title": "油泼面",
"intro": "苏格兰打卤面,大杯可乐",
"price": 13,
"num": 1
},
{
"id": 2,
"img":"/static/img/2.jpg",
"title": "酸辣土豆丝",
"intro": "苏格兰打卤面,大杯可乐",
"price": 12,
"num": 1
},
{
"id": 3,
"img":"/static/img/3.jpg",
"title": "家乡味糖醋排骨",
"intro": "苏格兰打卤面,大杯可乐",
"price": 20,
"num": 1
},
{
"id": 4,
"title": "魏家凉皮",
"img":"/static/img/1 (2) - 副本.jpg",
"intro": "苏格兰打卤面,大杯可乐",
"price": 34,
"num": 1
},
{
"id": 5,
"img":"/static/img/5.jpg",
"title": "家乡味的酸汤肥牛",
"intro": "苏格兰打卤面,大杯可乐",
"price": 21,
"num": 1
},
{
"id": 6,
"title": "北京烤鸭",
"img":"/static/img/4.jpg",
"intro": "苏格兰打卤面,大杯可乐",
"price": 19,
"num": 1
},
{
"id": 7,
"title": "家乡凉拌黄瓜",
"img":"/static/img/3.jpg",
"intro": "苏格兰打卤面,大杯可乐",
"price": 43,
"num": 1
}
]
server index.js
- koa 后台读取数据,返回数据
let koa = require("koa");
let app = new koa();
let fs=require('fs');
let data=require('../src/mock/data.json')
let bodyParser=require('koa-bodyparser')
console.log(data)
console.log(bodyParser)
app.use(bodyParser())
app.use(async function(ctx){
// await next();
ctx.body={
message:JSON.parse(fs.readFileSync('../src/mock/data.json'))
}
})
app.listen(9090)