Vue中的属性绑定和双向数据绑定
v-bind:进行属性绑定
举个例子
<div title="hello"></div>
很多时候我们想要title属性不要写死,要像之前的DOM元素的内容一样,和数据进行绑定怎么办呢?
方法很简单:直接在属性前面加上 v-bind:<div id="root"v-bind:title="title">hello world</div>
这样就可以让title属性的值变成一个js的表达式,和前面学习的v-text一样。
v-bind:指令还可以进行简写:<div id="root":title="title">hello world</div>
":"<==>"v-bind:"
v-bind:动态绑定class(对象语法)
很多情况下,我们的class往往不是写死的。而是动态改变的。那么我们怎么实现呢?那我们可以通过操控数据来决定class的显示与否。
<div :class="{className1:bool,className2:bool}"></div>
这就是class的对象写法。通过后面的bool值决定这个class要不要进行显示。这种写法用的非常多。一个要注意的点是<div class="className1" :class="{className2:bool}"></div>
这种写法是不会覆盖的,而是会进行合并。那么这样,我们可以将那些一直绑定的class放在位置1,要动态决定的class放在位置二
v-bind:绑定class(数组写法)
<div :class="['className1','className2']"></div>
这种写法就是数组写法,但是他不能通过数据动态决定。
v-bind:动态绑定style(对象写法)
首先在js中css属性的写法font-size===fontSize。
使用v-bind绑定css属性,其实就是使用对象的键值对的形式。css属性作为键,然后css属性的值是一个字符串。
<div :style="{font-size:'50px'}"></div>//如果写50px那么显然就把50px当成变量了
这时候我们可以通过数据去替换这个'50px'字符串,所以我们可以通过数据决定元素的样式。
v-bind绑定style(数组写法)
<div :style="[fontsize1,bgc....]"></div>
数组的每个元素其实就是刚刚的那种对象,比如fontsize1={font-size:"50px"},用的很少
Vue中的计算属性和侦听器
计算属性
同样,我们从一个简单的小例子入手:
<body>
<div id="root">
姓:<input type="text" v-model="firstName">名: <input type="text" v-model="lastName">
<p>{{firstName}}{{lastName}}</p>
</div>
<script>
new Vue({
el:"#root",
data:{
firstName:"",
lastName:""
}
})
</script>
</body>
显示如下:
但是firstName和lastName这样生硬的拼接,看起来真的有点low。能不能这样给这个名字起个变量名叫fullName,他应该是firstName和lastName相加得来的。fullName就是一个计算属性,它是由其他数据计算而来的。
<p>{{fullName}}</p>
计算属性应该定义在Vue实例的computed属性里面,这个属性值是一个对象。这个对象的属性名,就应该是那个要计算的数据,对应的属性值是一个函数,返回计算结果
<div id="root">
姓:<input type="text" v-model="firstName">名: <input type="text" v-model="lastName">
<p>{{fullName}}</p>
</div>
<script>
var a = new Vue({
el:"#root",
data:{
firstName:"",
lastName:"",
},
computed:{
fullName:function()
{
return this.firstName+""+this.lastName
}
}
})
</script>
这个this应该好理解吧:就跟对象一样,这个this应该指向的是Vue实例。
计算属性它的优势在哪:
就是他的性能很高:当你使用它的时候,如果它的计算项并没有发生改变,它是不会去做计算的,它会使用上一次计算结果的缓存值,只有当计算项发生改变了,它才会重新计算。这样的话,它能做更少的事达到同样的目的。
深入理解计算属性
从上面的代码可以看出来,计算属性对应的是一个方法,为什么使用的时候,是fullName而不是fullName()呢?这里面的学问还有点大,其实计算属性fullName对应的其实是一个对象并不是一个函数,所以使用它的时候并不能加(),看下面的代码
computed:{
fullName:{
set:function()
{
console.log("set被调用");
return 1;
},
get:function()
{
console.log("computed被调用")
return this.firstName+this.lastName;
}
}
}
其实计算属性对应的是一个对象,而不是一个函数,这个对象有两个方法。一个是get方法,一个是set方法。当你读取计算属性的时候,实际上调用的是get方法。当你想改变计算属性的值的时候实际上调用的是set方法。
example:
<p>{{fullName}}</p>//这就是读取计算属性。
当你在控制台输入app.fullName="lixian"
,方法。
值得注意的是,计算属性默认是一个只读属性,也就是默认情况下它不存在set方法,所以通常是不写的。所以最后就精简为了
computed:{
fullName:function()
{
return this.firstName+""+this.lastName
}
}
所以它本质是一个对象,不是一个函数。
那我有个小疑问,当你在控制台输入app.fullName="li xian"
,他会做出相应的改变嘛?答案是不会的,你做这步操作他仅仅会帮你调用它的set方法,然而它的set方法我现在什么都没实现,那么这就是一个无效的命令。那么要实现目的得怎么做呢?你要在set方法中去改变fullName的值,怎么改变fullName的值呢?只能改变firstName和lastName的值,当你改变了他俩的值,他就会自动调用get方法重新计算fullName的值
computed:{
fullName:{
set:function(newName)
{
let arr = newName.split(" ");
this.firstName=arr[0];
this.lastName=arr[1];
},
get:function()
{
console.log("computed被调用")
return this.firstName+this.lastName;
}
}
}
侦听器
侦听器的作用是监听一个数据或是一个计算属性的改变,如果改变了就应该执行对应的方法。
它写在vue实例的watch属性里,属性值是一个对象。对象的属性名,是你要监听的数据或是计算属性,值是数据或是计算属性改变后触发的方法。方法的第一个参数是改变后的值,第二个参数是改变前的值。
<div id="root">
姓:<input type="text" v-model="firstName">名: <input type="text" v-model="lastName">
<p>{{fullName}}</p>
<p>{{count}}</p>
</div>
<script>
var a = new Vue({
el:"#root",
data:{
firstName:"",
lastName:"",
count:0
},
computed:{
fullName:function()
{
return this.firstName+""+this.lastName
}
},
watch:{
fullName:function()
{
this.count++;
}
}
})
</script>
v-show v-if v-for 指令
v-show指令
控制DOM元素的显示与否,后面跟一个值,如果值是true则显示,如果值是false,则隐藏。
v-if指令
也是控制DOM元素的显示与否,后面跟一个值,如果值是true则显示,如果值是false,则隐藏。
v-if和v-show的区别
- 区别一:
使用v-if指令,是动态的增加和删除DOM,也就是如果它是false,他不会出现在DOM树中。而v-show指令,是改变DOM的样式,控制它的display属性。
这导致一个后果就是,如果DOM元素需要频繁的显示/隐藏的话,v-show的性能明显高于v-if。因为v-if要一直添加/删除DOM,而v-show只需要改css样式即可。
2.区别二:
v-if指令是具有惰性的,只有v-if的条件第一次为真的时候,才会开始局部编译,进行渲染条件块,(然后将编译缓存,切换条件的时候再局部卸载。)
而v-show却不一样,不管条件是否为真,他都会渲染条件块,再根据条件操作css样式。这个区别导致了v-if初始加载的性能更高,因为他是惰性的,他会判断直到为真的时候才会进行渲染,减轻了服务器的压力。
总结:
v-show 切换性能高,所以适用于需要频繁隐藏/显示的情形。
v-if初始渲染性能高,所以适用于状态不大可能改变的情形。
v-for指令
列表渲染
就是把一组数据用遍历的方式渲染到页面上,类似ES6中的for of循环
<div id="root">
<ul>
<li v-for="(items,index) of item">{{items}}-{{index}}</li>
</ul>
</div>
<script>
new Vue(
{
el:"#root",
data:{
item:{
a:1,
b:2,
c:3
}
}
})
</script>
在这里,<li v-for="items of item">
是等价于<li v-for = items in item>
的。ES6里面的for of是不可以遍历对象的,但是这里是可以遍历对象的。如果既要得到键名又要得到键值应该采用这种写法:<li v-for="(items,index) in/of item">
注意是()不是[],还有顺序是键名,键值的顺序。
列表渲染实际上要和一个key属性进行绑定使用。
为什么要进行绑定使用呢?
v-for进行渲染的时候有一个就地复用的策略,这是为了提高渲染的效率而出现的:简单来说就是这样,当你更新已经渲染的列表的时候(很简单:就比如我把data里面的数组增加/删除/插入一个值),如果你要重新渲染这个列表,肯定是效率很低的,如果这个列表项数据没有发生改变的话我们没有必要去重新渲染它,我们直接复用它就好。那怎么实现这个过程呢,换言之,我们怎么去判断某个列表项他到底有没有发生改变呢?我们可以给每个列表项做一个标记,这个标记实际上就是key属性,既然是标记,肯定是要独一无二与众不同的,所以key值在同一个列表渲染中具有唯一性。(类似我们人的身份证)当我们更新列表的时候,实际是这样一个过程(我自己想像的一个过程应该大致没有错):比如说之前有三个列表项,值是a,b,c。与之对应的:三个key值是1,2,3。当我更新列表的时候,比如我把第三个的值改成了d(c-->d),渲染的时候会执行一个怎样的逻辑呢?它会根据key值判断某个值是否发生改变。首先,它判断key值等于1的那个值有没有改。发现并没有改变,还是a,就直接复用......直到最后一个key值等于3的发现值发生改变了!所以他要重新的渲染。这就是key值的意义,目的是让浏览器更少的事,更少的渲染,更多的复用,达到目的。
key值的选择
用数组的index作为的弊端
使用index作为key值有一定的好处,就是key值不会重复。
弊端:首先看两种情况:
1.从尾部更新上述这个数组[1,2,3]===>[1,2,3,4],前三个列表项,key值对应的那个值是没变的,所以直接就地复用。只需要重新渲染一个列表项
2.从别的位置插入,比如从首部插入:[1,2,3]===>[4,1,2,3],key值为0的项值从1-->4,key值为1的项值从2-->1。。。。导致四个列表项都要重新渲染
最好的方法是给每一组数据都绑定一个唯一的id作为它的key值
<div id="root">
<ul>
<li v-for="items of item" :key="items.id">{{items.value}}</li>
</ul>
</div>
<script>
new Vue(
{
el:"#root",
data:{
item:[
{
id:1,
value:"wo"
},
{
id:2,
value:"shi"
},
{
id:3,
value:"zhu"
},
]
}
}
)
</script>
key值实际上是跟虚拟DOM使用diff算法有关。
简单解释一下虚拟DOM使用diff算法的更新过程:
比如我们在CD之间插入插入一个F
diff算法默认执行过程是这样的:
将C更新成F ,D更新成C,E更新成D。。。。这样的效率是很低很低的。
那么我们引入key值来标记每一组数据,从而diff算法能正确的识别每一个节点。在相应的位置插入元素。
key值就是为了让高效的更新虚拟的DOM,办更少的事儿,达到同样的效果。
v-for的使用
- 遍历数组
- 不获取index值,
<li v-for="item in/for items"> {{item}}</li>
- 获取index值,
<li v-for="(item,index) in/for items"> {{item}}{{index}}</li>
- 不获取index值,
- 遍历对象
- 不获取index,key值 ,
<li v-for="item in/for items"> {{item}}</li>
- 不获取index值,
<li v-for="(item,key) in/for items"> {{item}}--{{key}}</li>
- 都获取i
<li v-for="(item,key,index) in/for items"> {{item}}--{{key}}--{{index}}</li>
- 不获取index,key值 ,