vue 的 Render 函數(shù)
一、節(jié)點(diǎn)、樹(shù)以及虛擬 DOM
<div> <h1>My title</h1> Some text content <!-- TODO: Add tagline --> </div>

每個(gè)元素都是一個(gè)節(jié)點(diǎn)。每段文字也是一個(gè)節(jié)點(diǎn)。甚至注釋也都是節(jié)點(diǎn)。一個(gè)節(jié)點(diǎn)就是頁(yè)面的一個(gè)部分。就像家譜樹(shù)一樣,每個(gè)節(jié)點(diǎn)都可以有孩子節(jié)點(diǎn) (也就是說(shuō)每個(gè)部分可以包含其它的一些部分)。
高效地更新所有這些節(jié)點(diǎn)會(huì)是比較困難的,不過(guò)所幸你不必手動(dòng)完成這個(gè)工作。你只需要告訴 Vue 你希望頁(yè)面上的 HTML 是什么,這可以是在一個(gè)模板里:
<h1>{{ blogTitle }}</h1>
或者一個(gè)渲染函數(shù)里:
render: function (createElement) {
return createElement('h1', this.blogTitle)
}
在這兩種情況下,Vue 都會(huì)自動(dòng)保持頁(yè)面的更新,即便 blogTitle 發(fā)生了改變。
二、虛擬 DOM
Vue 通過(guò)建立一個(gè)虛擬 DOM 來(lái)追蹤自己要如何改變真實(shí) DOM。請(qǐng)仔細(xì)看這行代碼:
return createElement('h1', this.blogTitle)
createElement 到底會(huì)返回什么呢?其實(shí)不是一個(gè)實(shí)際的 DOM 元素。它更準(zhǔn)確的名字可能是 createNodeDescription,因?yàn)樗男畔?huì)告訴 Vue 頁(yè)面上需要渲染什么樣的節(jié)點(diǎn),包括及其子節(jié)點(diǎn)的描述信息。我們把這樣的節(jié)點(diǎn)描述為“虛擬節(jié)點(diǎn) (virtual node)”,也常簡(jiǎn)寫(xiě)它為“VNode”。“虛擬 DOM”是我們對(duì)由 Vue 組件樹(shù)建立起來(lái)的整個(gè) VNode 樹(shù)的稱(chēng)呼。
// @returns {VNode}
createElement(
// {String | Object | Function}
// 一個(gè) HTML 標(biāo)簽名、組件選項(xiàng)對(duì)象,或者
// resolve 了上述任何一種的一個(gè) async 函數(shù)。必填項(xiàng)。
'div',
// {Object}
// 一個(gè)與模板中 attribute 對(duì)應(yīng)的數(shù)據(jù)對(duì)象??蛇x。
{
// (詳情見(jiàn)下一節(jié))
},
// {String | Array}
// 子級(jí)虛擬節(jié)點(diǎn) (VNodes),由 `createElement()` 構(gòu)建而成,
// 也可以使用字符串來(lái)生成“文本虛擬節(jié)點(diǎn)”??蛇x。
[
'先寫(xiě)一些文字',
createElement('h1', '一則頭條'),
createElement(MyComponent, {
props: {
someProp: 'foobar'
}
})
]
)
2.1 深入數(shù)據(jù)對(duì)象
在渲染函數(shù)中,一些模板屬性會(huì)在Vnode數(shù)據(jù)對(duì)象中有頂層字段,同時(shí)對(duì)象也允許綁定普通的屬性,也允許綁定如 innerHTML 這樣的 DOM property (這會(huì)覆蓋 v-html 指令)。
{
// 與 `v-bind:class` 的 API 相同,
// 接受一個(gè)字符串、對(duì)象或字符串和對(duì)象組成的數(shù)組
'class': {
foo: true,
bar: false
},
// 與 `v-bind:style` 的 API 相同,
// 接受一個(gè)字符串、對(duì)象,或?qū)ο蠼M成的數(shù)組
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML attribute
attrs: {
id: 'foo'
},
// 組件 prop
props: {
myProp: 'bar'
},
// DOM property
domProps: {
innerHTML: 'baz'
},
// 事件監(jiān)聽(tīng)器在 `on` 內(nèi),
// 但不再支持如 `v-on:keyup.enter` 這樣的修飾器。
// 需要在處理函數(shù)中手動(dòng)檢查 keyCode。
on: {
click: this.clickHandler
},
// 僅用于組件,用于監(jiān)聽(tīng)原生事件,而不是組件內(nèi)部使用
// `vm.$emit` 觸發(fā)的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定義指令。注意,你無(wú)法對(duì) `binding` 中的 `oldValue`
// 賦值,因?yàn)?Vue 已經(jīng)自動(dòng)為你進(jìn)行了同步。
directives: [
{
name: 'my-custom-directive',
value: '2',
expression: '1 + 1',
arg: 'foo',
modifiers: {
bar: true
}
}
],
// 作用域插槽的格式為
// { name: props => VNode | Array<VNode> }
scopedSlots: {
default: props => createElement('span', props.text)
},
// 如果組件是其它組件的子組件,需為插槽指定名稱(chēng)
slot: 'name-of-slot',
// 其它特殊頂層 property
key: 'myKey',
ref: 'myRef',
// 如果你在渲染函數(shù)中給多個(gè)元素都應(yīng)用了相同的 ref 名,
// 那么 `$refs.myRef` 會(huì)變成一個(gè)數(shù)組。
refInFor: true
}
2.2 約束
VNode 必須唯一
組件樹(shù)中的所有 VNode 必須是唯一的。這意味著,下面的渲染函數(shù)是不合法的:
render: function (createElement) {
var myParagraphVNode = createElement('p', 'hi')
return createElement('div', [
// 錯(cuò)誤 - 重復(fù)的 VNode
myParagraphVNode, myParagraphVNode
])
}
如果你真的需要重復(fù)很多次的元素/組件,你可以使用工廠(chǎng)函數(shù)來(lái)實(shí)現(xiàn)。例如,下面這渲染函數(shù)用完全合法的方式渲染了 20 個(gè)相同的段落:
render: function (createElement) {
return createElement('div',
Array.apply(null, { length: 20 }).map(function () {
return createElement('p', 'hi')
})
)
}
三、在Render函數(shù)中的模板功能
3.1 v-if 和 v-for
只要在原生的 JavaScript 中可以輕松完成的操作,Vue 的渲染函數(shù)就不會(huì)提供專(zhuān)有的替代方法。比如,在模板中使用的 v-if 和 v-for:
<ul v-if="items.length">
<li v-for="item in items">{{ item.name }}</li>
</ul>
<p v-else>No items found.</p>
這些都可以在渲染函數(shù)中用 JavaScript 的 if/else 和 map 來(lái)重寫(xiě):
props: ['items'],
render: function (createElement) {
if (this.items.length) {
return createElement('ul', this.items.map(function (item) {
return createElement('li', item.name)
}))
} else {
return createElement('p', 'No items found.')
}
}
3.2 v-model
渲染函數(shù)中沒(méi)有與 v-model 的直接對(duì)應(yīng)——你必須自己實(shí)現(xiàn)相應(yīng)的邏輯:
props: ['value'],
render: function (createElement) {
var self = this
return createElement('input', {
domProps: {
value: self.value
},
on: {
input: function (event) {
self.$emit('input', event.target.value)
}
}
})
}
這就是深入底層的代價(jià),但與 v-model 相比,這可以讓你更好地控制交互細(xì)節(jié)。
3.3 事件 & 按鍵修飾符
對(duì)于 .passive、.capture 和 .once 這些事件修飾符,Vue 提供了相應(yīng)的前綴可以用于 on:

