Vue的渲染函數

在Vue中,咱們都是絕大部分都是使用template來建立html,框架給予了很好的支持,使用起來也很方便,符合常規的編程方式。可是在一些特殊的場景須要有特殊的判斷時,使用template顯得會低效率,而且代碼的可讀性也不高。此時咱們能夠用到render函數,使用javascript的徹底編程能力來實現html的建立。

情景:

//要求是經過size的值來動態生成title-size標籤的組件
< title-size :size="1">Hello world!< /title-size>
複製代碼

此時採用以前的常規作法,咱們會選擇javascript

< script type="text/x-template" id="titleSize-template">
  < h1 v-if="size === 1">
    < slot>< /slot>
  < /h1>
  < h2 v-else-if="size === 2">
    < slot>< /slot>
  < /h2>
  < h3 v-else-if="size === 3">
    < slot>< /slot>
  < /h3>
  < h4 v-else-if="size === 4">
    < slot>< /slot>
  < /h4>
  < h5 v-else-if="size === 5">
    < slot>
  < /h5>
  < h6 v-else-if="size === 6">
    < slot>
  < /h6>
  < /script>
複製代碼
Vue.component('anchored-heading', {
  template: '#titleSize-template',
  props: {
    size: {
      type: Number,
      required: true
    }
  }
})
複製代碼

此時的組件根據prop取到的數據size值進行選擇標籤的類型,從而完成動態生成title-size標籤的組件。可是這樣的話是咱們在template中定義不一樣的h1~h6的標籤,而後再去根絕size的值來決定取得是哪一個標籤,這樣的話在數據的處理上顯得被動不靈活。而且用這種方式處理時,須要重複使用< slot>< /slot>來插入title-size的內容,反正總結起來就是低效。html

此時能夠嘗試render函數重寫上面的例子

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.size,   // tag name 標籤名稱
      this.$slots.default // 子組件中的陣列
    )
  },
  props: {
    size: {
      type: Number,
      required: true
    }
  }
})
複製代碼

此時就顯得很靈活,直接根據傳入的size值進行建立對應的標籤,而且也不須要再寫那麼多冗長的代碼了。

註釋: this.$slots.default對用 template的的使用沒有name(做用至關於以上例子中的slot標籤)vue

節點、樹以及虛擬 DOM

深刻渲染函數以前,咱們須要瞭解一些瀏覽器的工做原理,當瀏覽器讀html代碼時,它會創建一個「DOM 節點」樹來保持追蹤。每一個元素都是一個節點。每片文字也是一個節點。甚至註釋也都是節點。一個節點就是頁面的一個部分。就像家譜樹同樣,每一個節點均可以有孩子節點 (也就是說每一個部分能夠包含其它的一些部分)。js的運行速度是很快的,可是dom的渲染確實很慢的,每每是影響性能的一個重要因素。java

可是vue是數據驅動的,不須要咱們去手動更新節點。只須要告訴 Vue 你但願頁面上的 HTML 是什麼

< h1>{{ testData }}< /h1>
複製代碼
render: function (createElement) {
  return createElement('h1', this.testData)
}
複製代碼

當數據發生改變時,頁面的dom都會被及時高效的去渲染,而不須要本身去作其餘的處理。express

虛擬 DOM

Vue 經過創建一個虛擬 DOM 對真實 DOM 發生的變化保持追蹤。能夠作個例子:編程

return createElement('h1', this.testData)
複製代碼

createElement 返回的是什麼呢?其實不是一個實際的 DOM 元素。它更準確的名字多是 createNodeDescription,由於它所包含的信息會告訴 Vue 頁面上須要渲染什麼樣的節點,及其子節點。咱們把這樣的節點描述爲「虛擬節點 (Virtual Node)」,也常簡寫它爲「VNode」。「虛擬 DOM」是咱們對由 Vue 組件樹創建起來的整個 VNode 樹的稱呼。瀏覽器

createElement 參數

// @returns {VNode} 返回的是一個描述對象它所包含的信息會告訴 Vue 頁面上須要渲染什麼樣的節點
createElement(
  // {String | Object | Function} 
  // 一個 HTML 標籤字符串,組件選項對象,或者
  // 解析上述任何一種的一個 async 異步函數,必要參數。
  'div',

  // {Object}
  // 一個包含模板相關屬性的數據對象
  // 這樣,能夠在 template 中使用這些屬性。可選參數。
  {
  },

  // {String | Array}
  // 子節點 (VNodes),由 `createElement()` 構建而成,
  // 或使用字符串來生成「文本節點」。可選參數。
  [
    '先寫一些文字',
    createElement('h1', '一條數據'),
    createElement(MyComponent, {
      props: {
        someProp: 'foobar'
      }
    })
  ]
)
複製代碼

深刻 data 對象

在使用data時要注意:在模板語法中,v-bind:class 和 v-bind:style ,會被特別對待同樣,在 VNode 數據對象中,下列屬性名是級別最高的字段。該對象也容許你綁定普通的 HTML 特性,就像 DOM 屬性同樣,好比 innerHTML (這會取代 v-html 指令)。(此處的官方文檔寫的很全了,就直接拿過來了)markdown

{
  // 和`v-bind:class`同樣的 API
  'class': {
    foo: true,
    bar: false
  },
  // 和`v-bind:style`同樣的 API
  style: {
    color: 'red',
    fontSize: '14px'
  },
  // 正常的 HTML 特性
  attrs: {
    id: 'foo'
  },
  // 組件 props
  props: {
    myProp: 'bar'
  },
  // DOM 屬性
  domProps: {
    innerHTML: 'baz'
  },
  // 事件監聽器基於 `on`
  // 因此再也不支持如 `v-on:keyup.enter` 修飾器
  // 須要手動匹配 keyCode。
  on: {
    click: this.clickHandler
  },
  // 僅對於組件,用於監聽原生事件,而不是組件內部使用
  // `vm.$emit` 觸發的事件。
  nativeOn: {
    click: this.nativeClickHandler
  },
  // 自定義指令。注意,你沒法對 `binding` 中的 `oldValue`
  // 賦值,由於 Vue 已經自動爲你進行了同步。
  directives: [
    {
      name: 'my-custom-directive',
      value: '2',
      expression: '1 + 1',
      arg: 'foo',
      modifiers: {
        bar: true
      }
    }
  ],
  // Scoped slots in the form of
  // { name: props => VNode | Array }
  scopedSlots: {
    default: props => createElement('span', props.text)
  },
  // 若是組件是其餘組件的子組件,需爲插槽指定名稱
  slot: 'name-of-slot',
  // 其餘特殊頂層屬性
  key: 'myKey',
  ref: 'myRef'
}

複製代碼

!注意:VNodes 必須惟一

相關文章
相關標籤/搜索