來(lái)聊聊Vue中使用Render函數(shù)和JSX
Render函數(shù)
render函數(shù)是組件渲染的重要核心,它跟template模板開發(fā)一樣,只不過(guò)這種形式開發(fā),它(render)更接近底層,這樣能讓Vue編譯時(shí)少轉(zhuǎn)換一次。
讓我們來(lái)看一下哪里能用到render函數(shù)。
我們都知道Vue項(xiàng)目入口文件main.js里面有個(gè)render函數(shù)長(zhǎng)下面這樣,將項(xiàng)目的App根組件,掛載到根實(shí)例上通過(guò)render渲染。
new Vue({
render: h => h(App)
}).$mount('#app')
我們來(lái)解刨一下render函數(shù)身體。
render函數(shù)返回值是一個(gè)
VNode-> "virtual node"虛擬節(jié)點(diǎn)render函數(shù)的參數(shù)是一個(gè)
createElement函數(shù)第一個(gè) 標(biāo)簽名稱 第二個(gè) 屬性值 第三個(gè) 標(biāo)簽子級(jí)元素 createElement返回值也是一個(gè)VNode節(jié)點(diǎn)createElement函數(shù)的參數(shù)有三個(gè)
「代碼演示:」
index.js
export default {
data() {
return {
name: '蛙人'
}
},
render(createElement) {
return createElement(
"div",
{ attrs: {title: "蛙人"} },
[
createElement("span", null, "蛙人")
]
)
}
}
main.js
import config from "./index.js"
Vue.component("test", config)
上面會(huì)調(diào)用標(biāo)簽會(huì)創(chuàng)建出一個(gè)div帶有span子級(jí)的內(nèi)容,注意createElement第二個(gè)參數(shù)屬性這里,這里不能亂寫,必須遵守官網(wǎng)風(fēng)格點(diǎn)擊這里。
當(dāng)然這里肯定有人會(huì)問(wèn),這樣寫有什么用,跟template寫不一樣嘛,render函數(shù)這樣寫還麻煩可讀性不強(qiáng)。
分情況,有時(shí)候用render更加靈活,咱就拿官網(wǎng)最典型的案例來(lái)「舉個(gè)例子」。
封裝一個(gè)組件,進(jìn)行傳入數(shù)字參數(shù),就顯示數(shù)字參數(shù)的標(biāo)簽,你肯定會(huì)先想到這樣。
<template>
<div>
<h1 v-if="num == 1"></h1>
<h2 v-if="num == 2"></h2>
<h3 v-if="num == 3"></h3>
<h4 v-if="num == 4"></h4>
<h5 v-if="num == 5"></h5>
<h6 v-if="num == 6"></h6>
</div>
</template>
上面這樣實(shí)現(xiàn)是沒問(wèn)題的,但是代碼會(huì)冗余,一堆判斷。我們?cè)賮?lái)看一下render函數(shù)的實(shí)現(xiàn)
<script>
render: function (createElement) {
return createElement(
'h' + this.num,
)
},
props: {
num: {
type: Number,
required: true
}
}
</script>
上面兩種都實(shí)現(xiàn)了同樣的功能,是不是render函數(shù)這種方式看起來(lái)要簡(jiǎn)潔的多。所以一般用render函數(shù)封裝東西是比較靈活的,尤其是配置和模板分離。深入理解配置這里。
什么是JSX
JSX是JavScript和XML結(jié)合一種的格式,是JavaScript的擴(kuò)展語(yǔ)法。說(shuō)白了就是可以在JavaScript代碼中使用JSX。JavaScript在解析JSX時(shí)會(huì)先創(chuàng)建虛擬DOM,JSX最后會(huì)被編譯為JavaScript代碼執(zhí)行。
為什么要用JSX
有的人肯定覺得用render函數(shù)寫如果嵌套子級(jí)太多層看著太別扭了,可讀性太差。
export default {
render(createElement) {
return createElement(
"div",
{ attrs: {title: "蛙人"} },
[
createElement(
"span",
null,
"蛙人"
),
createElement(
"span",
null,
createElement(
"b",
null,
"前端娛樂圈"
)
),
createElement(
"span",
null,
createElement(
"b",
null,
createElement(
"i",
null,
"關(guān)注前端娛樂圈"
)
)
)
]
)
}
}
比如上面這種,嵌套多層,可讀性太差,時(shí)間一長(zhǎng)自己還得捋半天。

所以為了解決這問(wèn)題,JSX就登場(chǎng)了,JSX相當(dāng)于就是createElement的語(yǔ)法糖,這種形式可以直接使用template模板那種格式在render函數(shù)里寫。
我們用這種形式來(lái)還原一下上面的createElement寫的,是不是這種很簡(jiǎn)潔易讀。
export default {
render() {
return (<div>
<span>蛙人</span>
<span>
<b>前端娛樂圈</b>
</span>
<span>
<b>
<i>關(guān)注前端娛樂圈</i>
</b>
</span>
</div>)
}
}
JSX和Render函數(shù)有什么不同
除了寫法不一樣外,沒什么不同,屬性都是遵循Vue文檔上的。
我們來(lái)使用JSX語(yǔ)法,看看怎么使用,這里玩過(guò)React的同學(xué)估計(jì)都會(huì)使用。
export default {
data() {
return {
name: "前端娛樂圈",
dataList: {
title: "前端娛樂圈",
href: "www.baidu.com"
}
}
},
render() {
return <div onClick={this.xxx} {...{attrs: this.dataList}}>{ this.name }</div>
}
}
使用
「如果你的項(xiàng)目是Webpack搭建,babel@6的情況」
npm i @babel/core @vue/babel-preset-jsx babel-loader
根目錄.babelrc文件
{
"plugins": ["transform-vue-jsx"]
}
webpack.config.js
{
test: /\.js/,
use: "babel-loader"
}
「如果你的項(xiàng)目是Webpack搭建,babel@7的情況」
npm i @babel/core @vue/babel-preset-jsx babel-loader @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
根目錄.babelrc文件
文檔說(shuō)明babel7兼容JSX問(wèn)題
{
"presets": ["@vue/babel-preset-jsx"]
}
webpack.config.js
{
test: /\.js/,
use: "babel-loader"
}
「如果你的項(xiàng)目是Vue-cli」
最新版本的cli是會(huì)默認(rèn)支持JSX語(yǔ)法的,如果你的版本較老請(qǐng)跟上面一樣的配置。
npm i @vue/babel-preset-jsx @vue/babel-helper-vue-jsx-merge-props
babel.config.js
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}參考
https://blog.csdn.net/sansan_7957/article/details/83014838
https://cn.vuejs.org/v2/guide/render-function.html#%E5%9F%BA%E7%A1%80
