新建vue项目
此项目需要用到json-server,模拟后台服务器接口功能,
npm i json-server -g
安装此包,然后再vue项目的全局根目录中新建db文件夹,其中新建index.json文件。
{
"cart": [
{
"id": 1001,
"name": "低帮城市休闲户外鞋天然牛皮COOLMAX纤维",
"price": 128,
"count": 3,
"thumb": "https://yanxuan-item.nosdn.127.net/3a56a913e687dc2279473e325ea770a9.jpg"
},
{
"id": 1002,
"name": "网易未央黑猪猪肘330g*1袋",
"price": 39,
"count": 3,
"thumb": "https://yanxuan-item.nosdn.127.net/3a56a913e687dc2279473e325ea770a9.jpg"
},
{
"id": 1003,
"name": "KENROLL男女简洁多彩一片室外拖",
"price": 88,
"count": 3,
"thumb": "https://yanxuan-item.nosdn.127.net/3a56a913e687dc2279473e325ea770a9.jpg"
},
{
"id": 1004,
"name": "低帮城市休闲户外鞋天然牛皮COOLMAX纤维",
"price": 99,
"count": 6,
"thumb": "https://yanxuan-item.nosdn.127.net/3a56a913e687dc2279473e325ea770a9.jpg"
}
],
"friends": [
{
"id": 1,
"name": "hang",
"age": 18
},
{
"id": 2,
"name": "wang",
"age": 29
}
]
}
模拟数据库,在db文件夹下,调用系统cmd命令,启动模拟服务器
json-server --watch index.json
main.js
import Vue from 'vue'
import App from './App.vue'
import store from "@/store";
Vue.config.productionTip = false;
new Vue({
render: h => h(App),
store
}).$mount('#app');
app.vue
<template>
<div id="app">
<!-- Header 区域 -->
<cart-header></cart-header>
<!-- Item 区域 -->
<cart-item v-for="item in list" :key="item.id" :item="item"></cart-item>
<!-- Footer 区域 -->
<cart-footer></cart-footer>
</div>
</template>
<script>
import CartHeader from "@/components/CartHeader";
import CartItem from "@/components/CartItem";
import CartFooter from "@/components/CartFooter";
import { mapState } from 'vuex'
export default {
name: 'App',
components: {
CartHeader,
CartItem,
CartFooter
},
computed:{
...mapState('cart',['list'])
},
created() {
this.$store.dispatch('cart/getList');
}
}
</script>
<style>
*{
padding: 0;
margin: 0;
}
</style>
index.js
import Vue from 'vue'
import Vuex from 'vuex'
import cart from "@/store/modules/cart";
Vue.use(Vuex);
const store = new Vuex.Store({
modules:{
cart
}
});
export default store;
cart.js
import axios from "axios";
export default {
//开启命名空间
namespaced:true,
state(){
return {
list:[]
}
},
getters:{
//总数
total(state){
return state.list.reduce( (sum,item) => sum += item.count,0);
},
//总金额
totalPrice(state){
return state.list.reduce( (sum,item) => sum + item.count * item.price ,0);
}
},
mutations:{
updateList(state,newList){
state.list = newList;
},
//
updateCount(state,obj){
//根据id找到对应的对象,更新count属性
const goods = state.list.find( item => item.id === obj.id);
goods.count = obj.newCount;
}
},
actions:{
//请求方式 get
//请求地址:http://localhost:3000/cart
async getList(context){
const res = await axios.get('http://localhost:3000/cart');
//console.log(res);
context.commit('updateList',res.data);
},
//请求方式 patch
//请求地址:http://localhost:3000/cart/:id值
//请求参数 { name:'新值', [可选]}
//
async updateCountAsync(context,obj){
//将修改更新同步到后台服务器
const res = await axios.patch(`http://localhost:3000/cart/${obj.id}`,{
count: obj.newCount
});
console.log(res);
//调用mutation
context.commit('updateCount',{
id: obj.id,
newCount: obj.newCount
});
}
}
}
CartHeader.vue
<template>
<div class="cart-header">
<div class="title">购物车案例</div>
</div>
</template>
<script>
export default {
name: "CartHeader"
}
</script>
<style scoped>
.cart-header{
width: 100%;
height: 70px;
background-color: mediumseagreen;
margin-bottom: 10px;
}
.cart-header .title{
color: white;
font-size: 34px;
width: 200px;
height: 100%;
line-height: 70px;
text-align: center;
margin: 0 auto;
}
</style>
CartItem.vue
<template>
<div class="cart-item">
<!-- 左侧图片区域 -->
<div class="left">
<img :src="item.thumb" alt="" class="avatar">
</div>
<!-- 右侧商品区域 -->
<div class="right">
<!-- 标题 -->
<div class="title">{{ item.name }}</div>
<div class="info">
<span class="price">¥{{ item.price }}</span>
<div class="btns">
<!-- 按钮区域 -->
<button class="btn btn-light" @click="btnClick(-1)">-</button>
<span class="count">{{ item.count }}</span>
<button class="btn btn-light" @click="btnClick(+1)">+</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "CartItem",
props:{
item: {
type: Object,
required:true
}
},
methods:{
btnClick(step){
const newCount = this.item.count + step;
const id = this.item.id;
//console.log(id,newCount);
if(newCount < 1) return;
this.$store.dispatch('cart/updateCountAsync',{
id,
newCount,
});
}
}
}
</script>
<style scoped>
.cart-item{
width: 98%;
height: 200px;
margin-left: 2%;
}
.cart-item .left{
width: 180px;
height: 180px;
float: left;
}
.left img{
width: 100%;
height: 100%;
}
.cart-item .right{
width: 30%;
height: 100%;
float: left;
}
.right .title{
text-indent: 40px;
font-size: 24px;
height: 75%;
font-family: Arial,"Arial Black",Georgia;
}
.right .info{
width: 100%;
height: 25%;
line-height: 30px;
}
.right .price{
padding: 3px;
margin-left: 40px;
color: orange;
font-size: 24px;
}
.right .btns{
float: right;
}
.btns .btn{
width: 30px;
height: 33px;
line-height: 30px;
font-size: 20px;
margin: 0 15px;
}
.btns .count{
display: inline-block;
width: 25px;
text-align: center;
font-size: 20px;
font-weight: bold;
}
.btns .btn-light{
background-color: #cccccc;
}
</style>
CartFooter.vue
<template>
<div class="cart-footer">
<!-- 中间合计 -->
<div>
<span>共 {{ total }} 件商品,合计:</span>
<span class="price">¥ {{ totalPrice }}</span>
</div>
<!-- 右侧结算按钮 -->
<button class="btn">结算</button>
</div>
</template>
<script>
import { mapGetters} from 'vuex'
export default {
name: "CartFooter",
computed:{
...mapGetters('cart',['total','totalPrice'])
}
}
</script>
<style scoped>
.cart-footer{
width: 30%;
height: 50px;
font-size: 20px;
float: right;
}
.cart-footer div{
display: inline;
width: 400px;
margin-left: 8%;
}
.cart-footer .price{
font-size: 30px;
font-weight: bold;
color: red;
}
.cart-footer .btn{
width: 150px;
height: 50px;
background-color: mediumseagreen;
border-radius: 30px;
float: right;
margin-right: 40px;
}
</style>
标签:vue,name,width,cart,购物车,item,height,vuex,id
From: https://blog.51cto.com/u_15356972/7495434