在vue中,只有预先在data中定义的属性才能是响应式的属性。如果是新增或者删除,数据改变但是页面却没有改变。
所以在vue中重写了数组中涉及数组项的新增、删除或者位置变化的方法。包括七种,'push','pop','shift','unshift','splice','sort','reverse'。
源码的位置就在src/core/observer/array.js中。下面我们来看一下。
import { def } from '../util/index'
const arrayProto = Array.prototype
export const arrayMethods = Object.create(arrayProto)
这里利用Object.creat方法创建一个新对象,而新对象的原型是数组的原型。相当于copy了一份原生数组对象的原型。目的是防止污染原生数组对象的原型。
先来看一个工具函数。作用是定义对象的属性。下面要用到。
/**
* Define a property.
*/
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
继续回到array.js中。
[
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
.forEach(function (method) {
// cache original method
// 将数组的原生方法缓存起来,后面要调用
const original = arrayProto[method]
// 修改新数组对象的属性,这里的属性是数组方法。
def(arrayMethods, method, function mutator () {
// avoid leaking arguments:
//这里定义的属性的值是一个mutator函数。
//执行数组方法后的value值用函数来返回,返回之前添加observe响应
// 避免泄露参数 参数是执行数组方法时括号中的参数
// http://jsperf.com/closure-with-arguments
let i = arguments.length
const args = new Array(i)
while (i--) {
args[i] = arguments[i]
}
//调用原生的数组方法
const result = original.apply(this, args)
//执行数组方法的当前数组的属性有__ob__属性,因为当前数组初始化时已经变成响应式属性。
const ob = this.__ob__
//数组新插入的元素需要重新进行observe才能响应式
let inserted
switch (method) {
case 'push':
inserted = args
break
case 'unshift':
inserted = args
break
case 'splice':
////splice 方法第三个参数开始才是新增的元素
inserted = args.slice(2)
break
}
if (inserted) ob.observeArray(inserted)
// notify change
//dep通知所有注册的观察者进行响应式处理
ob.dep.notify()
//返回原生的数组处理结果
return result
})
})
标签: Vue
还木有评论哦,快来抢沙发吧~