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); } } } };
相关文章推荐
- Android -- 带你从源码角度领悟Dagger2入门到放弃(一)
- Android -- 带你从源码角度领悟Dagger2入门到放弃(三)
- Vue.js2.0从入门到放弃---入门实例(三)
- Java从入门到放弃(五)集合框架之ArrayList源码(1)
- Vue.js 2.0从入门到放弃---入门实例(二)
- vue从入门到放弃 --- 真的是入门
- vue.js从入门到放弃2--官方文档阅读笔记
- vue.js从入门到放弃1--环境安装,包括linux和window
- Java从入门到放弃(六)集合框架之ArrayList源码(2)
- vue从入门到放弃--- 滚动加载
- Android -- 带你从源码角度领悟Dagger2入门到放弃(二)
- 1、VUE入门到放弃第一步安装
- vue从入门到放弃---Vuex vueBus
- vue从入门到放弃--- 父子组件通信
- Vue.js2.0从入门到放弃---入门实例(三)
- vue从入门到放弃--- 时间戳 跨域
- Vue.js2.0从入门到放弃---入门实例
- Vue.js2.0从入门到放弃---入门实例(一)
- vuex - modal的实现 =>从入门到放弃(一)
- vue从入门到放弃---axios 和 rap模拟数据