Vuejs--属性绑定以及v-for指令

165 阅读9分钟

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的区别

  1. 区别一:
    使用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的使用

  • 遍历数组
    1. 不获取index值, <li v-for="item in/for items"> {{item}}</li>
    2. 获取index值, <li v-for="(item,index) in/for items"> {{item}}{{index}}</li>
  • 遍历对象
    1. 不获取index,key值 , <li v-for="item in/for items"> {{item}}</li>
    2. 不获取index值, <li v-for="(item,key) in/for items"> {{item}}--{{key}}</li>
    3. 都获取i <li v-for="(item,key,index) in/for items"> {{item}}--{{key}}--{{index}}</li>