实现功能有:
1.渲染功能:v-if / v-else? ? ? ? v-for? ? ? ? :class
2.删除功能:点击传参 filter过滤覆盖原数据
3.修改个数:点击传参 find找对象
4.全选反选:计算属性computed 完整写法 get/set
5.统计选中的总价和总数量:计算属性computed reduce条件求和
6.持久化到本地:watch监视,local storage,json.stringify,json.parse
<!DOCTYPE html>
<html lang="en">
? <head>
? ? <meta charset="UTF-8" />
? ? <meta http-equiv="X-UA-Compatible" content="IE=edge" />
? ? <meta name="viewport" content="width=device-width, initial-scale=1.0" />
? ? <link rel="stylesheet" href="./css/inputnumber.css" />
? ? <link rel="stylesheet" href="./css/index.css" />
? ? <title>购物车</title>
? </head>
? <body>
? ? <div class="app-container" id="app">
? ? ? <!-- 顶部banner -->
? ? ? <div class="banner-box"><img src="http://autumnfish.cn/static/fruit.jpg" alt="" /></div>
? ? ? <!-- 面包屑 -->
? ? ? <div class="breadcrumb">
? ? ? ? <span>🏠</span>
? ? ? ? /
? ? ? ? <span>购物车</span>
? ? ? </div>
? ? ? <!-- 购物车主体 -->
? ? ? <div class="main" v-if="fruitList.length > 0">
? ? ? ? <div class="table">
? ? ? ? ? <!-- 头部 -->
? ? ? ? ? <div class="thead">
? ? ? ? ? ? <div class="tr">
? ? ? ? ? ? ? <div class="th">选中</div>
? ? ? ? ? ? ? <div class="th th-pic">图片</div>
? ? ? ? ? ? ? <div class="th">单价</div>
? ? ? ? ? ? ? <div class="th num-th">个数</div>
? ? ? ? ? ? ? <div class="th">小计</div>
? ? ? ? ? ? ? <div class="th">操作</div>
? ? ? ? ? ? </div>
? ? ? ? ? </div>
? ? ? ? ? <!-- 身体 -->
? ? ? ? ? <div class="tbody">
? ? ? ? ? ? <div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
? ? ? ? ? ? ? <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 :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> - </button>
? ? ? ? ? ? ? ? ? <span class="my-input__inner">{{ item.num }}</span>
? ? ? ? ? ? ? ? ? <button class="increase" @click="add(item.id)"> + </button>
? ? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? </div>
? ? ? ? ? ? ? <div class="td">{{ item.num * item.price }}</div>
? ? ? ? ? ? ? <div class="td"><button @click="del(item.id)">删除</button></div>
? ? ? ? ? ? </div>
? ? ? ? ? </div>
? ? ? ? </div>
? ? ? ? <!-- 底部 -->
? ? ? ? <div class="bottom">
? ? ? ? ? <!-- 全选 -->
? ? ? ? ? <label class="check-all">
? ? ? ? ? ? <input type="checkbox" v-model="isAll"/>
? ? ? ? ? ? 全选
? ? ? ? ? </label>
? ? ? ? ? <div class="right-box">
? ? ? ? ? ? <!-- 所有商品总价 -->
? ? ? ? ? ? <span class="price-box">总价 : ¥ <span class="price">{{ totalPrice }}</span></span>
? ? ? ? ? ? <!-- 结算按钮 -->
? ? ? ? ? ? <button class="pay">结算( {{ totalCount }} )</button>
? ? ? ? ? </div>
? ? ? ? </div>
? ? ? </div>
? ? ? <!-- 空车 -->
? ? ? <div class="empty" v-else>🛒空空如也</div>
? ? </div>
? ? <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
? ? <script>
? ? ? const defaultArr = [
? ? ? ? ? ? {
? ? ? ? ? ? ? id: 1,
? ? ? ? ? ? ? icon: 'http://autumnfish.cn/static/火龙果.png',
? ? ? ? ? ? ? isChecked: true,
? ? ? ? ? ? ? num: 2,
? ? ? ? ? ? ? price: 6,
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? id: 2,
? ? ? ? ? ? ? icon: 'http://autumnfish.cn/static/荔枝.png',
? ? ? ? ? ? ? isChecked: false,
? ? ? ? ? ? ? num: 7,
? ? ? ? ? ? ? price: 20,
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? id: 3,
? ? ? ? ? ? ? icon: 'http://autumnfish.cn/static/榴莲.png',
? ? ? ? ? ? ? isChecked: false,
? ? ? ? ? ? ? num: 3,
? ? ? ? ? ? ? price: 40,
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? id: 4,
? ? ? ? ? ? ? icon: 'http://autumnfish.cn/static/鸭梨.png',
? ? ? ? ? ? ? isChecked: true,
? ? ? ? ? ? ? num: 10,
? ? ? ? ? ? ? price: 3,
? ? ? ? ? ? },
? ? ? ? ? ? {
? ? ? ? ? ? ? id: 5,
? ? ? ? ? ? ? icon: 'http://autumnfish.cn/static/樱桃.png',
? ? ? ? ? ? ? isChecked: false,
? ? ? ? ? ? ? num: 20,
? ? ? ? ? ? ? price: 34,
? ? ? ? ? ? },
? ? ? ? ? ]
? ? ? const app = new Vue({
? ? ? ? el: '#app',
? ? ? ? data: {
? ? ? ? ? // 水果列表
? ? ? ? ? fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
? ? ? ? },
? ? ? ? computed: {
? ? ? ? ? // 默认计算属性:只能获取不能设置,要设置需要写完整写法
? ? ? ? ? // isAll () {
? ? ? ? ? // ? // 必须所有的小选框都选中,全选按钮才选中 → every
? ? ? ? ? // ? return this.fruitList.every(item => item.isChecked)
? ? ? ? ? // }
? ? ? ? ?
? ? ? ? ? // 完整写法 = get + set
? ? ? ? ? isAll: {
? ? ? ? ? ? get () {
? ? ? ? ? ? ? return this.fruitList.every(item => item.isChecked)
? ? ? ? ? ? },
? ? ? ? ? ? set (value) {
? ? ? ? ? ? ? // 基于拿到的布尔值,要让所有的小选框 同步状态
? ? ? ? ? ? ? this.fruitList.forEach(item => item.isChecked = value)
? ? ? ? ? ? ? // forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
? ? ? ? ? ? }
? ? ? ? ? },
? ? ? ? ? // 统计选中的总数 reduce
? ? ? ? ? // reduce () 方法是 JavaScript Array 对象的一个方法,用于将数组中的每个值缩减为一个值,接收一个函数作为累加器。
? ? ? ? ? totalCount () {
? ? ? ? ? ? return this.fruitList.reduce((sum, item) => {
? ? ? ? ? ? ? if (item.isChecked) {
? ? ? ? ? ? ? ? // 选中 → 需要累加
? ? ? ? ? ? ? ? return sum + item.num
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? // 没选中 → 不需要累加
? ? ? ? ? ? ? ? return sum
? ? ? ? ? ? ? }
? ? ? ? ? ? }, 0)
? ? ? ? ? },
? ? ? ? ? // 总计选中的总价 num * price
? ? ? ? ? totalPrice () {
? ? ? ? ? ? return this.fruitList.reduce((sum, item) => {
? ? ? ? ? ? ? if (item.isChecked) {
? ? ? ? ? ? ? ? return sum + item.num * item.price
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? return sum
? ? ? ? ? ? ? }
? ? ? ? ? ? }, 0)
? ? ? ? ? }
? ? ? ? },
? ? ? ? methods: {
? ? ? ? ? del (id) {
? ? ? ? ? ? this.fruitList = this.fruitList.filter(item => item.id !== id)
? ? ? ? ? },
? ? ? ? ? add (id) {
? ? ? ? ? ? // 1. 根据 id 找到数组中的对应项 → find
? ? ? ? ? ? const fruit = this.fruitList.find(item => item.id === id)
? ? ? ? ? ? // 2. 操作 num 数量
? ? ? ? ? ? fruit.num++
? ? ? ? ? },
? ? ? ? ? sub (id) {
? ? ? ? ? ? // 1. 根据 id 找到数组中的对应项 → find
? ? ? ? ? ? const fruit = this.fruitList.find(item => item.id === id)
? ? ? ? ? ? // 2. 操作 num 数量
? ? ? ? ? ? fruit.num--
? ? ? ? ? }
? ? ? ? },
? ? ? ? watch: {
? ? ? ? ? fruitList: {
? ? ? ? ? ? deep: true,
? ? ? ? ? ? handler (newValue) {
? ? ? ? ? ? ? // 需要将变化后的 newValue 存入本地 (转JSON)
? ? ? ? ? ? ? localStorage.setItem('list', JSON.stringify(newValue))
? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? }
? ? ? })
? ? </script>
? </body>
</html>