Vue源碼解析(3)-AST到VNode過程

模版以下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就是數字啦

相關文章
相關標籤/搜索