综合案例-购物车
目标:功能分析,创建项目,构建分析基本结构
- 功能模块分析
- 请求动态渲染购物车,数据存入
vuex
- 数字框控件修改数据
- 动态计算总价和总数量
- 脚手架新建项目(注意:勾选
vuex
)
构建模块
既然明确数据要存到vuex
,建议分模块存储,购物车数据存入cart
模块,之后若还有其他数据如用户数据存入user
模块,文章数据存入article
模块等
项目复杂度高,分模块存数据更方便管理
cart 购物车模块
- 新建
store/modules/cart.js
1 2 3 4 5 6 7 8
| export default { namespaced: true, state() { return { list: [], }; }, };
|
- 挂载到 vuex 仓库上
store/index.js
1 2 3 4 5 6
| import cart from './modules/cart'; export default new Vuex.Store({ modules: { cart, }, });
|
后端接口环境
基于json-server
工具,准备后端接口服务环境
实际开发中后端接口还未准备好时,可以先使用这个工具开发功能
开发时需要单独开一个窗口启动服务
- 安装全局工具
json-server
(全局工具仅需安装一次)官网
1 2 3
| npm i json-server -g # 或 yarn global add json-server
|
- 代码根目录新建一个
db
目录
- 将资料
index.json
移入db
目录
- 进入
db
目录,执行命令,启动后端接口服务
- 访问接口测试 http://localhost:3000/cart
请求数据存入 vuex
- 安装
axios
- 准备
actions
和mutations
- 调用
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: { async getList (context) { const res = await axios.get('http://localhost:3000/cart') console.log(res) context.commit('updateList', res.data) } },
|
- 动态渲染
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
| <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:’新值’,[可选]
}
- 点击事件绑定
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>
|
- 页面中
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 if (newCount < 1) return this.$store.dispatch('cart/updateCountAsync', { id, newCount }) } },
|
- 提供
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 }) ctx.commit('updateCount', { id: obj.id, newCount: obj.newCount }) }
|
- 提供
mutation
函数
1 2 3 4 5 6
| updateCount (state, obj) { const goods = state.list.find(item => item.id === obj.id) goods.count = obj.newCount }
|
功能-底部 getters 统计
- 提供 getters
cart.js:
1 2 3 4 5 6 7 8 9 10
| getters: { total (state) { return state.list.reduce((totalCount, item) => totalCount + item.count, 0) }, totalPrice (state) { return state.list.reduce((totalPrice, item) => totalPrice + item.count * item.price, 0) } }
|
- 使用 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>
|