今天的内容书接上回,同样是vue的核心基础部分,今天偏向于理论性,特别是vue对于数据对象的监测那一块,刚开始琢磨了半天,这股劲一过,现在好理解多了
10.watch和computed对比
计算属性案例(watch来做)
在增加一条需求输入姓后要反应一秒后再响应
computed
==区别== :
- computed能完成的功能,watch都可以完成
- watch可以完成的功能,computed不一定能完成,就比如watch这里可以异步操作,computed就不行,<u>因为computed里面我们靠的就是那个返回值让他的getter返回值就会等于fullname这个计算属性,所以如果返回值给了定时器,那么我的fullname就没有得到返回值,但是watch不一样,watch是对值做操作,在定时器里面就已经完成了赋值的操作,不需要你返回给我</u>
==注意== :
- 前面都说被vue所管理的函数最好别写箭头函数,但是这里的定时器必须写为箭头函数,因为如果是普通函数那么他的this就为window,定时器的this本身就是为window,但是如果这里是箭头函数,都知道,箭头函数的this是定义它位置的地方的this,所以就是监视这个属性里面的this就是vm实例
- 被vue所管理的函数最好写成普通函数,==不被vue所管理的函数(定时器、ajax回调、promise的回调)最好写成箭头函数==
11.绑定class样式
-
字符串写法,适用于:==样式类名不确定,需要动态指定==
注意一下这里的生成随机整数是怎么的写法
-
数组写法:==适用于:个数不确定,类名也不确定的时候==,个数我以后 可能有一百个可能有几个,名字可能叫这个可能叫那个
-
对象写法:==适用于个数确定,类名也确定==,我只有这两个,也只叫这个名字
-
绑定style样式(了解)这是对象写法,同样也有数组写法,就是fontsize写在这个对象,background写在那个对象,数组写法就是将两个对象结合起来【obj1,obj2】
12.条件渲染
控制元素的隐藏显示
全新指令语法:==v-show、v-if==他们两个都可以实现显示隐藏,v-show底层实现是display:none,v-if直接把元素都删没了,所以当我们需要频繁切换显示隐藏的时候建议v-show
案例:
==v-else-if==跟v-if是一组的判断,如果前面达成条件后面就不再做判断
==v-else== 注意v-else后面就不跟条件了直接写上v-else,出了条件外的都显示他
==注意==v-if判断是一个整体,包括else if、else,中间不能写其他的来打断
==v-if与template配合使用==
我要完成这么一个界面当点击达到1的时候显示出来
这种做法是不是有点冗余,每个都要去判断一下,所以就有一个标签template,==只能配合v-if使用==,它最大的好处就是不会影响页面标签布局
13.列表渲染
全新==指令语法v-for==
- 遍历数组
首先用了v-for我们有多少数据,就自动会遍历出多少li,然后v-for每个li是必须配置一个:key的动态属性的,我们的遍历可以写多个参数,写多少个的时候前面表示这个对象,后面表示这个对象在数组里面的索引号,而我们的key就可以配置为p.id或者是index这个索引号
-
遍历对象
遍历对象要注意,==遍历的值和我们的数据是反的,前面是我们的数据,后面变成了值,而且遍历对象,key就为这个属性名,==
==v-for除了可以用in 用 of也是一样的效果==
-
遍历字符串
字符串就是可以把每一个字符遍历出来,前面是值,后面是下标
-
遍历指定次数(不常用)
13.1 key作用与原理(面试)
首先要知道我们动态生成的key并不是拿在页面上来呈现的,可以看到最终生成的真实DOM是没有这个属性的,它是用来vue拿来用的
当我们用index作为key的值会出现的问题:
有一个需求当我们点击按钮会在上面新增条数据老六
是不是就出现问题了,分析一下下面这个图就知道问题在哪了
这个就是我们前面所说的vue的一大优点,虚拟DOM加Diff算法,就在这里体现了。首先我们初始化的数据,打开网页vue会先在内存生成虚拟DOM,同时key是我们的index,然后正常将虚拟DOM转为真实DOM,转到页面上来了,我们正常在input框输入内容,这个时候我们去点击新增老六这个按钮,相当于让数据变成了我们的新数据样式,然后又会在内存生成虚拟DOM,这个时候由于是第二次生成了,所以Diff算法就来了,vue会拿我们新的虚拟dom和旧的虚拟dom进行比较,而比较的依据就是==key==,当我们比较第一条数据的时候,key对上了之后,先去比较文本发现文本不一样,那么就不能复用,就会以新的虚拟dom为准,接着回去比较input标签,注意这个时候比较input标签会发现是一样的,为什么,因为都是input标签,都是text格式,我们在里面输入的内容实在真实dom输入的跟虚拟dom没有关系,所以比较出来是一样的,既然一样我就可以去key=0,以前已经生成过真实dom了吧,那我就直接去拿来复用了,所以最终形成的结果就是,新增的文本就上我们旧的input,以此类推,所以就导致了我们最终呈现的效果有问题
这是用index作为key的问题一,还有一个问题就是效率变低了,为什么,因为我们原来本来可以复用的数据,他给我重新生成了真实dom肯定效率低了
当我们用id作为key时
首先比较key=004发现没有,没有那就直接新增,后面的都发现有,而且数据也对的上那就直接复用
开发中如何选择key
- 最好是用每条数据的唯一标识(id、手机号、身份证号、学号等)
- 如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,或者渲染列表仅用于展示(没有新增删除),使用index作为key还是没问题的,顺序添加删除使用它还是可以的
13.2 列表过滤
也就是模糊搜索,先完成能过滤的功能(==注意数组和字符串的方法==)
这么做的话就会损坏原数据,我们的原数据是不能动的,因为要确保,不搜索了还能回去
定义一个新数组,让新数组去接收搜索出来的值,同时原数组也没有改动所以可以一直搜索,不会像原来一样越搜数据越少的情况,同时要把遍历的v-for修改为新数组,但是现在就有一个问题新数组为空,那我们刚开始的时候就看不到列表了
==这里有一个很重要的概念,字符串的indexOf方法对于空字符串的查找是找得到的,意思就是任何字符串.indexOf('')都不会返回-1,都是有值的==
所以只需要开启初始化就监视一下即可,这个时候keyword为空字符串,那么数据里面的每条数据都有空字符串,那就会把全部数据输出出来
==计算属性实现==
计算属性能实现的,watch肯定能实现,watch能实现的只要不涉及到异步任务,计算属性一般也能实现
就这一段代码即可实现,为什么直接就能渲染,以为watch默认是要先搜索再去执行handler,这里一来就会执行,一来就是空字符串,为什么不用自定义一个新的数组,因为计算属性就相当于一个新的数组了
13.3 列表排序
关键点在于利用计算属性里面的任何一个依赖数据发生变动都会重新运算计算节点
- 数组排序参数是谁
- 排序和过滤是密不可分的,我还需要在过滤出来的基础上排序,不是一点排序就回到了原数据列表
- 之所以点击原顺序可以回去,关键点就在于计算属性里面每一个依赖数据发生变动,都会重新计算重新渲染,所以一点击原顺序sortType就变动了,重新根据关键字去过滤数组,得出来的满足不了排序的if就直接输出arr了
13.4 vue监测数据改变的原理
先看到一个数据更新时的问题
点击后没反应,vue管理工具也没有数据更新
13.4.1 vue对象监测原理
先看一张图,这里有点绕,有点难以理解,我在那里捋了四五十分钟接近一个小时,vue的一个对象检测原理就是,我们说过我们的data数据最终会呈现在vm实例的_data上,vue对于对象数据的检测就是定义了一个构造函数,这个构造函数会把我们的数据的属性名全部拿过来然后做一个遍历,在遍历里面,是最重要的逻辑,用对象定义属性的方法,**对象为this,这里的this指的就是这个构造函数的实例,同时给他上面定义属性,当访问到这个构造函数实例的这个属性的时候就把obj对应的属性的值给到他(也就是data上面对应的值),其实这里就是做了一个数据代理,我们读取和写入虽然是在这个实例上面我就说_data上面吧,插值语法之所以能够直接写name是因为后面又给vm做了一个数据代理,其实vue的读写都是基于这个_data的,读通过_data来读,修改虽然是修改的_data但是会把val给到data数据本身。总结就是:vue对于对象数据的监测就是通过一个构造函数,目的是加工data来给_data赋值,真正的逻辑在于里面的defineProperty这个方法,真正的监测原理就是通过这里面的getter和setter来读和写我们的data,然后再setter作进一步的逻辑,既然是setter那就是值变化了,就回去重新解析模板,diff比较虚拟DOM看哪些能复用,再把我们修改的值渲染上去 **
一句话总结:==vue监测原理就靠这个setter==
13.4.2 vue.set()的使用
这个案例首先要注意一点,在vue里面如果==值为undefined,并不会报错,只是没有文字显示出来而已,这里的age没有赋值,所以undefined,在页面上并不会报错,只是一片空白没有数据==
一个需求,我如果想通过将它直接赋值让页面出现他的性别:
可以看到页面并没有显示,而且我们的数据也有,但是是写死的并不是响应式的,我们之前研究过vue的监测原理靠的就是那个setter,这里没有给她做setter所以自然也不会映射到页面上来
-
==Vue.set()==vue提供的的api,可以让我们在后面添加的数据,也能够完成响应式数据,也有属于自己的getter和setter
三个参数:第一个参数往哪里添加这个属性,第二个参数属性名,第三个参数值
-
第二种写法:==vm.$set(参数跟上面一样三个)==
-
==局限性==
该方法不能直接给data和vm添加属性
13.4.3 vue数组监测原理
vue里面不能直接以数组索引去修改值
可以看到我们数组的值都变了,但是vue监测不到,所以页面不会变,==不能直接通过数组索引去修改值==
在vue里面数组能被监测到的只能是可以修改数组本身的七种方法
所以现在就可以对我们13.4那里的案例做出回应了
问题:为什么vue知道我们使用了这些方法
因为vue对这些方法做出了包装,不是Array原来的那七个方法了,实现逻辑肯定还是原来那种只是添加了一些逻辑(方法完成后会去重新解析模板,重新diff虚拟DOM)
==让数组被监测到方法二==:
Vue.set这个api也可以
13.4.4 总结vue数据监测
看下总结案例(如何实现性别在未添加之前为隐藏、修改数组里面的对象不需要数组的方法)
-
vue会监视data中所有层次的数据
-
对象中通过setter实现监视,且要在定义data时就传入数据,如果是在之后添加的数据,需要Vue.set或者是vm.$set来实现监视
-
数组中的数据通过包裹数组的七种方法实现
-
vue数组中修改元素大多数要通过七种方法或者set两个api
七种方法为变更方法,但是也有非变更方法如(==filter、concat、slice这些会返回新数组的方法,可以让返回的新数组替换掉旧数组,同样可以受到监视,页面同样会被更改==)
-
最后注意一下set两个api不能给vm和data跟数据对象添加属性
-
==数据劫持==:就是前面说的对象监测原理,把一个完好的data数据变成了setter的方式,我如果要修改student的值,瞬间就被setter劫持到了,去做了其他解析模板等操作,这就叫数据劫持