在开始写代码前,要对需求进行分析,这样有助于理清业务逻辑,尽可能还原设计与产品交互。
购物车需要展示一个已加入购物车的商品列表,包括商品名称、商品单价、购买数量和操作等信息,还需要实时显示购买的总价。其中购买数量可以增加或减少,每类商品还可以从购物车中移除。
这里需要把
js
文件写在<body>
的最底部,如果写在<head>
里面,Vue实例将无法创建,因为此时DOM还没有被解析完成,除非通过异步或在事件DOMContentLoaded
(IE是onreadystatechange
)触发时再创建Vue实例,这有点像jQuery的$(document).ready()
方法。
在实际业务中,数据列表应该是通过AJAX从服务端动态获取,这里直接写入在data
选项内,另外每个商品还应该有一个全局唯一的ID
。
data: {
list: [
{
id: 1,
name: 'iPhone 7',
price: 6188,
count: 1
}, {
id: 2,
name: 'iPad Pro',
price: 5888,
count: 1
}
]
}
因为每个商品都是可以从购物车移除的,所以当列表为空时,在页面中显示一个“购物车为空”的提示更为友好,可以通过判断数组list
的长度来实现该功能。
<div id="app" v-cloak>
<template v-if="list.length"></template>
<div v-else>购物车为空</div>
</div>
<template>
中的代码分两部分,一部分是商品列表信息,用表格table
展示;另一部分是带有千分位分隔符的商品总价(每个三位数加进一个逗号)。
<template v-if="list.length">
<table>
<thead>
<tr>
<th></th>
<th>商品名称</th>
...
</tr>
</thead>
<tbody></tbody>
</table>
<div>总价:¥ {{totalPrice}}</div>
</template>
总价totalPrice
是依赖于商品列表动态变化的,所以用计算属性来实现。
computed: {
totalPrice: function () {
var total = 0;
for (var i = 0; i < this.list.length; i++) {
var item = this.list[i];
total += item.price * item.count;
}
return total.toString().replace(/\B(?=(\d{3})+$)/g, ',');
}
}
商品序号、名称、单价、数量都是直接使用插值完成。
很多时候,一个元素上会同时使用多个特性(尤其是在组件中使用props
传递数据时),写在一行代码较长,不便阅读,所以建议特性过多时,将每个特性都单独写成一行。比如<button>
中使用了v-bind
和v-on
两个指令。
每件商品购买数量最少是1件,所以当count
为1时,不允许再继续减少,这里给<button>
动态绑定了disabled
特性来禁用按钮。
<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>