例如:
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}
對(duì)于所有其它的修飾符,私有前綴都不是必須的,因?yàn)槟憧梢栽谑录幚砗瘮?shù)中使用事件方法:

這里是一個(gè)使用所有修飾符的例子:
on: {
keyup: function (event) {
// 如果觸發(fā)事件的元素不是事件綁定的元素
// 則返回
if (event.target !== event.currentTarget) return
// 如果按下去的不是 enter 鍵或者
// 沒(méi)有同時(shí)按下 shift 鍵
// 則返回
if (!event.shiftKey || event.keyCode !== 13) return
// 阻止 事件冒泡
event.stopPropagation()
// 阻止該元素默認(rèn)的 keyup 事件
event.preventDefault()
// ...
}
}
3.4 插槽
你可以通過(guò) this.$slots 訪(fǎng)問(wèn)靜態(tài)插槽的內(nèi)容,每個(gè)插槽都是一個(gè) VNode 數(shù)組:
render: function (createElement) {
// `<div><slot></slot></div>`
return createElement('div', this.$slots.default)
}
也可以通過(guò) this.$scopedSlots 訪(fǎng)問(wèn)作用域插槽,每個(gè)作用域插槽都是一個(gè)返回若干 VNode 的函數(shù):
props: ['message'],
render: function (createElement) {
// `<div><slot :text="message"></slot></div>`
return createElement('div', [
this.$scopedSlots.default({
text: this.message
})
])
}
如果要用渲染函數(shù)向子組件中傳遞作用域插槽,可以利用 VNode 數(shù)據(jù)對(duì)象中的 scopedSlots 字段:
render: function (createElement) {
// `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
return createElement('div', [
createElement('child', {
// 在數(shù)據(jù)對(duì)象中傳遞 `scopedSlots`
// 格式為 { name: props => VNode | Array<VNode> }
scopedSlots: {
default: function (props) {
return createElement('span', props.text)
}
}
})
])
}
3.5 例子
import { CreateElement, RenderContext } from 'vue/types/umd'
export default {
functional: true,
props: {
row: Object,
render: Function,
index: Number,
column: {
type: Object,
default: null
}
},
render: (h: CreateElement, ctx: RenderContext) => {
const params: any = {
row: ctx.props.row,
index: ctx.props.index
}
if (ctx.props.column) params.column = ctx.props.column
return ctx.props.render(h, params)
}
}
到此這篇關(guān)于 vue 的 Render 函數(shù)的文章就介紹到這了,更多相關(guān)Render 函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue動(dòng)態(tài)設(shè)置頁(yè)面title的方法實(shí)例
這篇文章主要給大家介紹了關(guān)于vue動(dòng)態(tài)設(shè)置頁(yè)面title的相關(guān)資料,文中通過(guò)實(shí)例代碼結(jié)束的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
vue.js實(shí)現(xiàn)回到頂部動(dòng)畫(huà)效果
這篇文章主要為大家詳細(xì)介紹了vue.js實(shí)現(xiàn)回到頂部動(dòng)畫(huà)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
vue登錄以及權(quán)限驗(yàn)證相關(guān)的實(shí)現(xiàn)
這篇文章主要介紹了vue登錄以及權(quán)限驗(yàn)證相關(guān)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Vue+java實(shí)現(xiàn)時(shí)間段的搜索示例
本文主要介紹了Vue+java實(shí)現(xiàn)時(shí)間段的搜索示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
el-table樹(shù)形表格表單驗(yàn)證(列表生成序號(hào))
這篇文章主要介紹了el-table樹(shù)形表格表單驗(yàn)證(列表生成序號(hào)),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
vue如何在用戶(hù)要關(guān)閉當(dāng)前網(wǎng)頁(yè)時(shí)彈出提示的實(shí)現(xiàn)
這篇文章主要介紹了vue如何在用戶(hù)要關(guān)閉當(dāng)前網(wǎng)頁(yè)時(shí)彈出提示的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
vue使用screenfull插件實(shí)現(xiàn)全屏功能
這篇文章主要為大家詳細(xì)介紹了vue使用screenfull插件實(shí)現(xiàn)全屏功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-09-09
vue移動(dòng)端使用appClound拉起支付寶支付的實(shí)現(xiàn)方法
這篇文章主要介紹了vue移動(dòng)端使用appClound拉起支付寶支付的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11

