用一个简单的购物车demo来回顾一下其中需要注意的细节。
先看一下最终效果
功能:
(1)全选按钮和下面的商品项的选中状态同步,当下面的商品全部选中时,全选勾选,反之,则不勾选。
(2)控制购物车商品数量,最低为1
(3)拥有小计和总计功能。其中,总计为勾选的商品所需要的总金额。
首先,先把静态页面写出来。
<template>
<div>
<h2>购物车</h2>
全选 <input type="checkbox" >
<div v-for="(item,index) in goods" :key="index">
<input type="checkbox" name="" id="" >--商品名:{{ item.name }} --价格:{{ item.price }}
<!-- 后端数据没有item.num,就使用或1的形式给所有商品默认的数量为1,这样就不用一个个在后端数据中加了 -->
--<button type="button" >+</button>{{item.num || 1}}<button >-</button>
--小计:0
</div>
<div>总计:0</div>
</div></template>
上面的代码将静态页面写了出来,目前没有任何功能而。我们一一进行功能的添加。首先,实现简单的数量加减和小计。
思路:
现在存在两种情况,
第一,就是后端返回了商品数量,也就是item.num这个数据后端是直接给你的,然后我们直接进行使用即可。但是,实际的情况是后端返回的数量是这个商品的总库存,作为我们的购物车来说,一般默认的数量是为1的。所以,这里我们使用逻辑运算符的情况考虑了两种情况。
然后就是加一和减一,比较容易的方法就是直接给加和减分别绑定点击事件,分别进行加减,这里需要使用两个方法。这样的方法就不再介绍。不如换一个思路,让两个事件使用同一个事件,这样就少写了一个方法。
就是两者都是加,而减的操作是加-1.这样就可以合并为一个方法。
代码如下
updateNum(actionType,index){//初始化numthis.goods[index].num = this.goods[index].num||1//数量操作this.goods[index].num+=actionType},
解释一下,第一个参数就是传递过来的值,是加1,还是加-1,第二个值就是对应的索引,因为要对对应的商品进行数量加减操作,所以需要对应商品的索引。
首先,在考虑初始化num的时候,也要考虑num不存在的情况,
然后进行对应的数量操作即可。
那么我们的小计也就可以根据商品数量和价格进行计算了,注意:也要考虑数量不存在的情况。
对应的代码为:
<button type="button" @click="updateNum(1,index)">+</button>{{item.num || 1}}
<button @click="updateNum(-1,index)">-</button>
--小计:{{(item.num ||1) *item.price}}
</div>
然后就是全选,商品单选,和总计的功能了。
首先进行全选实现,就是让全选的状态和商品单选进行同步。
我们首先定义全选的状态,默认是不选中的。( isAllSelected:false,)
data(){return{isAllSelected:false,goods:[{name:"商品1",price:"100",// num:"1",},{name:"商品2",price:"200"},{name:"商品3",price:"300"}]}},
然后对应的给他添加change事件(注意,这里是change事件,并不是click)
全选 <input type="checkbox" :checked="isAllSelected" @change="allSelect">
使用动态绑定属性使他与 isAllSelected:的状态同步,然后写allSelect方法
allSelect(){this.isAllSelected=!this.isAllSelectedconsole.log(this.isAllSelected);//同步单选状态this.goods.forEach(item=>{item.select=this.isAllSelected})},
这里就是让他的状态和下面的商品列表的选择框进行同步,思路为:就是对下面的商品列表进行遍历,使用forEach方法,并将其状态赋值给每一项商品的选择状态。
然后就是当下面的每一项的商品取消选中时,那个全选的状态要进行改变。
这里用到另一个数组方法every
singleSelect(index){//修改当前单选商品状态this.goods[index].select=!this.goods[index].select//使用every方法循环数组,如果有一个select为false//整个结果为false 全部为true 整个结果为true//和我们单选联动 全选逻辑一致//直接使用返回值 赋给全选状态this.isAllSelected=this.goods.every(item=>item.select)}
最后就是总计了,这里的总计是将所有选中的商品进行金额的计算。
这里也是用到了两个数组方法,他们分别是filter和every。
<div>总计:{{ goods.filter(item=>item.select).reduce((total,item)=>total+=item.price*(item.num ||1),0) }}</div>
然后解释一下,这里首先使用filter方法将满足选中状态的商品进行过滤,返回的是一个数组,然后再将返回的数组使用累加方法reduce进行金额的计算。
完整代码附上:
<!--* @Author: RealRoad1083425287@qq.com* @Date: 2024-07-06 16:18:52* @LastEditors: Mei* @LastEditTime: 2024-07-06 17:03:12* @FilePath: \Fighting\new_project_0705\my-vue-app\src\components\shopcar.vue* @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
-->
<template>
<div>
<h2>购物车</h2>
全选 <input type="checkbox" :checked="isAllSelected" @change="allSelect">
<div v-for="(item,index) in goods" :key="index">
<input type="checkbox" name="" id="" :checked="item.select" @change="singleSelect(index)">--商品名:{{ item.name }} --价格:{{ item.price }}
<!-- 后端数据没有item.num,就使用或1的形式给所有商品默认的数量为1,这样就不用一个个在后端数据中加了 -->
--<button type="button" @click="updateNum(1,index)">+</button>{{item.num || 1}}<button @click="updateNum(-1,index)">-</button>
--{{(item.num ||1) *item.price}}
</div>
<div>总计:{{ goods.filter(item=>item.select).reduce((total,item)=>total+=item.price*(item.num ||1),0) }}</div>
</div></template><script>
export default {data(){return{isAllSelected:false,goods:[{name:"商品1",price:"100",// num:"1",},{name:"商品2",price:"200"},{name:"商品3",price:"300"}]}},methods:{updateNum(actionType,index){//初始化numthis.goods[index].num = this.goods[index].num||1//数量操作this.goods[index].num+=actionType},allSelect(){this.isAllSelected=!this.isAllSelectedconsole.log(this.isAllSelected);//同步单选状态this.goods.forEach(item=>{item.select=this.isAllSelected})},singleSelect(index){//修改当前单选商品状态this.goods[index].select=!this.goods[index].select//使用every方法循环数组,如果有一个select为false//整个结果为false 全部为true 整个结果为true//和我们单选联动 全选逻辑一致//直接使用返回值 赋给全选状态this.isAllSelected=this.goods.every(item=>item.select)}}
}
</script><style></style>
通过这个案例,主要是复习一下vue的常见指令的使用,主要是数组方法的使用。这里,将使用的四个数组方法进行详细的介绍。
①forEach
forEach 是 JavaScript 中的一个数组方法,它允许你对数组中的每个元素执行一个函数。这个方法接受一个回调函数作为参数,这个回调函数会对数组中的每个元素执行一次。此外,forEach 方法不会返回一个新数组,它仅仅是对原数组的每个元素执行了提供的函数。
forEach 的基本语法如下:
array.forEach(function(currentValue, index, arr), thisArg)
参数说明:
currentValue:数组中正在处理的当前元素。
index(可选):数组中正在处理的当前元素的索引。
arr(可选):forEach() 方法正在操作的数组。
thisArg(可选):执行回调函数时用作 this 的对象。
上面是官方的介绍,但是在实际的使用中,用的最多的还是currentValue,偶尔也会用到index,这里用一个上次的案例进行效果演示。(主要是遍历数组,记住不会返回新数组就行了)
<!--* @Author: RealRoad1083425287@qq.com* @Date: 2024-07-05 21:28:45* @LastEditors: Mei* @LastEditTime: 2024-07-06 17:39:19* @FilePath: \Fighting\new_project_0705\my-vue-app\src\components\practice5.vue* @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
-->
<template><div><div id="myList" v-for="(item,index) in arr" :key="index" @click="arrTest">{{ item.name }}</div></div></template><script>
//列表渲染
//为什么循环的时候需要加key
//1.key的作用主要是为了高效的更新虚拟Dom,提高渲染性能
//2.key属性可以避免数据混乱的情况出现
export default{data(){return{arr:[{name:"张三"},{name:"李四"},{name:"王五"}]}},methods:{arrTest(){this.arr.forEach((item,index)=>{console.log("我是每一项",item);console.log("我是每一项的索引",index);})}}
}</script><style scoped>
#myList{color: blue;background-color: yellow;margin-top: 20px;
}
</style>
效果如下:
②every
every 是 JavaScript 中的一个数组方法,用于测试数组的所有元素是否都满足提供的函数中的测试条件。如果所有元素都通过测试,则返回 true;否则,返回 false。这个方法不会改变原数组,而是返回一个布尔值。
every 方法的基本语法如下:
array.every(function(currentValue, index, arr), thisArg)
参数说明:
currentValue:数组中正在处理的当前元素。
index(可选):数组中正在处理的当前元素的索引。
arr(可选):every 方法正在操作的数组。
thisArg(可选):执行回调函数时用作 this 的值。如果省略了 thisArg 参数,或者设为 null 或 undefined,则 this 会被视为全局对象。在严格模式下,如果省略或为 null 或 undefined,则 this 会是 undefined。
还是一个案例来演示:
<!--* @Author: RealRoad1083425287@qq.com* @Date: 2024-07-05 21:28:45* @LastEditors: Mei* @LastEditTime: 2024-07-06 17:53:54* @FilePath: \Fighting\new_project_0705\my-vue-app\src\components\practice5.vue* @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
-->
<template><div><div id="myList" v-for="(item,index) in arr" :key="index" @click="arrTest">{{ item.name }}</div><div><button @click="arrTest2">点我看every{{ testEvery }}</button></div></div></template><script>
//列表渲染
//为什么循环的时候需要加key
//1.key的作用主要是为了高效的更新虚拟Dom,提高渲染性能
//2.key属性可以避免数据混乱的情况出现
export default{data(){return{testEvery:"",arr:[{name:"张三"},{name:"李四"},{name:"王五"}],arr2:[{age:10},{age:20},{age:30}]}},methods:{arrTest(){this.arr.forEach((item,index)=>{console.log("我是每一项",item);console.log("我是每一项的索引",index);})},arrTest2(){this.testEvery=this.arr2.every((item,index)=>{return item.age>5})}}
}</script><style scoped>
#myList{color: blue;background-color: yellow;margin-top: 20px;
}
</style>
写一个按钮,当我们点击按钮的时候,就可以看到arrTest2返回的值,我们可以看到多了一个true,因为在执行every后,this.testEvery=true,对应页面的testEvery值也会进行显示。
③filter
filter 是 JavaScript 中的一个非常有用的数组方法,它创建一个新的数组,该数组包含通过测试函数的所有元素。换句话说,filter 方法会遍历原数组,对每个元素执行一个测试函数,如果该函数返回 true,则将该元素包含在新数组中。
filter 方法的基本语法如下:
let newArray = array.filter(function(currentValue, index, arr), thisArg)
参数说明:
currentValue:数组中正在处理的当前元素。
index(可选):数组中正在处理的当前元素的索引。
arr(可选):filter 方法正在操作的数组。
thisArg(可选):执行回调函数时用作 this 的值。
filter 方法返回一个新数组,该数组包含原数组中满足测试函数的元素。它不会改变原数组。
上代码
<!--* @Author: RealRoad1083425287@qq.com* @Date: 2024-07-05 21:28:45* @LastEditors: Mei* @LastEditTime: 2024-07-06 18:03:11* @FilePath: \Fighting\new_project_0705\my-vue-app\src\components\practice5.vue* @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
-->
<template><div><div id="myList" v-for="(item,index) in arr" :key="index" @click="arrTest">{{ item.name }}</div><div><button @click="arrTest2">点我看Filter</button><div v-for="(item,index) in testFilter " :key=index>{{ item.age }}</div></div></div></template><script>
//列表渲染
//为什么循环的时候需要加key
//1.key的作用主要是为了高效的更新虚拟Dom,提高渲染性能
//2.key属性可以避免数据混乱的情况出现
export default{data(){return{testEvery:"",testFilter:"",arr:[{name:"张三"},{name:"李四"},{name:"王五"}],arr2:[{age:10},{age:20},{age:30}]}},methods:{arrTest(){this.arr.forEach((item,index)=>{console.log("我是每一项",item);console.log("我是每一项的索引",index);})},arrTest2(){this.testFilter=this.arr2.filter((item,index)=>{return item.age>15})console.log(this.testFilter);}}
}</script><style scoped>
#myList{color: blue;background-color: yellow;margin-top: 20px;
}
</style>
当我点击按钮后,对应返回的新数组就会被渲染出来。
④reduce
reduce 是 JavaScript 中的一个数组方法,用于将数组中的所有元素通过某个函数(称为“reducer”函数)归并成一个单一的结果。这个方法会遍历数组中的每个元素,并使用 reducer 函数将其累积成一个单一的值。
reduce 方法的基本语法如下:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
参数说明:
function(total, currentValue, currentIndex, arr): 这是 reducer 函数,它接受四个参数:
total(必需):初始值,或者计算结束后的返回值(累加器)。
currentValue(必需):当前元素。
currentIndex(可选):当前元素的索引。
arr(可选):当前元素所属的数组对象。
initialValue(可选):传递给函数的初始值。如果没有提供初始值,则将使用数组的第一个元素作为初始值,并从数组的第二个元素开始进行迭代。
上代码:
<!--* @Author: RealRoad1083425287@qq.com* @Date: 2024-07-05 21:28:45* @LastEditors: Mei* @LastEditTime: 2024-07-06 18:11:41* @FilePath: \Fighting\new_project_0705\my-vue-app\src\components\practice5.vue* @Description: * * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved.
-->
<template><div><div id="myList" v-for="(item,index) in arr" :key="index" @click="arrTest">{{ item.name }}</div><div><button @click="arrTest2">点我看Filter</button><div v-for="(item,index) in testFilter " :key=index>{{ item.age }}</div><button @click="arrTest3">点我看Reduce</button><!-- <div v-for="(item,index) in testFilter " :key=index>{{ item.age }}</div> --></div></div></template><script>
//列表渲染
//为什么循环的时候需要加key
//1.key的作用主要是为了高效的更新虚拟Dom,提高渲染性能
//2.key属性可以避免数据混乱的情况出现
export default{data(){return{testEvery:"",testFilter:"",testReduce:0,arr:[{name:"张三"},{name:"李四"},{name:"王五"}],arr2:[{age:10},{age:20},{age:30}]}},methods:{arrTest(){this.arr.forEach((item,index)=>{console.log("我是每一项",item);console.log("我是每一项的索引",index);})},arrTest2(){this.testFilter=this.arr2.filter((item,index)=>{return item.age>15})console.log(this.testFilter);},arrTest3(){this.testReduce=this.arr2.reduce((total,item)=>{return total+item.age},0)console.log(this.testReduce);}}
}</script><style scoped>
#myList{color: blue;background-color: yellow;margin-top: 20px;
}
</style>
我的年龄数据为10,20,30,他们累加之后为60,如果在最后一项,我不是以0为初始值,更改为1后,累加的值就变成了61.
this.testReduce=this.arr2.reduce((total,item)=>{return total+item.age},0)