从vue源码看Vue.set()和this.$set()

 

前言

最近死磕了一段时间vue源码,想想觉得还是要输出点东西,我们先来从Vue提供的Vue.set()和this.$set()这两个api看看它内部是怎么实现的。

Vue.set()和this.$set()应用的场景

平时做项目的时候难免不会对数组或者对象进行这样的骚操作操作,结果发现,咦~~,他喵的,怎么页面没有重新渲染。

const vueInstance = new Vue({   data: {     arr: [1, 2],     obj1: {         a: 3     }   } });  vueInstance.$data.arr[0] = 3;  // 这种骚操作页面不会重新渲染 vueInstance.$data.obj1.b = 3;  // 这种骚操作页面不会重新渲染

查了一下官方文档,发现人家早就说过这种情况

Vue.set()向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 (比如 this.myObject.newProperty = 'hi')

所以按照官网的写法,我们应该使用下面这种写法:

Vue.set(vueInstance.$data.arr, 0, 3);  // 这样操作数组可以让页面重新渲染 vueInstance.$set(vueInstance.$data.arr, 0, 3); // 这样操作数组也可以让页面重新渲染 Vue.set(vueInstance.$data.obj1, b, 3);  // 这样操作对象可以让页面重新渲染 vueInstance.$set(vueInstance.$data.obj1, b, 3); // 这样操作对象也可以让页面重新渲染

Vue.set()和this.$set()实现原理

是时候看一波这两个api的源码了,我们先来看看Vue.set()的源码:

import { set } from '../observer/index'  ... Vue.set = set ...

再来看看this.$set()的源码:

import { set } from '../observer/index'  ... Vue.prototype.$set = set ...

结果我们发现Vue.set()和this.$set()这两个api的实现原理基本一模一样,都是使用了set函数。set函数是从 ../observer/index 文件中导出的,区别在于Vue.set()是将set函数绑定在Vue构造函数上,this.$set()是将set函数绑定在Vue原型上。

接下来我们根据 ../observer/index 中找出set函数:

function set (target: Array<any> | Object, key: any, val: any): any {   if (process.env.NODE_ENV !== 'production' &&     (isUndef(target) || isPrimitive(target))   ) {     warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}`)   }   if (Array.isArray(target) && isValidArrayIndex(key)) {     target.length = Math.max(target.length, key)     target.splice(key, 1, val)     return val   }   if (key in target && !(key in Object.prototype)) {     target[key] = val     return val   }   const ob = (target: any).__ob__   if (target._isVue || (ob && ob.vmCount)) {     process.env.NODE_ENV !== 'production' && warn(       
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信