在开始写代码前,要对需求进行分析,这样有助于我们理清业务逻辑,尽可能还原设计与产品交互。购物车需要展示一个已加入的商品列表,包含商品名称、商品单价、购买数量和操作等信息,还需要实时显示购买的总价。其中购买数量可以增加或者减少,每类商品还可以从购物车中移除。最终实现的效果如图·:
在明确需求之后,就可以编程了,因为业务代码比较多,这次我们将HTML、CSS、JavScript分离为3个文件,便于阅读和维护:

  • index.html(引入资源及模板)
  • index.js(Vue实例以及业务代码)
  • style.css(样式)

首先在index.html引入Vue.js和相关资源,创建一个根元素来挂载Vue实例:

<!DOCTYPE html>
<html>

    <head>
        <meta charset="utf-8">
        <title>购物车</title>
<link rel="stylesheet" href="test.css"  href="style.css"/>
    </head>

    <body>
        <div id="app" v-cloak>  </div>
          <script src="img/js/vue.js"></script>  
          <script src="img/js/index.js"></script>
    </body>

</html>

注意这里将Vue.js和index.js文件写在body的最底部,如过写在head里,Vue实例将无法创建,因为此时DOM还没有被解析完成。
本例用到的Vue.js的computed、methods等选项,在index.js中先初始化实例。

我们需要的数据比较简单,只有一个列表,里面包含了商品名称,单价,购买数量。在实际业务中,这个列表是Ajax从服务端动态获取的,这里只做示例,所以直接写入在data选项内,另外每个商品应该有一个全局唯一的id。我们在data内写入列表list:

var app=new Vue({
    e1:'#app',
    data:{
        [
        {
            id:1,
            name:'苹果8',
            price:4999,
            count:1
        },
        {
            id:2,
            name:'小米6',
            price:1999,
            count:2
        },
        {
            id:3,
            name:'华为8',
            price:5999,
            count:9
        },
        ]

    },
    computed:{

    },
    methods:{

    }
});

数据构建好后,可以在index.html中展示列表了,毫无疑问,肯定会用到v-for,不过在此之前,我们要做一些小的优化,因为每个商品都是可以从购物车移除的,所以当列表为空时,在页面中显示一个“购物车为空的”提示更为友好,我们可以通过判断list的长度来实现此功能。

<template v-if="list.length"></template>
        <div v-else>购物车为空</div>

template里面的代码分为两部分,一部分是商品列表信息,我们用表格table来展现:另一部分就是带有千位分隔符的商品总价(每隔三位数加进一个逗号),这部分的代码如下:

<template v-if="list.length"></template>
        <table>
            <thead>
                <tr>
                    <th></th>
                    <th>商品名称</th>
                    <th>商品单价</th>
                    <th>购买数量</th>
                    <th>操作</th>
                </tr>               
            </thead>
            <tbody>

            </tbody>        
        </table>
        <div>总价:¥{{totalPrice}}</div>
        <div v-else>购物车为空</div>

总价totalPrice是依赖于商品列表动态变化的,所以我们用计算属性来实现,顺便将结果转换为带有千位分隔符的数字,在index.js的computed选项内写入。
这段代码的难点在于千位分隔符的转换,最后就剩下商品列表的渲染和相关的几个操作了,先在<tbody>内把数组list用v-for指令循环出来:

<tbody>
<tr v-for="(item,index) in list">
    <td>{index+1}</td>
    <td>{{item.name}}</td>
    <td>{{item.price}}</td>
    <td>
        <button
            @click="handleReduce(index)"
            :disabled="item.count===1"
            >-</button>
            {{item.count}}
            <button
                @click="handleAdd(index)"
            >+</button>     
    </td>
    <td>
        <button
            @click="handleRemove(index)"
            >移除</button>

    </td>
</tr>               
            </tbody>

商品序号、名称、单价、数量都是直接使用插值来完成的,在第4列的两个按钮用于增减购买数量,分别绑定了两个方法handleReduce和handleAdd,参数都是当前商品在数组list中的索引,很多时候一个元素上会使用多个特性,写在一行代码比较长,不便阅读,所以建议特性过多的时候,将每个特性单独写一行,这里给<button>动态绑定了disabled特性来禁用按钮。
在index.js中完成剩余的三个方法:

methods:{
        handleReduce:function(index){
            if(this.list[index].count===1)
            return;
            this.list[index].count--;
        },
        handleAdd:function(index){
            this.list[index].count++;       
        },
        handleRemove:function(index){
            this.list.splice(index,1);
        }


    }

这3个方法都是直接对数组list的操作,没有太复杂的逻辑,需要说明的是,虽然在button上已经绑定了disabled特性,但是在handleReduce方法内又判断了一遍,这是因为在某些时候,可能不一定用button元素,也可能是div、span元素等,给他们增加disabled是没有任何作用的,为了安全起见,在业务逻辑上再判断一次,避免因修改HTML模板后出现BUG.

Logo

前往低代码交流专区

更多推荐