由於最近接手維護一個基於 ivew 的項目, 新增模塊中包含不少自定義功能, 因此大量使用到了 render 函數; 故對其作一下總結...關於 render 函數, 官方文檔也作了比較詳細的介紹: render 函數: https://cn.vuejs.org/v2/guide... ; 通常組件咱們都是用 template模板的方式去寫; 有時候會形成代碼上的冗餘, 很差擴展.html
在學習 render 函數以前, 最好先了解一下虛擬節點 vNode, 以及虛擬節點樹組成的虛擬vDom, 這樣會更好的理解 render 函數vue
/* *@describe {渲染函數} *@params {見下方} *@returns {一段VNode} */ createElement函數: 一般寫爲 h 函數, 也是官方推薦的 h( // {String | Object | Function} => 'p' | 'Select' | (h, p) => {} // 一個 HTML 標籤名、組件選項對象,或者 // resolve 了上述任何一種的一個 async 函數。必填項。 'div', // {Object} // 一個與模板中屬性對應的數據對象。可選。 { style: { width: '100px' }, }, // {String | Array} // 子級虛擬節點 (VNodes),通常是數組: 由 `h()` 構建而成,參數: ('標籤|組件', {attrs}, text) // 也可使用字符串來生成「文本虛擬節點」。可選。 [ '先寫一些文字', h('h1', '一則頭條'), h(MyComponent, { props: { someProp: 'foobar' } }) ] )
函數式組件 能夠看作是組件裏的一個函數,入參是渲染上下文(render context),返回值是渲染好的HTML字符串
對於函數式組件,能夠這樣定義:數組
Stateless(無狀態):組件自身是沒有狀態的 Instanceless(無實例):組件自身沒有實例,也就是沒有this
因爲函數式組件中沒有this,參數須要靠context來傳遞; export default { name: 'functional-button', functional: true, render (h, context) { return h('button', '按鈕 1 號') } }
由官方文檔可知: context 參數以下:less
props:提供全部 prop 的對象 children: VNode 子節點的數組 slots: 一個函數,返回了包含全部插槽的對象 scopedSlots: (2.6.0+) 一個暴露傳入的做用域插槽的對象。也以函數形式暴露普通插槽。 data:傳遞給組件的整個數據對象,做爲 createElement 的第二個參數傳入組件 parent:對父組件的引用 listeners: (2.3.0+) 一個包含了全部父組件爲當前組件註冊的事件監聽器的對象。這是data.on 的一個別名。 injections: (2.3.0+) 若是使用了 inject 選項,則該對象包含了應當被注入的屬性。
<template> <div class="home"> <func-button> hello button </func-button> </div> </template> <script> import FuncButton from '../function-components/func-button' export default { name: 'home', components: { FuncButton } } </script>
如今咱們將這個 func-button.js 組件改造一下, 上面的hello button 文本節點爲func-button.js的childern屬性(數組|String),咱們可讓父組件去控制組件的button按鈕內容, 改寫以下:dom
// export default { // name: 'functional-button', // functional: true, // render (h, context) { // return h('button', '按鈕 1 號') // } // } export default { name: 'funtional-button', functional: true, render (h, { children }) { return h('button', children) } }
code以下:async
<template> <div class="home"> <func-button @click="handleClick"> hello button </func-button> </div> </template> <script> import FuncButton from '../function-components/func-button' export default { name: 'home', components: { FuncButton }, methods: { handleClick () { alert('你點到我了') } } } </script> // func-button組件 export default { functional: true, // 組件的屬性集成在data裏, 爲了簡便,咱們能夠用 data 來替換下面的 props, listeners等 // 寫成 h('button', data, ['hello', ...children]) render (h, { props, listeners, children }) { return h( 'button', { attrs: props, on: { click: listeners.click } }, children ) } }
平時開發仍是多用temlate由於直觀簡潔,各類指令用着很方便,可是常常寫template有時會以爲代碼看着很冗餘,若是想本身控制渲染邏輯好比循,判斷等等時咱們就能夠考慮使用JSX
關於 JSX 的使用參考ide
<script> export default { name: 'h-title', props: { id: { type: Number, default: 1 } }, render () { const hText = `<h${this.id}>${this.$slots.default[0].text}</h${this.id}>` return <div domPropsInnerHTML={hText}></div> } } </script>
// List.vue 組件 <template> <div> <template v-for="(item, index) in data"> <li :key="index" v-if="!render">{{ item }}</li> <ListItem v-else :key="`a${index}`" :render="render" :item="item" ></ListItem> </template> </div> </template> <script> import ListItem from "./list-item" export default { components: { ListItem }, props: { // 支持自定義渲染 render: { type: Function }, data: { type: Array, default: () => [] } } }; </script> // list-item.js export default { props: { render: { type: Function }, item: { type: String } }, render(h) { // createElement return this.render(h, this.item) } }
// 父組件中 <List :data="['香蕉','蘋果','橘子']" :render="render"></List> // 能夠渲染你想要的標籤和內容 render (h, data) { return <span>{data}</span> }