Vue2中检测数组变化的限制和解决方法
vue2用下标设置数组没效果
- arr = [1,2] arr[0] = 0,页面上显示的arr并没有修改(如果对应下标是原始值;若是引用值)
- 解决1:Vue.Set
- 解决2:arr.splice (Vue会劫持splice方法) Vue2对对象是循环defineProperty(递归、深度)set时通知dep.notify();对于数组则是重写数组7个方法(push、pop、shift、unshift、splice、sort、reverse)时通知dep.notify();
<div id="app">{{ arr[0].a }}{{ arr[1].a }}</div><script>var app = new Vue({el: '#app',data: {arr: [{ a: 2 }, { a: 600 }]},mounted() {setTimeout(() => {this.arr[1] = [{ a: 400 }] // 这样看不到400this.arr[1].a = 800 // 这样能看到变成800}, 3000)}})</script>
vue2设置数组长度没效果
- arr.length-- ,页面上显示的arr并没有修改
- 解决1:Vue.Delete
- 解决2:arr.splice
Vue nextTick
Vue渲染是异步渲染,添加元素时不会马上渲染,而是到下一个tick才渲染。 nextTick的回调会在dom异步渲染完毕后执行(vue是组件级的,若一有数据就更新性能肯定不好)。并且vue是批量做渲染的 在外部添加3个 在nextTick里获取个数 只会打印一次
nextTick的实现
- 如果支持promise,将回调放在then方法里
- 若不,若支持MutationObserver,就xxx也是异步执行的
- 若不,若支持setImmediate
- 再不,setTimeout
computed method watch区别
- method用在视图上,每次都去执行,开销大,而computed是具备缓存的,若依赖的属性无变化,不计算
Vue Plugin
- 全局方法 Vue.xx访问
- 全局指令
- mixin
- 原型上绑定方法 Vue实例this访问
- 导出插件,在main.js里use
Vue组件data返回函数
- Vue组件可能存在多个实例,如果使用对象形式定义data,会导致他们共用一个data对象,那么状态变更将会影响所有组件实例;采用函数形式定义,在initData时会将其作为工厂函数返回全新的data对象,有效规避多实例之间状态污染问题。而Vue根实例只能有一个,不会有次问题。
加key 高效更新dom
- key的作用主要是为了高效更新虚拟DOM,其原理是vue在patch(打补丁)过程中通过key可以精准判断两个节点是都是同一个,从而避免频繁更新不同元素,是patch过程更高效,减少dom操作量,提高性能
- 若不设置key还可能在列表更新时引发一些隐蔽的bug
- vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,目的是为了让vue可以区分他们,否则vue只会替换其内部属性而不会触发过渡效果
- 不使用key,更新时不知道每个元素的位置,所以在A更新A,B更新B,C更新为F,以此类推,实际更新了3次,从F开始FCD + 创建插入E (源码中,每次循环认为这5对是sameVnode,只能每次都去更新。而加了key能精准判断是否是相同节点)
- 使用key,只做了一次创建F并插入到C前面的操作(比较时,比较首位元素是否相同)
源码
-
没有设置key时,key的值是undefined,两个未设置key的标签值被判断为相同
-
diff算法不是最优,增加key优化了diff,降低复杂度
-
加key
index作为key
- 在数据会增减时可能会产生问题,在头部插入,在中间删除(数量变化,index是在变的)
- random作为key,随机数还是有可能是一样的
vue-router的原理
- vue-router通过hash与History interface两种方式实现前端路由,更新视图但不重新请求页面”是前端路由原理的核心
- history模式则会将URL修改得就和正常请求后端的URL一样,如后端没有配置对应/user/id的路由处理,则会返回404错误
- 它提供mode参数
- hash带# new HashHistory 是基于location.hash来实现的。Location.hash的值就是URL中#后面的内容。当hash改变时,页面不会因此刷新,浏览器也不会请求服务器。
- history更像url new HTML5History
update beforeUpdate
总结:
- 不能笼统地说能修改或不能修改数据
- 修改的数据未渲染到视图不会触发这2个钩子
- this.msg = this.msg + 1是有可能引起死循环的操作
- beforeUpdate修改视图数据不会再次触发beforeUpdate 即使++也没关系
- updated修改视图数据为常量,会再触发一轮beforeUpdate → update;因此,若在此生命周期++会死循环