今天用vue实现了一个小需求,里面涉及到了不少知识点,在此对这个需求的实现做一个记录。
首先上效果图
说下需求:
- 渲染功能
- 删除功能
- 修改个数
- 全选反选
- 统计选中的 总价 和 总数量
- 持久化到本地
实现思路:
-
基本渲染:v-for遍历 :class动态绑定样式
-
删除功能:v-on 绑定事件,获取当前的id
-
修改个数:v-on绑定事件,获取当前行的i,进行筛选出对应的项然后增加或减少
-
全选和反选
- 必须所有的小选框
- 必须所有的小选框都选中,全选按钮才选中 → every
- 如果全选按钮选中,则所有小选框都选中
- 如果全选取消,则所有小选框都取消选中
- 声明计算属性,判断数组中的每一个checked属性的值,看是否需要全部选
-
统计 选中的 总价 和 总数量 :通过计算属性来计算选中的总价和总数量
-
持久化到本地: 在数据变化时都要更新下本地存储 watch
下面对需求一个个进行实现
//先看下数据结构
const fruitList = [
{
id: 1,
icon: "http://autumnfish.cn/static/火龙果.png",
isChecked: true,
num: 2,
price: 6,
},
...
]
//渲染功能
<div
class="tr"
:class="{active : item.isChecked}"
v-for="(item, index) in fruitList"
:key="item.id"
>
<div class="td">
<input type="checkbox" v-model="item.isChecked" />
</div>
<div class="td"><img :src="item.icon" alt="" /></div>
<div class="td">{{item.price}}</div>
<div class="td">
<div class="my-input-number">
<button
class="decrease"
@click="count(item.id)"
:disabled="item.num <= 1"
>
-
</button>
<span class="my-input__inner">{{item.num}}</span>
<button class="increase" @click="add(item.id)">+</button>
</div>
</div>
<div class="td">{{item.price * item.num}}</div>
<div class="td">
<button @click="cancleBtn(item.id)">删除</button>
</div>
</div>
//删除功能
给对应的按钮添加点击事件,然后配合filter进行删除功能实现
methods: {
cancleBtn(id) {
this.fruitList = this.fruitList.filter(item => item.id !== id)
}
}
//修改商品的数量个数:这里面要注意的一点是在点击--的时候需要判断是否小于或等于1,若满足这个条件需要将对应的按钮设置disabled禁用。
方法一:可以直接在对应的标签里面通过vue添加点击事件然后直接将相应的属性++或者--。
<button class="increase" @click="add(item.num++)">+</button>
<button
class="decrease"
@click="count(item.id)"
:disabled="item.num <= 1"
>
-
</button>
方法二:给对应的按钮添加函数,使用find
methods: {
add(id){
this.fruitList.find(item => item.id === id).num++
},
count(id){
this.fruitList.find(item => item.id === id).num--
}
}
//全选反选
全选反选在用原生js实现的时候,会让你的头上着火,但是随着vue等一些mvvm框架的出现,这个需求变得简单了很多。在vue中,可以使用计算属性computed来实现这个需求:
<!-- 底部 -->
<div class="bottom">
<!-- 全选 -->
<label class="check-all">
<input type="checkbox" v-model="allCheck" />全选
</label>
<div class="right-box">
<!-- 所有商品总价 -->
<span class="price-box"
>总价 : ¥ <span class="price"
>{{totalPrice}}</span
></span
>
<!-- 结算按钮 -->
<button class="pay">结算( {{totalCount}} )</button>
</div>
</div>
computed: {
allCheck: {
get(){
return this.fruitList.every(item => item.isChecked)
},
set(newValue){
this.fruitList.forEach(item => item.isCheckes = newValue)
}
}
}
//统计选中的 总价 和 总数量
总价是更具商品的数量*商品的单价来决定的,所以这里我们也可以用计算属性来实现需求
computed: {
//总价
totalPrice(){
this.fruitList.reduce((sum, item) => {
//这里要做个判断,因为商品的总价是选中的商品
if(item.isChecked) {
return item.price * item.num
}else{
return sum
}
}, 0)
},
totalCount(){
this.fruitList.reduce((sum, item) => {
//这里要做个判断,因为商品的总价是选中的商品
if(item.isChecked) {
return item.num
}else{
return sum
}
}, 0)
}
//持久化到本地:这里我们需要用到vue的侦听器watch配合localStorage
watch: {
//因为持久化数据到本地,我们知道这里变化的就是数组fruitList,所以我们通过侦听数组的变化来实现这个需求
fruitList: {
deep: true, 这个属性保证侦听器能进行深度侦听,也就是能侦听复杂数据类型的数据
handler(newVal){ //newVal是变化后的新数据
localStorage.setItem('fruitList', JSON.stringify(newVal)) //复杂数据需要先转化成JSON字符串才能存储
}
}
}
//为了保证在界面刷新的时候,界面的状态不变,所以我们需要在界面加载的时候从本地存储取出数据(注意:此处需要JSON.parse转换成对象),然后将取出的对象赋值给fruitList.
}
以上就是我对这一需求的编写过程,本人水平有限,若有不足之处还望各位大佬指出。欢迎评论区讨论~