您的位置:首页 > 产品设计 > UI/UE

Vue源码 --- 从入门到放弃

2017-01-13 15:09 337 查看

Vue 源码分析

本文是根据源码 Vue.js v2.0.2 进行分析,内容主要针对options中最常见数据项props、data、computed、methods、watch的工作原理及流程进行详细说明。描述上,重于关键点的罗列,部分未能详细阐述。建议与这篇文章对比学习。

function initState (vm) {
vm._watchers = [];
initProps(vm);
initData(vm);
initComputed(vm);
initMethods(vm);
initWatch(vm);
}


initState

new Vue() 时,调用 _init 初始化,=> initState

_watchers

在每个vue实例上定义一个_watchers空数组

在该实例的数据属性发生 new Watcher() 时,将当前watcher放入数组中

当该实例销毁或主动调用unwatch时,将当前watcher从数组中移除

initProps

单独处理Boolean类型的值 (validateProp) ,三种写法:

<x-component :xxx="true"></x-component>


<x-component xxx></x-component>


<x-component xxx="xxx"></x-component>


校验prop值的合法性 assertProp 方法

核心方法 defineReactive$$1 来设置属性的getter和setter,但当props属性被setter时,触发回调来warn不可修改

initData

vm._data = data
将当前实例属性$options的data赋值给实例的_data属性

判断data中是否有与props中相同的属性,warning

proxy 代理处理,将data中的每个属性getter和setter到vm实例上,getter和setter直接转向了_data的getter和setter方法

观察_data到设置getter和setter,observe(data) => new Observe() => observe.walk => defineReactive$$1

插入Watcher 先看下方脚注

initComputed

initComputed 其实也是将computed中的每个属性通过
Object.defineProperty
定义到vm上,只不过每个属性的getter是在computed中自定义的,而默认setter为空。当属性为对象时,可显示声明set和get方法。

isFunction => 设置getter和setter,setter默认为空。getter通过new Watcher过度一层到自定义的get方法

isObject => 设置getter和setter,setter直接bind到自定义set方法,getter通过new Watcher过度一层到自定义的get方法

initMethods

将methods中的方法一一绑定到vm实例上

initWatch

createWatcher => 判断handler类型

isObject =>
handler = handler.handler
其他属性:deep, immediate, sync, lazy

deep: true
递归watch

immediate: true
在创建watcher时就执行一次handler方法

sync: true
同步,直接执行watcher.run,否则要排队到queue数组中,等到nextTick异步到这里再依次执行

lazy: true
在创建watcher时是否需要立即计算当前watcher的value值,通过computed属性创建的watcher默认
lazy=true
不需要计算

isString =>
handler = vm[method]
handler在vm的methods中查找对应的方法

isFunction =>
handler = handler


vm.$watch => 执行实例的
$watch
方法,创建watcher,同时在这里判断immediate来决定是否执行一次handler

渲染流程

在页面挂载前所new的Watcher会被立即调用this.get(),来回调vm.update更新$el。而在更新前会先执行_render创建vnode。此时就会真正执行页面生成的render方法,获取页面所需的值,从而进入定义好的getter方法。



更新流程

当data中的属性进入到setter阶段,即进入_data属性的set方法时,会执行依赖修改
dep.notify()
。依赖修改的最终目的还是通过执行watcher.run来获取属性值,并回调handler,最终更新到vm的$el上。



流程:

改变属性值进入 set

依赖修改 dep.notify

watcher更新 watcher.update

直接执行run或者排队进入queue后异步nextTick执行flushSchedulerQueue

根据watcher.id排序queue后,执行watcher.run

nextTick: 异步兼容

Promise

MutationObserver

setTimeout

脚注

Watcher

var Watcher = function Watcher (
vm,
expOrFn,
cb,
options
) {
if ( options === void 0 ) options = {};

this.vm = vm;
vm._watchers.push(this);
// options
this.deep = !!options.deep;
this.user = !!options.user;
this.lazy = !!options.lazy;
this.sync = !!options.sync;
this.expression = expOrFn.toString();
this.cb = cb;
this.id = ++uid$1; // uid for batching
this.active = true;
this.dirty = this.lazy; // for lazy watchers
this.deps = [];
this.newDeps = [];
this.depIds = new _Set();
this.newDepIds = new _Set();
// parse expression for getter
if (typeof expOrFn === 'function') {
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
if (!this.getter) {
this.getter = function () {};
"development" !== 'production' && warn(
"Failed watching path: \"" + expOrFn + "\" " +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
);
}
}
this.value = this.lazy
? undefined
: this.get();
};


Watcher.prototype.run = function run () {
if (this.active) {
var value = this.get();
if (
value !== this.value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
isObject(value) ||
this.deep
) {
// set new value
var oldValue = this.value;
this.value = value;
if (this.user) {
try {
this.cb.call(this.vm, value, oldValue);
} catch (e) {
"development" !== 'production' && warn(
("Error in watcher \"" + (this.expression) + "\""),
this.vm
);
/* istanbul ignore else */
if (config.errorHandler) {
config.errorHandler.call(null, e, this.vm);
} else {
throw e
}
}
} else {
this.cb.call(this.vm, value, oldValue);
}
}
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  JavaScript Vue 源码