vue 的 Render 函數(shù)
一、節(jié)點、樹以及虛擬 DOM
<div> <h1>My title</h1> Some text content <!-- TODO: Add tagline --> </div>
每個元素都是一個節(jié)點。每段文字也是一個節(jié)點。甚至注釋也都是節(jié)點。一個節(jié)點就是頁面的一個部分。就像家譜樹一樣,每個節(jié)點都可以有孩子節(jié)點 (也就是說每個部分可以包含其它的一些部分)。
高效地更新所有這些節(jié)點會是比較困難的,不過所幸你不必手動完成這個工作。你只需要告訴 Vue 你希望頁面上的 HTML 是什么,這可以是在一個模板里:
<h1>{{ blogTitle }}</h1>
或者一個渲染函數(shù)里:
render: function (createElement) { return createElement('h1', this.blogTitle) }
在這兩種情況下,Vue 都會自動保持頁面的更新,即便 blogTitle 發(fā)生了改變。
二、虛擬 DOM
Vue 通過建立一個虛擬 DOM 來追蹤自己要如何改變真實 DOM。請仔細(xì)看這行代碼:
return createElement('h1', this.blogTitle)
createElement
到底會返回什么呢?其實不是一個實際的 DOM 元素。它更準(zhǔn)確的名字可能是 createNodeDescription
,因為它所包含的信息會告訴 Vue 頁面上需要渲染什么樣的節(jié)點,包括及其子節(jié)點的描述信息。我們把這樣的節(jié)點描述為“虛擬節(jié)點 (virtual node
)”,也常簡寫它為“VNode
”?!疤摂M DOM”是我們對由 Vue 組件樹建立起來的整個 VNode 樹的稱呼。
// @returns {VNode} createElement( // {String | Object | Function} // 一個 HTML 標(biāo)簽名、組件選項對象,或者 // resolve 了上述任何一種的一個 async 函數(shù)。必填項。 'div', // {Object} // 一個與模板中 attribute 對應(yīng)的數(shù)據(jù)對象??蛇x。 { // (詳情見下一節(jié)) }, // {String | Array} // 子級虛擬節(jié)點 (VNodes),由 `createElement()` 構(gòu)建而成, // 也可以使用字符串來生成“文本虛擬節(jié)點”。可選。 [ '先寫一些文字', createElement('h1', '一則頭條'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
2.1 深入數(shù)據(jù)對象
在渲染函數(shù)中,一些模板屬性會在Vnode數(shù)據(jù)對象中有頂層字段,同時對象也允許綁定普通的屬性,也允許綁定如 innerHTML
這樣的 DOM property
(這會覆蓋 v-html 指令)。
{ // 與 `v-bind:class` 的 API 相同, // 接受一個字符串、對象或字符串和對象組成的數(shù)組 'class': { foo: true, bar: false }, // 與 `v-bind:style` 的 API 相同, // 接受一個字符串、對象,或?qū)ο蠼M成的數(shù)組 style: { color: 'red', fontSize: '14px' }, // 普通的 HTML attribute attrs: { id: 'foo' }, // 組件 prop props: { myProp: 'bar' }, // DOM property domProps: { innerHTML: 'baz' }, // 事件監(jiān)聽器在 `on` 內(nèi), // 但不再支持如 `v-on:keyup.enter` 這樣的修飾器。 // 需要在處理函數(shù)中手動檢查 keyCode。 on: { click: this.clickHandler }, // 僅用于組件,用于監(jiān)聽原生事件,而不是組件內(nèi)部使用 // `vm.$emit` 觸發(fā)的事件。 nativeOn: { click: this.nativeClickHandler }, // 自定義指令。注意,你無法對 `binding` 中的 `oldValue` // 賦值,因為 Vue 已經(jī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) }, // 如果組件是其它組件的子組件,需為插槽指定名稱 slot: 'name-of-slot', // 其它特殊頂層 property key: 'myKey', ref: 'myRef', // 如果你在渲染函數(shù)中給多個元素都應(yīng)用了相同的 ref 名, // 那么 `$refs.myRef` 會變成一個數(shù)組。 refInFor: true }
2.2 約束
VNode 必須唯一
組件樹中的所有 VNode
必須是唯一的。這意味著,下面的渲染函數(shù)是不合法的:
render: function (createElement) { var myParagraphVNode = createElement('p', 'hi') return createElement('div', [ // 錯誤 - 重復(fù)的 VNode myParagraphVNode, myParagraphVNode ]) }
如果你真的需要重復(fù)很多次的元素/組件,你可以使用工廠函數(shù)來實現(xiàn)。例如,下面這渲染函數(shù)用完全合法的方式渲染了 20 個相同的段落:
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ù)就不會提供專有的替代方法。比如,在模板中使用的 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
來重寫:
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ù)中沒有與 v-model
的直接對應(yīng)——你必須自己實現(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) } } }) }
這就是深入底層的代價,但與 v-model
相比,這可以讓你更好地控制交互細(xì)節(jié)。
3.3 事件 & 按鍵修飾符
對于 .passive
、.capture
和 .once
這些事件修飾符,Vue 提供了相應(yīng)的前綴可以用于 on:
例如:
on: { '!click': this.doThisInCapturingMode, '~keyup': this.doThisOnce, '~!mouseover': this.doThisOnceInCapturingMode }
對于所有其它的修飾符,私有前綴都不是必須的,因為你可以在事件處理函數(shù)中使用事件方法:
這里是一個使用所有修飾符的例子:
on: { keyup: function (event) { // 如果觸發(fā)事件的元素不是事件綁定的元素 // 則返回 if (event.target !== event.currentTarget) return // 如果按下去的不是 enter 鍵或者 // 沒有同時按下 shift 鍵 // 則返回 if (!event.shiftKey || event.keyCode !== 13) return // 阻止 事件冒泡 event.stopPropagation() // 阻止該元素默認(rèn)的 keyup 事件 event.preventDefault() // ... } }
3.4 插槽
你可以通過 this.$slots
訪問靜態(tài)插槽的內(nèi)容,每個插槽都是一個 VNode
數(shù)組:
render: function (createElement) { // `<div><slot></slot></div>` return createElement('div', this.$slots.default) }
也可以通過 this.$scopedSlots
訪問作用域插槽,每個作用域插槽都是一個返回若干 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ù)對象中的 scopedSlots
字段:
render: function (createElement) { // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>` return createElement('div', [ createElement('child', { // 在數(shù)據(jù)對象中傳遞 `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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue登錄以及權(quán)限驗證相關(guān)的實現(xiàn)
這篇文章主要介紹了vue登錄以及權(quán)限驗證相關(guān)的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10vue如何在用戶要關(guān)閉當(dāng)前網(wǎng)頁時彈出提示的實現(xiàn)
這篇文章主要介紹了vue如何在用戶要關(guān)閉當(dāng)前網(wǎng)頁時彈出提示的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05vue移動端使用appClound拉起支付寶支付的實現(xiàn)方法
這篇文章主要介紹了vue移動端使用appClound拉起支付寶支付的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11