就目前所了解的状况,key的做用有如下这些。html
场景一大同小异司空见惯,场景二是下面这样的:vue
<div :key="rerender"> <span>Hello Vue.js !</span> <complexComponent :propObj="propObj" :propArr="propArr" ></complexComponent> </div> refresh(){ this.rerender = + new Date(); }
那么vue中key的相关知识点究竟是怎样的呢?node
<ul> <li v-for="item in items" :key="item.id">...</li> </ul>
<transition> <span :key="text">{{ text }}</span> </transition>
text发生变化时,<span>
会被replaced,而不会patched,所以transition会被触发。
个人理解:
text变化时,span的key发生了变化,也就是说曾经拥有了旧key的span再也不出现了,当拥有新值的text做为key时,拥有了新key的span出现了,那么旧key span会被移除,旧transition也会移除,新key span触发渲染,新transition触发。git
结合官方API的知识点,如今再来回顾文章开头提出的场景。github
答案:算法
<div :key="rerender"> <span>Hello Vue.js !</span> <complexComponent :propObj="propObj" :propArr="propArr" ></complexComponent> </div> refresh(){ this.rerender = + new Date(); }
答案:api
思考:数组
因为Vue.js的obj和arr存在没法检测到数据变化的状况,obj是属性的新增和删除(缘由是新增和删除都没有触发setter,watcher未告诉外界更新),arr则是数组内元素从新赋值或者修改length属性(缘由是没有使用改变数组自己的方法,没有触发数组原型链拦截器,watcher未告诉外界更新)。
因此!经过赋予新key的方式,移除旧key div,渲染新key div,propObj和propArr在complexComponent组件内会从新触发一次生命周期,作一次从新渲染。此时父组件的propObj和propArr js变量其实已经获取到新值了,只是没有触发DOM也好,VNode也好的从新渲染。须要经过刷新key去force update,说到forceUpdate,能够经过$forceUpdate()去手动强制更新DOM。ide
场景:父组件修改传递给子组件的数据,数组数据的更新没有按照this.$set去更新。该怎么办?ui
this.productImages.forEach((product) => { if (product.productId in this.productsState) { product.status = this.productsState[product.productId]; } });
不使用this.$set去赋值数据的不能rerender的缘由是什么?
在Vue.js中,对Array的变化侦测是经过拦截原型的方式实现的。也就经过对push,pop,shift,unshift,splice,sort,reverse,fill,copyWithin去改变数组自身内容的方法作拦截,从而响应。而product.status = this.productsState[product.productId];
没有触发任何改变数组自身的被监听的方法,所以不会rerender。
加在this.productImages的父元素上就好。
若不涉及数据传递,也能够直接加在须要更新的element上。
如今是粗暴的+new Date()时间戳作key值的。
也能够用双向绑定的值做为key值,保证新旧key值不一样就行。
vue.js的虚拟DOM算法,在更新vNode时,须要从旧vNode列表中查找与新vNode节点相同的vNode进行更新,若是这个过程设置了属性key,过程就会快不少。
其余具体见上文。
只能在父组件调用这个方法,手动通知vue实例从新渲染。
// $forceUpdate源码 Vue.prototype.$forceUpdate = function () { const vm: Component = this if (vm._watcher) { vm._watcher.update() } } // update源码 /** * Subscriber interface. * Will be called when a dependency changes. */ update () { /* istanbul ignore else */ if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } }
product.status = this.productsState[product.productId];
之后,其实此时dep已经发生变化了,可是Vue.js数组响应式的实现因为是拦截原型链方法的方式,没有检测到这个变化,因此不会自动rerender,没有触发update。所以咱们经过$forceUpdate的方式,调用包含dep的watcher上的update方法,从而作到rerender。
不能够。
由于dep是父组件的watcher和dep,并非子组件,是父组件的this.productImages没有被检测到并实时更新,并非子组件的问题。
https://vuejs.org/v2/api/#key
https://vuejs.org/v2/api/#vm-...
https://vuejs.org/v2/guide/co...