vue中$set的实现方法
在日常开发中,$set
的也是一个非常实用的API,因为Vue2实现响应式的核心是利用了ES5的Object.defineProperty
,当我们通过直接修改数组下标更改数组或者给对象添加新的属性,这个时候Object.defineproperty是监听不到数据的变化的,这时候大家就会用上$set
,让修改的操作也实现响应,我们知其然更要知其所以然,接下来看一下Vue中的$set是如何实现的。
应用场景
let dataArr = ["item1"];
let dataObject = {
name: "ccs"
};
dataArr[2] = "item2";
dataObject.age = 22;
响应失败,页面没有显示更新新增的数据
this.$set(this.dataArr,2,'item2')
this.$set(this.dataObject,'age',22)
响应成功,页面显示更新新增的数据
set实现
接下来我们看一下$set在Vue中的定义
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(
"Avoid adding reactive properties to a Vue instance or its root $data " +
"at runtime - declare it upfront in the data option."
);
return val;
}
if (!ob) {
target[key] = val;
return val;
}
defineReactive(ob.value, key, val);
ob.dep.notify();
return val;
}
在源码中首先判断set的目标是否是undefined
和基本类型
如果是undefined
或基本类型
就报错,
因为用户不应该往undefined和基本类型中set东西,
然后又判断了目标是否是数组与key是不是合法的index,合法的index是指值为大于等于0的整数,
如果两个条件都成立就对目标数组调用splice方法插入或者修改数组
,
这里的splice
不是普通的splice
,是王维诗里的splice,是被vue代理重写过的splice
数组实现响应
$set实现数组修改响应的方式是代理重写的数组的一部分方法,接下来我们看一下具体实现
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
function def(obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
});
}
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
ob.dep.notify()
return result
})
})
vue中代理重写的不只是splice
,有push、pop、shift、unshift、splice、sort、reverse
这七个方法, 首先执行了const result = original.apply(this, args)
执行原本数组的方法并获取它的值,接下来判断如果是往数组中添加值就将新添加的值也实现响应式
,
最后一步拿到这个数组的_ob_对象
对_ob_
里的dep进行派发更新。
对象实现响应
$set
中下半部分的逻辑就是用来处理对象响应的,我们接着往下看
if (key in target && !(key in Object.prototype)) {
target[key] = val;
return val;
}
const ob = (target: any).__ob__;
if (!ob) {
target[key] = val;
return val;
}
defineReactive(ob.value, key, val);
ob.dep.notify();
return val;
首先判断了属性如果在目标对象中直接return结束逻辑,
因为vue只有添加目标对象中原本没有的属性时才会失去响应,例如 let obj={} obj.name='ccs'
,
vue在初始化的时候会将data里的所有属性都变成响应式,如果的值是对象或者数组则会new一个Observer
实例储存在__ob__,
拿到这个对象的_ob_进行判断,如果不存在就说明是未经过vue初始化的普通对象而不是响应式对象否则就手动通过defineReactive
为属性添加get方法与set方法实现响应,
然后手动调用dep
里的notify()
发布更新。
总结
vue中$set方法对数组和对象的处理本质上的一样的,对新增的值添加响应然后手动触发派发更新。
相关文章
- vue.js 计算属性与$watch的区别?
- How to Watch Deep Data Structures in Vue (Arrays and Objects)
- 【Vue】Vue-cli中组件之间的嵌套
- 【Vue】单文件的组件(.vue)代码实例
- Vue - 完美解决小数的四则运算(加减乘除)导致精度丢失问题,提供详细计算示例代码vue数据计算丢失精度
- vue的基本使用
- 揭密 Vue 的双向绑定
- vue 3.0 项目搭建移动端 (二) Vue-router: router-link 与 router-view keep-alive
- 用【mysql,vue,node】制作一个前后端分离小项目
- vue---向后台添加数据--删除数据--事件方法传参---在单页面配置url请求地址--暂时没有用到webpack
- vue基础---条件渲染
- 【Vue】vue基础语法——computed计算、watch监听、class和style,最后回顾JavaScript里面的常用方法(vue学习day03)
- Vue报错笔记(1)vue.esm.js?efeb:628 [Vue warn]: Property or method “handleClick“ is not defined on the...
- Vue+Echarts监控大屏实例十:智慧园区监控模板实例下
- vue学习笔记十:Vue中引入jquery
- vue文档摘录九:Vue Router
- Vue富文本编辑器的使用vue-quill-deitor
- vue.config.js配置本地测试开发环境变量及获取env中设置的变量
- vue问题解决:Vue packages version mismatch 版本始终不对的解决
- vue Inline JavaScript is not enabled. Is it set in your options?
- 04-vue-cli-启动配置和静态资源配置
- Django+Vue项目学习第九篇:vue项目部署到服务器
- Vue学习第13天——vue中使用自定义插件
- 【VUE】vue配置Gzip压缩
- vue 侦听器watch 之 深度监听 deep
- Vue.js 模板语法
- ejs结合vue实现SSR ,express+ejs+vue = 服务器端渲染 ?Vue-SSR的奇思妙想