利用 Vue 实现一个简单的购物车,提供单选、全选、取消全选、增减数量、价格计算的功能
一共应用到了以下几个 Vue 的知识点:
- vue-resource
- v-for
- v-bind
- filters
- v-model
- v-on
- watch
- computed
后端返回的购物车数据
后端返回的购物车数据如下。list
就是一个一个的商品数据,比如 ID、名称、单价、个数、图片和赠品
1 | { |
获取后端数据
1 | var vm = new Vue({ |
cartView
的方法体里,使用 vue-resource 发起 HTTP GET 请求,然后获取到后端数据,并赋值给 productList
变量。同时,这里还用到了箭头函数。为什么要用箭头函数?
如果不用箭头函数的话,cartView
得这么写
1 | cartView: function () { |
因为箭头函数的作用域指向的是外层,箭头函数内的 this
指向的是外层的 this
使用 v-for 进行列表渲染
现在已经获取到了后端数据,并将数据存放在 productList
中,现在就可以使用 v-for
把购物车数据列表展示出来
1 |
|
得到的效果如图
使用 v-bind 绑定 HTML 标签的属性
对于文本,使用 { { item.productImage } }
这样的插值表达式展示即可。如果是 <img>
标签的 src
属性,则应该使用 v-bind
指令
1 | <img v-bind:src="item.productImage" width="50px" height="50px"/> |
v-bind
指令就是专门用来绑定 HTML 标签的属性用的,比如 <div v-bind:id="item.productId"></div>
、<img v-bind:src="item.productImage" />
、<a v-bind:href="url">...</a>
等等
使用过滤器(filters)格式化商品金额
后端返回的商品信息如下:
1 | { |
商品单价(productPrice)是纯数字,不带有人民币的符号 ¥
也没有小数点。但是网页上需要显示人民币的符号和小数点。这时候可以使用 Vue 的过滤器(filters)
全局过滤器有两种:全局过滤器和局部过滤器。全局过滤器可以用在任何一个页面中。局部过滤器只能用在当前的 Vue 实例中
在 Vue 的实例里添加一个 filters,然后加上一个 money
方法
1 | var vm = new Vue({ |
然后在数据绑定上使用 |
加上方法名
1 | 单价: {{ item.productPrice | money }} |
这样就可以得到这样的效果
过滤器可以传入参数,将过滤器改为
1 | var vm = new Vue({ |
使用的时候这么使用
1 | 单价: {{ item.productPrice | money('元') }} |
现在效果就变成这样了
v-model 对表单进行双向数据绑定
1 | 数量: |
修改 <input>
标签的值,也会更新 Vue 实例 data 中的值。同样的,更新 Vue 实例 data 中的值也会修改 <input>
标签的值
使用 v-on 监听 DOM 的点击事件,对商品数量进行增减
用户点击商品数量的增减按钮,改变商品的数量同时改变商品的总价。点击事件可以使用 v-on:EventName
指令。v-on:
可以缩写为 @
对商品数量进行增减,可以监听 <button>
的 click
事件
1 | 数量: |
然后在 Vue 的实例中添加一个方法
1 | var vm = new Vue({ |
v-on、v-bind 与 Vue.set() 实现选中与取消选中商品
现在定义了两个 class
1 | <style> |
HTML 中添加一个 <a>
标签,并默认应用 item-check-btn
的 css 样式。
1 | <a class="item-check-btn"></a> |
然后加上一个点击事件的监听,修改商品的选中状态。如果商品选中了就应用 check
的 css 样式,否则就去掉 check
样式
1 | <a class="item-check-btn" v-bind:class="{ check: item.checked }" @click="selectProduct(item)"></a> |
注意:
现在有一个问题,从后端返回的购物车数据中,商品不存在 checked
属性,这样应该怎么办?
按照 javascript 给对象添加属性的方法,selectProduct
方法的实现是这么写
1 | selectProduct: function (product) { |
没有选择商品的时候,checked
属性不存在于对象中
选中商品之后,现在对象中有了 checked
属性,并且值为 true
。但是页面上没有变化
再取消选中商品,checked
的值变为 false
,但是页面还是没有变化
按照 Vue 官网上的解释:
因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = ‘hi’)
对于这种情况应该使用 Vue 的 Vue.set() 或者 vm.$set() API
1 | selectProduct: function (product) { |
对于全选按钮
1 | <div style="margin-bottom: 30px"> |
跟上面一样,使用 v-bind:class
绑定 css 的样式,用 v-on:click
监听 click
事件
1 | selectAll: function () { |
计算商品的总金额
1 | <div style="margin-bottom: 30px"> |
普通实现
执行增减数量、选中与取消选中、删除操作时,商品总金额会发生变化,增加一个计算总价的方法
1 | calcTotalPrice: function () { |
然后把 calcTotalPrice
方法放到几个操作商品方法的方法体最后面
1 | var vm = new Vue({ |
利用 watch 监听数据的变化,然后计算总金额
利用 Vue 的 watch
监听 Vue 实例的 data
的变化,然后计算总金额
有个要注意到地方:
为了发现对象内部值的变化,可以在选项参数中指定
deep: true
为了监听商品的选中状态、数量的变化,所以需要加上 deep: true
1 | var vm = new Vue({ |
利用计算属性来计算总金额
1 | var vm = new Vue({ |
这时候 data
就不需要再定义 totalPrice
变量了,HTML 页面上直接使用计算属性 totalPrice
的名称即可
1 | <div style="margin-bottom: 30px"> |
使用数组的 splice 方法删除商品
加一个 <button>
标签,并添加点击事件。这没什么难的,但是有个需要注意的地方:
方法名不要和 Vue 的自带方法名重复了
比如我定义的 delete
方法就和 Vue 自带的 delete 方法重复了
1 | delete: function (product) { |
点击 <button>
却没有删除商品。换一个方法名就好了
1 | deleteProduct: function (product) { |
这样点击删除按钮就能删除商品了