Vue 中 render 函式有點意思

前端小智發表於2020-02-27

作者:Joshua Bemenderfe

譯者:前端小智

來源:vuejsbook.com

點贊再看,養成習慣

本文 GitHub github.com/qq449245884… 上已經收錄,更多往期高贊文章的分類,也整理了很多我的文件,和教程資料。歡迎Star和完善,大家面試可以參照考點複習,希望我們一起有點東西。

我們知道 Vue 模板是非常強大的,基本可以完成我們日常開發的所有任務。但是,有一些用例,如基於輸入或插槽值建立動態元件方式,render 函式會比模板完成的更好也更出色。

用過 React 開發的人對 render 函式應該非常熟悉,因為React元件通過 JSX和 render 函式來構建的。 儘管Vue render 函式也可以用JSX編寫,但在這裡我們使用原生 JS方式,因為這樣,我們可以更輕鬆地瞭解Vue元件系統的一些基礎。

值得注意的是,Vue 的模板實際上在編譯時也是會先解析成 render 函式表示方式。 模板只是在render 函式之上提供了一個方便且熟悉的語法糖。 儘管 render 函式更強大,但render函式可讀性很差,相對用的也比較少了。

建立元件

帶有 render 函式的元件沒有template標記或屬性。 相反,該元件定義了一個了名為render的函式,該函式接收一個reateElement(renderElement: String | Component, definition: Object, children: String | Array)引數(由於某種原因,通常別名為h,歸咎於JSX)並返回使用該函式建立的元素,其他一切保持不變,來看看事例:

export default {
  data() {
    return {
      isRed: true
    }
  },

  /*
   * <template>
   *   <div :class="{'is-red': isRed}">
   *     <p>這是一個 render 事例</p>
   *   </div>
   * </template>
   */
  // render 中的渲染結果與上面等價
  render(h) {
    return h('div', {
      'class': {
        'is-red': this.isRed
      }
    }, [
      h('p', '這是一個 render 事例')
    ])
  }
}
複製程式碼

render 函式中如何表示指令

Vue 模板具有各種便捷功能,以便向模板新增基本邏輯和繫結功能,如 v-ifv-forv-moel指令等。 在render函式中是無法使用這些指令的。 取而代之的是以純 JS 來實現,對於大多數指令而言,這也是比較簡單的。

v-if

v-if 用純 JS 實現很簡單,只需圍繞createElement呼叫使用 if(expr)語句即可。

v-for

v-for可以使用for-ofArray.mapArray.filter等的JS方法中的任何一種來實現。我們可以通過非常有趣的方式將它們組合在一起,以實現過濾或狀態切片,而無需計算屬性。

例如,有以下 Vue 的模板程式碼

<template>
  <ul>
    <li v-for="pea of pod">
      
    </li>
  </ul>
</template>
複製程式碼

可以用下面的 render 函式來實現上面的效果:

render(h) {
  return h('ul', this.pod.map(pea => h('li', pea.name)));
}
複製程式碼

v-model

我們知道,v-model只是bind屬性與value的語法糖,並在觸發input事件時設定資料屬性。但是,在render函式沒有這樣的簡寫,我們需要自己實現。

假設,在 Vue 中,我們有如下的結構:

<template>
  <input v-model='myBoundProperty'/>
</template>
複製程式碼

上面程式碼等價於:

<template>
  <input :value="myBoundProperty" @input="myBoundProperty = $event.target.value"/>
</template>
複製程式碼

在 render 函式中可以用下面方式來實現上面的程式碼:

render(h) {
  return h('input', {
    domProps: {
      value: this.myBoundProperty
    },
    on: {
      input: e => {
        this.myBoundProperty = e.target.value
      }
    }
  })
}
複製程式碼

v-bind

attributeproperty 這兩種型別的繫結被放在元素定義中,如arttrspropsdomProps( valueinnerHTML之類的東西)。

render(h) {
  return h('div', {
    attrs: {
      // <div :id="myCustomId">
      id: this.myCustomId
    },

    props: {
      // <div :someProp="someonePutSomethingHere">
      someProp: this.someonePutSomethingHere
    },

    domProps: {
       // <div :value="somethingElse">
      value: this.somethingElse
    }
  });
}
複製程式碼

需要注意的是,對於 classstyle的繫結是直接在定義的根進行處理,而不是作為attrspropsdomProps處理。

render(h) {
  return h('div', {
    // “類”是JS中的保留關鍵字,因此必須引用它。
    'class': {
      myClass: true,
      theirClass: false
    },

    style: {
      backgroundColor: 'green'
    }
  });
}
複製程式碼

v-on

對事件處理程也是直接新增到元素定義中 on 定義

render(h) {
  return h('div', {
    on: {
      click(e) {
        console.log('I got clickeded!')
      }
    }
  });
}
複製程式碼

事件的修飾符可以在處理程式內部實現:

  • .stop -> e.stopPropagation()
  • .prevent -> e.preventDefault()
  • .self -> if (e.target !== e.currentTarget) return

鍵盤修飾符

  • .[TARGET_KEY_CODE] -> if (event.keyCode !== TARGET_KEY_CODE) return
  • .[MODIFIER] -> if (!event.MODIFIERKey) return

特殊屬性

Slots 可以通過this.$slots作為createElement()節點的陣列來訪問插槽。

作用域插槽儲存在this.$scopedSlots[scope](props:object) 中,作為返回createElement()節點陣列的函式。


程式碼部署後可能存在的BUG沒法實時知道,事後為了解決這些BUG,花了大量的時間進行log 除錯,這邊順便給大家推薦一個好用的BUG監控工具 Fundebug

原文:vuejsbook.com/introductio…


交流

文章每週持續更新,可以微信搜尋「 大遷世界 」第一時間閱讀和催更(比部落格早一到兩篇喲),本文 GitHub github.com/qq449245884… 已經收錄,整理了很多我的文件,歡迎Star和完善,大家面試可以參照考點複習,另外關注公眾號,後臺回覆福利,即可看到福利,你懂的。

Vue 中 render 函式有點意思

相關文章