模版以下vue
<div> <h1 style="color:red">我是選項模板3</h1> <p>{{number}}</p> <p>{{message}}</p> <div> <div> 1 <div>11</div> <div>12</div> </div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> </div> </div>
options.render爲node
function anonymous( ) { with(this){ return _c( 'div', [_c('h1',{staticStyle:{"color":"red"}},[_v("我是選項模板3")]) ,_v(" "),_c('p',[_v(_s(number))]), _v(" "), _c('p',[_v(_s(message))]), _v(" "), _m(0)] ) } }
對應緩存
<h1 style="color:red">我是選項模板3</h1> <p>{{number}}</p> <p>{{message}}</p>
options.staticRenderFns爲 [0]dom
function anonymous() { with(this){ return _c('div',[ _c('div',[_v("\n 1\n "), _c('div',[_v("11")]),_v(" "), _c('div',[_v("12")]) ]),_v(" "), _c('div',[_v("2")]),_v(" "), _c('div',[_v("3")]),_v(" "), _c('div',[_v("4")]),_v(" "), _c('div',[_v("5")]) ]) } }
對應的template爲async
<div> <div> 1 <div>11</div> <div>12</div> </div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> </div>
render-helpers 下 index.js函數
export function installRenderHelpers (target) { target._o = markOnce target._n = toNumber target._s = toString target._l = renderList target._t = renderSlot target._q = looseEqual target._i = looseIndexOf target._m = renderStatic target._f = resolveFilter target._k = checkKeyCodes target._b = bindObjectProps target._v = createTextVNode target._e = createEmptyVNode target._u = resolveScopedSlots target._g = bindObjectListeners }
render.jsthis
function renderMixin (Vue) { //把_v,_m等方法掛載到vue原型上 installRenderHelpers(Vue.prototype) } function initRender (vm) { vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false) }
這樣this._c就是執行createElement
this._m就是執行renderStatic
_v就是執行createTextVNodespa
在vdom下create-element.jsprototype
tag // 標籤 data // 關於這個節點的data值,包括attrs,style,hook等 children // 子vdom節點 context // vue實例對象 function _createElement(context,tag,data,children,normalizationType) { vnode = new VNode( tag, data, children, undefined, undefined, context ) return vnode }
建立vdom對象代理
vnode
class VNode { constructor ( tag, data, // 關於這個節點的data值,包括attrs,style,hook等 children, // 子vdom節點 text, // 文本內容 elm, // 真實的dom節點 context, // 建立這個vdom的上下文 componentOptions, asyncFactory ) { this.tag = tag this.data = data this.children = children this.text = text this.elm = elm this.ns = undefined this.context = context this.fnContext = undefined this.fnOptions = undefined this.fnScopeId = undefined this.key = data && data.key this.componentOptions = componentOptions this.componentInstance = undefined this.parent = undefined this.raw = false this.isStatic = false this.isRootInsert = true this.isComment = false this.isCloned = false this.isOnce = false this.asyncFactory = asyncFactory this.asyncMeta = undefined this.isAsyncPlaceholder = false } }
下面dom分別依次執行,先渲染裏面而後再渲染外層
1. [_c('h1',{staticStyle:{"color":"red"}},[_v("我是選項模板3")]) <h1 style="color:red">我是選項模板3</h1> 2._c('p',[_v(_s(number))] <p>{{number}}</p> 3._c('p',[_v(_s(message))]) <p>{{message}}</p> 4._m(0)是緩存渲染數 function anonymous() { with(this){ return _c('div',[ _c('div',[_v("\n 1\n "), _c('div',[_v("11")]),_v(" "), _c('div',[_v("12")]) ]),_v(" "), _c('div',[_v("2")]),_v(" "), _c('div',[_v("3")]),_v(" "), _c('div',[_v("4")]),_v(" "), _c('div',[_v("5")]) ]) } } vdom順序依次爲 (1)<div>11</div> (2)<div>12</div> (3)<div> 1 <div>11</div> <div>12</div> </div> (4)<div>2</div> (5)<div>3</div> (6)<div>4</div> (7)<div>5</div> (8)<div> <div> 1 <div>11</div> <div>12</div> </div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> </div> (9)<div> <h1 style="color:red">我是選項模板3</h1> <p>{{number}}</p> <p>{{message}}</p> <div> <div> 1 <div>11</div> <div>12</div> </div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> </div> </div>
最後一次執行最外面的
render-static.js給m[0]靜態樹作了緩存處理
renderStatic ( index, isInFor ) { //緩存處理 const cached = this._staticTrees || (this._staticTrees = []) // staticRenderFns被執行 tree = cached[index] = this.$options.staticRenderFns[index].call( this._renderProxy, // 代理能夠理解爲vue實例對象,多了一些提示處理 null, this // for render fns generated for functional component templates ) markStatic(tree, `__static__${index}`, false) return tree } function markStatic ( tree, key, isOnce ) { function markStaticNode (node, key, isOnce) { node.isStatic = true //靜態樹爲true node.key = key // `__static__${index}` 標誌 node.isOnce = isOnce // 是不是v-once } markStaticNode(node, key, isOnce) }
而後又從新執行
function anonymous( ) { with(this){return _c('div',[_c('div',[_v("\n 1\n "),_c('div',[_v("11")]),_v(" "),_c('div',[_v("12")])]),_v(" "),_c('div',[_v("2")]),_v(" "),_c('div',[_v("3")]),_v(" "),_c('div',[_v("4")]),_v(" "),_c('div',[_v("5")])])} }
打印render()結果
靜態樹有了isStatic和key值
補充個小問題 render函數裏number 仍是變量是何時變成數字的由於function有個with(this){}改變了做用域,當this.render()執行時候,那麼this就是指得vue, $options.data 已經經過defineProperty代理到了vue下,訪問this.data就是訪問$options.data 因此number就是數字啦