最近在学习vue,其中对购物车的编写有点感悟。先来看看简单的业务代码
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title></title>
<style>
h1 p {
display: inline-block;
font: 16px normal;
}
h1 p span {
background: #eee;
border-radius: 50%;
}
</style>
<script type="text/javascript" src="vue.js"></script>
</head>
<body>
<div id="myShoppingCart">
<h1>{{name}}的购物车
<p>清单总数<span>{{items.length}}</span></p>
<p>未采购数<span>{{count}}</span></p>
</h1>
<div>
<!--双向绑定数据,对应data下的text-->
<input type="text" v-model="text">
<!-- //添加操作 -->
<button v-on:click="addList(text)">添加</button>
</div>
<table>
<thead>
<tr>
<th>清单名称</th>
<th>已采购</th>
<th>状态</th>
<th>删除</th>
</tr>
</thead>
<tbody>
<!-- 遍历items,让其所有分别在td展示出来 -->
<tr v-for="(item, index) in items">
<!--展示清单名称,对应items下的action-->
<td>{{item.action}}</td>
<!--用checkbox显示是否选中,逻辑对应items下的state(v-model),另外需要进行对count进行绑定,选中的未采购数相应变化(减少)-->
<td ><input type="checkbox" v-model="item.state" v-on:click="myCount()"></td>
<!--设置状态,对应items.stated的值,可以再进行完善,如显示为,'已添加'-->
<td>{{item.state}}</td>
<!--需要进行相应的采草-->
<td><button v-on:click="del(index)">删除</button></td>
</tr>
</tbody>
</table>
</div>
<script>
/* Vue.component('todo-item',{
props: ['todo'],
template: '<li>{{todo.text}}</li>'
})*/
//新建new Vue
var app = new Vue({
//绑定#myShoppingCart
el: '#myShoppingCart',
//数据逻辑,购物车的对应操作都是通过data的数据操作进行
data: {
//对应23行的{{name}}
name: 'Desmond',
//购物车的状态,清单数据
items: [
{
action: 'iPhone7',
state: false
},
{
action: 'iPhone7 Plus',
state: false
},
{
action: 'Samsung Note9',
state: false
},
{
action: '一加6',
state: false
}
],
//对应28行input的数据,v-model进行双向绑定
text: '',
//对应未采购数
count: 0
},
//生命周期特点,可以简单理解为“页面加载完后”。这里‘当页面加载完’后,进行计数统计
mounted: function() {
this.myCount()
},
methods: {
//添加方法,传input.value进去,因为双向绑定了,即为text
addList: function(text) {
//当为空值时,不进行任何操作
if(this.text == '') return;
//只进行数据操作,将数据添加进data内
this.items.push({action: text, state: true});
//每次执行完后,需要对input清空
this.text = '';
//并对count进行操作,当TRUE不变化,false时则+1
this.myCount();
},
myCount: function(){
var _this = this;
_this.count = 0;
//对当前所有items进行遍历
this.items.forEach(function(el, index){
if(!el.state) _this.count++
})
},
del: function(index){
//仅进行数据操作,删除当前的数据
this.items.splice(index,1)
}
}
})
</script>
</body>
</html>
这里我在代码已经进行基本的解释。主要说说爬的坑,this的指向。
相信大部分的同学都了解过this指向的是new Vue这个对象,那么我这里就是指向app了。
这样说起来,这是什么鬼?指向app了?那么像addList,myCount,del方法(函数)究竟是怎么操作的呢?
就上面的addList的this.text为例子,这里的this确实是app(#myShoppingCart)。因为 text 用v-model双向绑定,而我们的this.text == '';能够起到效果就是最好的证明.
正当我也是这么认为的时候,大坑就来了。没错,myCount方法这样写的时候,未采购数没有任何变化。有兴趣的同学可以将112~119行代码换成以下代码进行验证。
myCount: function(){
this.count = 0;
//对当前所有items进行遍历
this.items.forEach(function(el, index){
if(!el.state) this.count++
})
},
经过对比两次代码是因为用了_this = this,那么为什么要这样做呢?为什么就是myCount方法这样用,其他方法不这样用。一开始我也实在爬不出这坑(原谅我是菜鸟,而且又不报错,这就千言万语说不出来了),还好就只有那么几句代码,聚句百度、Google,终于找到了forEach这个原因。根据搜索到资料:'forEach
循环体是以一个函数体的形式去循环的,this是会改变的’。
根据前半句,我就完全懵逼了,但是,我知道是this指向发生了改变,那么只要将之前的this储存起来不就好了。所以就有了_this = this。
同时,这个forEach浪费了我那么多时间,我也为了避免再次掉坑,就专门回去看一遍forEach的用法,然后百度了一下,发现一下这篇文章写的不错,专门说了下this的问题,详情查看以下文章。