前言
真的拜轨,一定會有一些小伙伴直到完整了幾個項目都做完了抽减,卻從未用過渲染函數(shù)和JSX,所以一旦遇到需要復(fù)雜處理的模板元素橄碾,其中就會夾雜大量的v-if
卵沉、v-else
、v-else-if
……以及各種三元操作符法牲。是時候了解一下渲染函數(shù)和JSX了史汗,即便Vue 3在幾個月后就要問世,學(xué)習(xí)一下JSX絕對沒有壞處拒垃,也不會過時停撞,JSX是React一直推崇的描述模板的方法,算是業(yè)界通用的一項技術(shù)悼瓮。
官網(wǎng)
https://cn.vuejs.org/v2/guide/render-function.html
為什么有官網(wǎng)介紹戈毒,還要來個教程
官網(wǎng)教程是基于運行時版本的Vue.js,按照全局組件的模式為例横堡,而我們通常是使用完整版的Vue.js埋市,且使用單文件組件,所以本文以單文件組件為例說明命贴。
渲染函數(shù)和JSX適用場景
當(dāng)你模板中存在大量條件判斷時道宅,就適用渲染函數(shù)和JSX。比如在class中胸蛛、style中污茵、文本中、屬性中存在條件判斷時葬项,會將模板搞得很冗長泞当,而且不容易閱讀,這時候適用渲染函數(shù)和JSX會讓代碼變得很清晰玷室。
Hello World
- 在components文件夾創(chuàng)建HelloWorld.vue零蓉,內(nèi)容是:
export default {
props: {
msg: {
type: String,
default: ""
},
type: {
type: String,
default: ""
}
},
render(createElement) {
return createElement("button", {
class: {
btn: true,
success: this.type === "success",
danger: this.type === "danger"
},
domProps: {
innerText: this.msg || "默認(rèn)"
},
on: {
click: this.handleClick
}
});
},
methods: {
handleClick() {
console.log(11);
}
}
};
<style scoped lang="scss">
.success {
color: green;
}
.danger {
color: red;
}
</style>
- 父組件按照常規(guī)的子組件調(diào)用方法調(diào)用即可:
<hello-world type="success" msg="abc">xyz</hello-world>
JS代碼從略。
效果是渲染出一段DOM:
<button data-v-469af010="" class="btn success">abc</button>
穷缤。-
講一下HelloWorld.vue敌蜂。其中props和methods不解釋,只說render津肛。render負(fù)責(zé)渲染一段DOM章喉,前提是要給它傳入VDOM,而createElement就是負(fù)責(zé)構(gòu)建VDOM,我們只需要關(guān)心createElement的參數(shù)就行了秸脱。這里官網(wǎng)都有介紹落包,簡單說:
第一個參數(shù)負(fù)責(zé)聲明頂級元素的標(biāo)簽名,也就是說摊唇,標(biāo)簽名到底是button還是div還是h2還是span還是其他什么咐蝇。
第二個參數(shù)就是對頂級元素的所有修飾,官網(wǎng)都有解釋巷查,這里只列一下:
- class
- style
- attrs
- props
- domProps
- on
- nativeOn
- directives
- scopedSlots
- slot
- key
- ref
- refInFor
第三個參數(shù)是可選的有序,是一個數(shù)組,每一個數(shù)組元素也就是一個子元素岛请,如果是文本旭寿,直接寫字符串,如果是元素崇败,就要繼續(xù)寫
create('標(biāo)簽名', {修飾對象})
盅称,這樣一層一層寫下去。從實踐說后室,如果層數(shù)太多缩膝,反而不如單文件的<template>標(biāo)簽直觀,所以盡量保持2層即可咧擂。
循環(huán)創(chuàng)建元素
使用v-for可以在模板中循環(huán)創(chuàng)建元素逞盆,在createElement里當(dāng)然也可以。
官方舉了一個例子松申,但實踐中一般用不到,因為實踐中往往將一個數(shù)組映射成一系列元素:
官網(wǎng)例子:
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
更貼近實踐的例子俯逾,dataList靠父組件傳入贸桶,然后利用map返回一系列相似的子元素:
render: function (createElement) {
return createElement('div',
this.dataList.map(function () {
return createElement('p', {
// ...
})
})
)
}
如何對應(yīng)<template>里的v-for/v-model/v-if/v-else指令
如何對應(yīng)v-for上面已經(jīng)說了,就用map就可以了桌肴。
如何對應(yīng)v-model略復(fù)雜皇筛,官網(wǎng)有專門介紹,不說了坠七。
v-if這類條件指令水醋,用JS的原生if...else...即可。這里不介紹用法彪置,但是強調(diào)一點拄踪,這就是渲染函數(shù)最有優(yōu)勢的地方。比如拳魁,一套條件語句如下所示惶桐,想象一下,如果將這套判斷邏輯實現(xiàn)到<template>標(biāo)簽里,會是多么的恐怖姚糊,多么難以理解贿衍,某個else是哪個if的else?看的眼花救恨。而在JS中贸辈,if...else...就會直觀得多。
if () {
if () {
if () {
}
} else {
}
} else {
}
事件和插槽
很容易肠槽,閱讀官網(wǎng)即可裙椭。
JSX
終于到JSX了,官網(wǎng)的介紹比較簡單署浩。JSX說白了就是將<template>里的標(biāo)簽直接寫到JS里揉燃,這本身在JS里是行不通的,只能依靠插件來編譯筋栋。比如官方的示例:
render: function (h) {
return (
<AnchoredHeading level={1}>
<span>Hello</span> world!
</AnchoredHeading>
)
}
在JS里用括號包裹一段像DOM的東西炊汤,而且還不是字符串,這在JS里是絕對行不通的弊攘,因此想用JSX就必須用插件編譯成正常的模板抢腐,https://github.com/vuejs/jsx有介紹。
注意幾點:
JSX的一個原則是從簡襟交、小片段原則迈倍,所以不要將計算過程寫入JSX中,如果寫入的話捣域,又跟<template>一樣了啼染,比如你要計算class的值,你需要在return之前焕梅,先聲明一個變量比如叫classVal迹鹅,然后通過一系列的JS運算算出classVal的值,然后JSX里面只能寫上像上文那樣比較簡單的內(nèi)容贞言,比如
<button class={classVal}></button>
斜棚。JSX默認(rèn)不支持v-if等v-*指令,只支持非常少的幾個指令该窗,需要再額外裝插件來彌補弟蚀。
JSX支持三元操作符,在
{}
里使用即可酗失。
總之义钉,vue沒有主打JSX,而且JSX本身也比較弱级零,至少在Vue 2.0里断医,不是良藥滞乙。