簡單的說,在vue中咱們使用模板HTML語法來組建頁面的,使用render函數咱們能夠用js語言來構建DOM。由於vue是虛擬DOM,因此在拿到template模板時也要轉譯成VNode的函數,而用render函數構建DOM,vue就免去了轉譯的過程。javascript
當使用render函數描述虛擬DOM時,vue提供一個函數,這個函數是就構建虛擬DOM所須要的工具。官網上給他起了個名字叫createElement。還有約定它的簡寫叫hhtml
【1】使用組件的形式vue
// 父組件 <template> <div> <child1 :level='level'>我是標題</child1> </div> </template> <script> const child1 = () => import("./child1.vue"); export default { components: { child1 }, data() { return { level: 1 }; }, }; </script>複製代碼
// 子組件 child1.vue <template> <div> <h1 v-if="level == 1"> <slot></slot> </h1> <h2 v-if="level == 2"> <slot></slot> </h2> <h3 v-if="level == 3"> <slot></slot> </h3> <h4 v-if="level == 4"> <slot></slot> </h4> <h5 v-if="level == 5"> <slot></slot> </h5> <h6 v-if="level == 6"> <slot></slot> </h6> </div> </template> <script> export default { props: { level: { require: true, type: Number, } } }; </script>複製代碼
【2】使用render函數的形式(修改child1子組件)java
<script> export default { props: { level: { require: true, type: Number, } }, render(createElement) { return createElement('h' + this.level, this.$slots.default); } }; </script>複製代碼
對比兩種實現方式,咱們發現這裏用模板並非最好的選擇,不但代碼冗長,並且在每個級別的標題中重複書寫了<slot></slot>。 使用render函數實現看起來簡單多了,這樣代碼精簡不少,可是須要很是熟悉 Vue 的實例屬性。在這個例子中,你須要知道,向組件中傳遞不帶v-slot指令的子節點時,好比child1中的「我是標題」,這些子節點被存儲在組件實例中的this.$slots.default中。git
render 函數即渲染函數,它是個函數,render 函數的返回值是VNode(即:虛擬節點,也就是咱們要渲染的節點)
createElement 是 render 函數的參數,它自己也是個函數,而且有三個參數。接來下咱們重點介紹這三個參數github
【1】createElement 第一個參數是必填的,能夠是String | Object | Function express
示例:數組
render: function (createElement) {
// String
return createElement('h1');
//Object
return createElement({
template: " <div>鋤禾日當午</div> "
})
// Function
let domFun = function () {
return {
template: " <div> 鋤禾日當午</div> "
}
}
return createElement(domFun())
}複製代碼
【2】createElement 第二個參數是選填的,一個與模板中屬性對應的數據對象 經常使用的有class | style | attrs | domProps | onbash
return createElement('div', {
// 與 `v-bind:class` 的 API 相同,
// 接受一個字符串、對象或字符串和對象組成的數組
'class': {
foo: true,
bar: false
},
// 與 `v-bind:style` 的 API 相同,
// 接受一個字符串、對象,或對象組成的數組
style: {
color: 'red',
fontSize: '14px'
},
// 普通的 HTML 特性
attrs: {
id: 'foo'
},
// 組件 prop
props: {
myProp: 'bar'
},
// DOM 屬性
domProps: {
innerHTML: 'baz'
},
// 事件監聽器在 `on` 屬性內,
// 但再也不支持如 `v-on:keyup.enter` 這樣的修飾器。
// 須要在處理函數中手動檢查 keyCode。
on: {
click: this.clickHandler
},
// 僅用於組件,用於監聽原生事件,而不是組件內部使用
// `vm.$emit` 觸發的事件。
nativeOn: {
click: this.nativeClickHandler
},
// 自定義指令。注意,你沒法對 `binding` 中的 `oldValue`
// 賦值,由於 Vue 已經自動爲你進行了同步。
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',
// 其它特殊頂層屬性
key: 'myKey',
ref: 'myRef',
// 若是你在渲染函數中給多個元素都應用了相同的 ref 名,
// 那麼 `$refs.myRef` 會變成一個數組。
refInFor: true
})複製代碼
【3】createElement 第三個參數是選填的,表明子級虛擬節點 (VNodes),由 `createElement()` 構建而成,正常來說接收的是一個字符串或者一個數組,通常數組用的是比較多的dom
return createElement('div', {
attrs: {
id: "content"
}
}, [
createElement('h1', '我是H1標題'),
createElement('h6', '我是H6標題')
]
)複製代碼
在render函數中,沒有提供v-model的實現,因此你必須本身實現相應的邏輯。這就是深刻底層的代價,但與v-model相比,這可讓你更好地控制交互細節。
<template> <div> <child1 :name='name' v-model="name"></child1> <p>{{name}}</p> </div> </template> <script> const child1 = () => import("./child1.vue"); export default { components: { child1 }, data() { return { name: 'Demi' }; }, }; </script>複製代碼
// child1子組件 <script> export default { props: { name: { require: true, } }, render(createElement) { let self = this return createElement('input', { domProps: { value: self.name }, on: { input(event) { self.$emit('input', event.target.value) } } }) } }; </script>複製代碼
結果以下:
render函數經過input方法實現數據雙向綁定,當子組件name改變,父組件也隨着更新
對於.passive,.capture, .once 這些事件修飾符, Vue 提供了相應的前綴能夠用於 on
修飾符 | 前綴 |
---|---|
.passive |
& |
.capture |
! |
.once |
~ |
.capture.once 或.once.capture |
~! |
on: {
'!click': this.doThisInCapturingMode,
'~keyup': this.doThisOnce,
'~!mouseover': this.doThisOnceInCapturingMode
}複製代碼
JSX就是Javascript和XML結合的一種格式。React發明了JSX,利用HTML語法來建立虛擬DOM。當遇到<,JSX就當HTML解析,遇到{就當JavaScript解析。
複雜的render函數書寫異常痛苦,這就是爲何會有一個Babel插件,用於在 Vue 中使用 JSX 語法,它可讓咱們回到更接近於模板的語法上。
render(h) {
return (
<Child1 level={1}>
<span>Hello</span> world!
</Child1>
)
}複製代碼
將h做爲createElement的別名是 Vue 生態系統中的一個通用慣例,實際上也是 JSX 所要求的。從 Vue 的 Babel 插件的3.4.0版本開始,咱們會在以 ES2015 語法聲明的含有 JSX 的任何方法和 getter 中 (不是函數或箭頭函數中) 自動注入const h = this.$createElement,這樣你就能夠去掉(h)參數了。對於更早版本的插件,若是h在當前做用域中不可用,應用會拋錯。