prefacio
Al aprender a entender el Everest principio de la fuente Vue supuesto Responsive.
principio de respuesta
1. El punto central: Object.defineProperty
2. Por defecto Vue durante la inicialización de datos utilizando los datos de atributos se Object.defineProperty redefinir todos los atributos, cuando la página correspondiente al atributo adquirida. Recopilada será dependiente (colector de corriente montaje Vigía) Si la propiedad notificará a la dependencia operación de actualización cambiado.
Lo que es dependiente de la colección?
Por Object.defineProperty
el tiempo para re-definir los atributos de datos, interceptar, entonces la representación real; que antes de la serie de proceso de representación real depende de la colección lógica 上边有说,会在依赖收集的时候为每一个属性创建一个watcher,如果属性发生变化,则通知对应的 watcher 更新视图
.
Para mirar la fuente
1, el primer constructor inicializa miradas, src/core/instance/index.js
porque compartimos los principios fundamentales de los datos sensibles, es decir, cómo se inicializan los datos Vue render y acumulación de escucha, sobre todo para ver el módulo stateMixin
2, en el stateMixin
módulo, miramos directamente en la initData
función
function initData (vm: Component) { // 初始化data
let data = vm.$options.data // 获取到用户传入的data数据
data = vm._data = typeof data === 'function' // 模板语法与标准语法区分获取data数据
? getData(data, vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) {
warn(
`Method "${key}" has already been defined as a data property.`,
vm
)
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' && warn(
`The data property "${key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(key)) {
proxy(vm, `_data`, key) // es6 proxy 代理
}
}
/*
中间我就跳过了,看意思是非生产环境下,对 props , methods 的一些定义,声明做的判断,不允许重复声明
另外就是添加了 proxy , es6 新增代理属性 , 包含所有 Object.defineProperty 的功能, 重要的一点是解决 了不能对象监听的问题等。
*/
// observe data
observe(data, true /* asRootData */) // 重点在这儿,为每一个data属性创建一个watcher
}
重点 : observe(data, true /* asRootData */) // 重点在这儿,为每一个data属性创建一个wathcer
Luego fuimos a la observer 类
3, src/core/observer/index.js
línea 37
está por debajo de la clase de observador, en concreto que se haga, mirada al código
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor(value: any) { // 构造函数
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
/*
观测呢分为两种,一种是数组,一种是对象
*/
if (Array.isArray(value)) { // 是数组
if (hasProto) {
protoAugment(value, arrayMethods) // 改写数组原型方法
} else {
copyAugment(value, arrayMethods, arrayKeys) // 复制数组已有方法
}
this.observeArray(value) // 深度观察数组中的每一项 , 下边方法
} else {
this.walk(value) // 重新定义对象类型数据 下边方法
}
}
/**
* Walk through all properties and convert them into
* getter/setters. This method should only be called when
* value type is Object.
*/
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) { // 遍历对象
defineReactive(obj, keys[i]); // 定义响应式数据,这里可以看到 defineReactive 方法
}
}
/**
* Observe a list of Array items.
*/
observeArray (items: Array<any>) { // 遍历数组
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i]) // 观测数组中的每一项
}
}
}
Por el código de arriba, vemos la cosa más importante que hacer, es distinguir entre las matrices y objetos, y los datos y objetos de recorrido, crear observador watcher
=>defineReactive 方法
Llegará en la parte superior cuando se trata de la matriz observeArray
método, que consiste en recorrer la llamada observer
, algunos tipos de datos y determinar si el monitor no había estado escuchando a la parte posterior devolución de llamada marcha para crear una observación.
src/core/observer/index.js
113 line
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
/*
不是对象不进行观测,如:不管是模板语法还是标准语法data均是一个对象
data () { 模板语法返回一个对象
return {}
}
new Vue ({ 标准语法 data 也是一个对象
data:{}
})
*/
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { // 已经被监听的,不会重复监听
ob = value.__b__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) && // 是否可扩展
!value._isVue
) {
ob = new Observer(value) //重点,重点,重点, 回调回去,观测对象类型
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}
Si no es una matriz, y luego ir directamente al defineReactive
Método de
src/core/observer/index.js
148 líneas defineReactive 响应式数据绑定关键方法
donde utilizamos la palabra que es la aplicación Object.defineProperty (); todos los datos de inicialización vendrán aquí.
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
const dep = new Dep()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val) // 是数组则递归观测
Object.defineProperty(obj, key, { // 重点
enumerable: true,
configurable: true,
get: function reactiveGetter () { // 数据的取值
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend() // 收集依赖 watcher
if (childOb) {
childOb.dep.depend() // 收集依赖
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) { // 数据的设置值
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify() // 触发数据对应的依赖进行更新 , 重点,重点,往下看
}
})
}
Todas las colecciones de observador Dep, que es una colección de wathcer, al crear los datos observados se crea para cada atributo del watcher
observador ( Object.defineProperty方法的 get 里边
), entonces la actualización de los datos de disparo set
llamadas a métodos dep.notify()
, vistazo al código
src/core/observer/dep.js
, línea 13, Dep gusta ver a la sierra constructor, complemento vigilante, vigilante de eliminación y así sucesivamente, entonces creo que el punto de vista método de actualizaciónnotify()
export default class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>;
constructor () {
this.id = uid++
this.subs = []
}
addSub (sub: Watcher) {
this.subs.push(sub)
}
removeSub (sub: Watcher) {
remove(this.subs, sub)
}
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify () { // 通知存储的依赖更新
// stabilize the subscriber list first
const subs = this.subs.slice()
if (process.env.NODE_ENV !== 'production' && !config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort((a, b) => a.id - b.id)
}
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update() // 依赖中对应修改属性的update方法
}
}
}
update ()
Métodos src/core/observer/wachter.js
166 filas, de hecho, esta es la definición de wachter
la clase observador, dentro de varios de operación wachter
métodos del observador, tales como: añadir, modificar, eliminar similares.
resumen
Pues bien, el análisis aquí, de hecho, ha sido muy claro para los datos sensibles principio, el proceso global es: