案例-购物车

838 词

综合案例-购物车#

目标:功能分析,创建项目,构建分析基本结构

  1. 功能模块分析
    1. 请求动态渲染购物车,数据存入vuex
    2. 数字框控件修改数据
    3. 动态计算总价和总数量
  2. 脚手架新建项目(注意:勾选vuex

构建模块#

既然明确数据要存到vuex,建议分模块存储,购物车数据存入cart模块,之后若还有其他数据如用户数据存入user模块,文章数据存入article模块等
项目复杂度高,分模块存数据更方便管理

cart 购物车模块#

  1. 新建store/modules/cart.js
1
2
3
4
5
6
7
8
export default {
namespaced: true,
state() {
return {
list: [],
};
},
};
  1. 挂载到 vuex 仓库上store/index.js
1
2
3
4
5
6
import cart from './modules/cart';
export default new Vuex.Store({
modules: {
cart,
},
});

后端接口环境#

基于json-server工具,准备后端接口服务环境
实际开发中后端接口还未准备好时,可以先使用这个工具开发功能
开发时需要单独开一个窗口启动服务

  1. 安装全局工具json-server(全局工具仅需安装一次)官网
1
2
3
npm i json-server -g
#
yarn global add json-server
  1. 代码根目录新建一个db目录
  2. 将资料index.json移入db目录
  3. 进入db目录,执行命令,启动后端接口服务
1
json-server index.json
  1. 访问接口测试 http://localhost:3000/cart

请求数据存入 vuex#

  1. 安装axios
1
npm add axios
  1. 准备actionsmutations
  2. 调用action获取数据

actions异步获取商品数据,提交mutations修改仓库数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mutations: {
updateList (state, newList) {
state.list = newList
}
},
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)
}
},
  1. 动态渲染

App.vue 导入mapState辅助函数,将商品数据映射到计算属性中

1
2
3
4
5
6
7
8
import { mapState } from 'vuex';
export default {
// ...
computed: {
...mapState('cart', ['list']),
},
// ...
};

商品组件v-for遍历生成节点,并传递商品数据项给组件
App.vue:

1
2
<!-- 商品 Item 项组件 -->
<cart-item v-for="(item) in list" :key="item.id" :item="item"></cart-item>

组件cart-item.vue内部通过props接收并用于渲染
cart-item.vue:

1
2
3
4
5
6
props: {
item: {
type: Object,
required: true
}
}

功能-修改数量#

请求方式:patch
请求地址:http://localhost:3000/cart/:id 值 后面跟 id 值表示要修改的商品对象
请求参数:
{
name:’新值’,[可选]
price:’新值’,[可选]
count:’新值’,[可选]
thumb:’新值’,[可选]
}

  1. 点击事件绑定

cart-item.vue:

1
2
3
<button class="btn btn-light" @click="btnClick(-1)">-</button>
<span class="count">{{ item.count }}</span>
<button class="btn btn-light" @click="btnClick(1)">+</button>
  1. 页面中dispatch

cart-item.vue:

1
2
3
4
5
6
7
8
9
methods: {
btnClick (step) {
const newCount = this.item.count + step
const id = this.item.id
// 判断newCount若小于1则不能再减少
if (newCount < 1) return
this.$store.dispatch('cart/updateCountAsync', { id, newCount })
}
},
  1. 提供action函数

cart.js:

1
2
3
4
5
6
7
8
9
10
11
12
async updateCountAsync (ctx, obj) {
// 将修改更新同步到后台服务器
console.log(obj)
await axios.patch(`http://localhost:3000/cart/${obj.id}`, {
count: obj.newCount
})
// 将修改更新同步到vuex
ctx.commit('updateCount', {
id: obj.id,
newCount: obj.newCount
})
}
  1. 提供mutation函数
1
2
3
4
5
6
// obj:{id:xxx,newCount:xxx}
updateCount (state, obj) {
// 根据id找对象,更新其count
const goods = state.list.find(item => item.id === obj.id)
goods.count = obj.newCount
}

功能-底部 getters 统计#

  1. 提供 getters

cart.js:

1
2
3
4
5
6
7
8
9
10
getters: {
// 总数,累加count
total (state) {
return state.list.reduce((totalCount, item) => totalCount + item.count, 0)
},
// 总价,累加count*price
totalPrice (state) {
return state.list.reduce((totalPrice, item) => totalPrice + item.count * item.price, 0)
}
}
  1. 使用 getters

cart-footer.vue:

1
2
3
4
5
import { mapGetters } from 'vuex';

computed: {
...mapGetters('cart', ['total', 'totalPrice'])
}
1
2
3
4
<div>
<span>共 {{total}} 件商品,合计:</span>
<span class="price">¥{{totalPrice}}</span>
</div>