购物车案例
-
项目准备
-
创建目录文件
vue create shopping-cart-demo
-
-
相关代码
- App.vue
<template> <div id="app"> <h1>{{title}}</h1> <hr> <div> <h2>添加课程</h2> <div> <label for="">课程名称:</label> <input type="text" v-model="courseInfo.name"> </div> <div> <label for="">课程价格:</label> <input type="text" v-model="courseInfo.price"> </div> <div> <button @click="addCourseToList">添加课程</button> </div> <table> <tr> <th>课程名称</th> <th>课程价格</th> <th>操作</th> </tr> <tr v-for="(item,index) in courseList" :key="item.id"> <td>{{item.name}}</td> <td>{{item.price}}</td> <td><button @click="addCourseToCart(index)">添加到购物车</button></td> </tr> </table> </div> <cart :courseItem="courseItem" @removeItem="remove"></cart> </div> </template> <script> import Cart from './components/Cart.vue' export default { name: 'App', components: { Cart, }, data(){ return{ title:"购物车", courseItem:[], courseInfo:{ name:'', price:'' }, courseList:[ { name:"sin", price:123 }, { name:"txm", price:123 } ] } }, methods:{ addCourseToList(){ this.courseList.push(this.courseInfo) }, addCourseToCart(index){ let item = this.courseList[index]; let isHasCourse = this.courseItem.find(x=>x.name == item.name) if(isHasCourse){ isHasCourse.number +=1; } else{ this.courseItem.push({ ...item, number:1, isActive:true }) } }, remove(index){ this.courseItem.splice(index,1) } } } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
-
Cart.vue
<template> <div> <h2>购物车</h2> <table> <div> <tr> <th>勾选</th> <th>课程</th> <th>数量</th> <th>价格</th> </tr> <tr v-for="(item,index) in courseItem " :key='index'> <td> <input type="checkbox" v-model="item.isActive"> </td> <td>{{item.name}}</td> <td> <button @click="min(index)">-</button> {{item.number}} <button @click="add(index)">+</button> </td> <td>{{item.price*item.number}}</td> </tr> <tr> <td></td> <td colspan='2'>{{isActiveCourse}}/{{allCourseList}}</td> <td colspan='2'>{{AllPrice}}</td> //colspan 属性规定单元格可横跨的列数。 </tr> </div> </table> </div> </template> <script> export default { props:['courseItem'], methods:{ min(index){ let number = this.courseItem[index].number if(number>1){ this.courseItem[index].number -=1 }else{ if(window.confirm('确定要删除吗')){ this.$emit('removeItem',index) } } }, add(index){ this.courseItem[index].number +=1 } }, computed:{ isActiveCourse(){ return this.courseItem.filter(item=>item.isActive).length }, allCourseList(){ return this.courseItem.length; }, AllPrice(){ let number = 0 this.courseItem.forEach(item => { if(item.isActive){ number +=item.price*item.number } }); return number }, } } </script> <style> </style>
-
思路
-
添加课程
使用v-model实现双向数据绑定,获取input内的内容。
通过@click="addCourseToList"点击事件,实现:
methods:{ addCourseToList(){ this.courseList.push(this.courseInfo) }, } 方法,讲数据添加到courseInfo中: data(){ return{ courseInfo:{ name:'', price:'' }, } }
-
push()
push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。要想数组的开头添加一个或多个元素,使用 unshift() 方法。
-
-
添加购物车
首先创建一个购物车组件Cart.vue。
然后在App.vue中使用该组件:
- 父向子传值— v-bind props:[]:
在App.vue中使用v-on动态绑定courseItem,在子组件中使用:props:['courseItem'],来接收数据
给按钮添加点击事件<button @click="addCourseToCart(index)">添加到购物车,将数组下标传入。然后通过方法将数据添加到数组中:
addCourseToCart(index){ let item = this.courseList[index]; let isHasCourse = this.courseItem.find(x=>x.name == item.name) //判断传入的数据是否已经存在 if(isHasCourse){ isHasCourse.number +=1; } else{ this.courseItem.push({ ...item, number:1, isActive:true }) } }, 将表格中的数据添加到courseItem数组中: data(){ return{ courseItem:[], } }
-
Array.find()
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
[1, 4, -5, 10].find((n) => n < 0) // -5
find
方法的回调函数可以接受三个参数,依次为当前的值、当前的位置和原数组。[1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10
-
扩展语法— ...
function sum(x, y, z) { return x + y + z; } const numbers = [1, 2, 3]; console.log(sum(...numbers)); // expected output: 6
-
购物车数据处理
-
数量加减
首先给数量两边加上加减按钮,并添加点击事件:
<td> <button @click="min(index)">-</button> {{item.number}} <button @click="add(index)">+</button> </td>
然后通过方法控制数量:
methods:{ min(index){ let number = this.courseItem[index].number if(number>1){ this.courseItem[index].number -=1 }else{ if(window.confirm('确定要删除吗')){ this.$emit('removeItem',index) // removeItem事件名称,index传递的值 } } }, add(index){ this.courseItem[index].number +=1 } },
-
window.confirm(message)
confirm()方法用于显示一个带有指定消息和确认及取消按钮的对话框。
如果访问者点击"确定",此方法返回true,否则返回false。
-
子向父传值—v-on $emit
在子组件上添加一个删除的点击事件,事件名称为$emit中定义的名称:
<cart :courseItem="courseItem" @removeItem="remove"></cart>
实现删除方法:
remove(index){ this.courseItem.splice(index,1) }
-
-
勾选数量,价格汇总
这里需要用到计算属性computed监听数据的变化:
<tr> <td></td> <td colspan='2'>{{isActiveCourse}}/{{allCourseList}}</td> <td colspan='2'>{{AllPrice}}</td> </tr>
isActiveCourse为当前勾选的个数,allCourseList为总个数,AllPrice为总价格。
computed:{ isActiveCourse(){ return this.courseItem.filter(item=>item.isActive).length }, allCourseList(){ return this.courseItem.length; }, AllPrice(){ let number = 0 this.courseItem.forEach(item => { if(item.isActive){ number +=item.price*item.number } }); return number }, }
-
filter
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 注意: filter() 不会对空数组进行检测。 注意: filter() 不会改变原始数组。
-
filter函数的参数:
// filter函数的参数 let arr = ['a', 'b', 'c'] let array = arr.filter((item, index, self) => { console.log(item, index, self) //依次返回 a 0 (3) ["a", "b", "c"] b 1 (3) ["a", "b", "c"] c 2 (3) ["a", "b", "c"] //即第一个参数是里面的元素,第二个参数为元素索引值,第三个参数为数组本身 })
-
-
-
-