作者: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-if
、v-for
、v-moel
指令等。 在render
函式中是無法使用這些指令的。 取而代之的是以純 JS 來實現,對於大多數指令而言,這也是比較簡單的。
v-if
v-if
用純 JS 實現很簡單,只需圍繞createElement
呼叫使用 if(expr)
語句即可。
v-for
v-for
可以使用for-of
,Array.map
,Array.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
attribute
和property
這兩種型別的繫結被放在元素定義中,如arttrs
、props
和domProps
( value
和innerHTML
之類的東西)。
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
}
});
}
複製程式碼
需要注意的是,對於 class
和style
的繫結是直接在定義的根進行處理,而不是作為attrs
,props
或domProps
處理。
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。
交流
文章每週持續更新,可以微信搜尋「 大遷世界 」第一時間閱讀和催更(比部落格早一到兩篇喲),本文 GitHub github.com/qq449245884… 已經收錄,整理了很多我的文件,歡迎Star和完善,大家面試可以參照考點複習,另外關注公眾號,後臺回覆福利,即可看到福利,你懂的。