chaihongjun.me

Vue极简单购物车checkbox

Vue极简单购物车checkbox

一个简单的购物车功能:

  1. 显示并列出产品的各项参数(商品名称,商品单价,购买数量,是否从购物车拿走,以及选择功能)

  2. 购买数量必须是大于等于1,如果不想购买,可以通过单击“移除”按钮,删除商品

  3. 显示全部产品的总价

  4. 显示选中的产品的总价

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1">
    <!--PC端必选   强制360浏览器使用webkit渲染 -->
    <meta name="renderer" content="webkit">
    <link rel="stylesheet" type="text/css"  href="css.css">
    <title>购物车</title>
    <style>
    table {
    border: 1px solid #ccc;
}

thead {
    background-color: #ddd;
}

td {
    border: 1px solid #ccc;
}


[v-cloak]{
    display: none
}
    </style>
</head>

<body>
    <div>
        <p>购物车需求</p>
        <ol>
            <li>展示已经加入购物车的商品列表</li>
            <li>商品列表包含商品名称,商品单价,购买数量和操作能力</li>
            <li>能够实时显示所购买的总价</li>
            <li>商品数量可以增加,减少或者直接移除</li>
        </ol>

    </div>
    <hr>
    <!-- 页面挂载点 -->
    <div id="app" v-cloak>
        <template v-if="goods.length">
            <table>
                <thead>
                    <tr>
                        <td>表头</td>
                        <td>商品名称</td>
                        <td>商品单价</td>
                        <td>购买数量</td>
                        <td>操作</td>
         <td>全选<input type="checkbox" @click="checkAll" id="checkAll" :checked="isCheckedAll"></td>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for="(good,index) in goods">
                        <td>{{index+1}}</td>
                        <td>{{good.name}}</td>
                        <td>{{good.price}}</td>
                        <!-- 数量调整 -->
                        <td>
                            <button @click="reduce(index)" :disabled="good.count === 1">-</button>
                            {{good.count}}
                            <button @click="add(index)">+</button>
                        </td>
                        <!-- 操作 -->
                        <td>
                            <button @click="remove(index)">移除</button>
                        </td>
                        <td>
                             <!-- 单选 -->
                         <input type="checkbox" @click="check(index,$event)" :checked="good.isChecked">
                        </td>
                    </tr>
                </tbody>
            </table>
            <div><p> 全部总价:¥{{totalPrice}}</p>

                    <p>选中总价: ¥{{checkedPrice}}</p>

            </div>
        </template>
        <div v-else>购物车是空的</div>
    </div>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    
    <script> 
    var app = new Vue({
    el: '#app',
    data: {
        //商品数据
        goods: [
            { id: 1, name: 'iphone 7', price: 6188, count: 1, isChecked: false },
            { id: 2, name: 'ipad Pro', price: 5888, count: 1, isChecked: false },
            { id: 3, name: 'MacBook Pro', price: 21488, count: 1, isChecked: false },
            { id: 4, name: 'iPod', price: 588, count: 1, isChecked: false }
        ],
    },
    computed: {
        totalPrice: function() {
            var total = 0;
            //遍历相加
            this.goods.forEach(function(item, index) {
                total += item.price * item.count;
            })
            return total;
        },
        //是否全选
        isCheckedAll: function() {
            var flag = true;
            //遍历数组选项
            this.goods.forEach(function(item, index) {
                //数组项没有选中
                if (!item.isChecked) {
                    flag = false;
                }
            })
            return flag;
        },
        //选中的产品价格
        checkedPrice: function() {
            var total = 0;
            this.goods.forEach(function(item, index) {
                if (item.isChecked) {
                    total += item.price * item.count;
                }
            })
            return total;
        }
    },
    methods: {
        reduce: function(index) {
            //再次判断 reduce 减法的可靠性
            if (this.goods[index].count === 1) return;
            this.goods[index].count--;
        },
        add: function(index) {
            this.goods[index].count++;
        },
        remove: function(index) {
            //删除一条数组数据
            this.goods.splice(index, 1);
        },
        //全部选择
        checkAll: function() {
            this.goods.forEach(function(item, index) {
                item.isChecked = !item.isChecked;
                //console.log(item.isChecked);
            })
        },
        check: function(index, event) {
            this.goods[index].isChecked = !this.goods[index].isChecked;
        }
    },
})    
    </script>
</body>

</html>

难点思路说明:

  1. 全选按钮绑定了一个计算属性isCheckedAll,这个属性的最终取值"true|false",是根据全部子选项的选择状态而确定的,如果选全部的子选项是选中的,则该属性是true,如果不是全部选中的,则是false。那么如何判断子选取的状态呢?通过JS原生的forEach方法,该方法针对数组元素有遍历功能,所以通过对数组goods的遍历来做判断即可:

      isCheckedAll: function() {
            var flag = true;
            //遍历数组选项
            this.goods.forEach(function(item, index) {
                //数组项没有选中
                if (!item.isChecked) {
                    flag = false;
                }
            })
            return flag;
        }

forEach里面的item和index分别代表数组项和索引,这里item指代每个产品项对象,比如{ id: 1, name: 'iphone 7', price: 6188, count: 1, isChecked: false }

  2.如何实现全选/反全选功能?和前面的思路一样,当点击全选按钮的时候子选项的状态全部变化,再次点击又再次变化,全选按钮实现的其实就是子选项的两种状态切换:

        checkAll: function() {
            this.goods.forEach(function(item, index) {
                item.isChecked = !item.isChecked;
                //console.log(item.isChecked);
            })
        },

也是遍历每个对象,然后取反。

3.单个子选项的点击切换和上面的类似,但是要求在用v-for渲染列表的时候必须显示的写出每个对象的索引(index)

 <tr v-for="(good,index) in goods">

然后再通过函数传入方法内:

   check: function(index) {
            this.goods[index].isChecked = !this.goods[index].isChecked;
        }

这里的index是指向当下点击的那个checkbox按钮,那么this.goods[index]也就指向了对应的数据对象

知识共享许可协议本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。作者:柴宏俊»