1.解析模板成render函数
-
<div id="app"> <p>{{price}}</p> </div> // render函数 with(this){ // this即vm return _c( 'div', { attrs: {"id": "app"} }, [ _c('p', [_v(_s(price))]) ] ) }
-
模板中的所有信息都被render函数包含
-
模板中用到的data中的属性,都变成了js变量
-
模板中的v-model,v-for,v-on都变成了js逻辑
-
render函数返回vnode
2.响应式开始监听
-
Object.defineProperty监听
当你把一个普通的JavaScript对象传给Vue实例的data选项,vue将遍历此对象所有的属性,并使用Object.defineProperty把这些属性全部转为getter/setter。
这些getter/setter对用户来说是不可见的,但是在内部它们让vue追踪依赖,在属性被访问和修改时通知变化。
// 模拟实现vue监听data属性 var obj = {}; var data = { price: 100, name: 'zhangsan' }; var key, value; for (key in data) { // 命中闭包,新建一个函数,保证key的独立作用域 (function (key) { Object.defineProperty(obj, key, { get: function() { console.log('get', key); return data[key]; }, set: function(newVal) { console.log('set', newVal); data[key] = newVal; } }) })(key) }
-
将data的属性代理到vm上
3.首次渲染,显示页面,且绑定页面
-
初次渲染,执行updateComponent,执行vm._render()
vm._update(vnode) { const prevVnode = vm._vnode; vm._vnode = vnode; if (!prevVnode) { vm.$el = vm._patch_(vm.$el, vnode); } else { vm.$el = vm._patch_(prevVnode, vnode); } } function updateComponent() { vm._update(vm._render()); }
-
执行render函数,会访问到vm.list和vm.title
-
会被响应式的get方法监听到
为什么要监听get,直接监听set不行吗?
data中有很多属性,有些被用到,有些可能不被用到,被用到的会走到get,不被用到的不会走到get,
未走到get的属性,set的时候我们也无须关心,这样能避免不必要的重复渲染。
-
执行updateComponent,会走到vdom的patch方法
-
patch将vnode渲染成DOM,初次渲染完成
4.data属性变化,触发rerender
- 修改属性被响应式的set监听到
- set中执行updateComponent
- updateComponent重新执行vm._render()
- 生成的vnode和prevVnode,通过patch进行对比
- 渲染到html中