一,el,template,render屬性優先性
當Vue選項對象中有render渲染函數時,Vue構造函數將直接使用渲染函數渲染DOM樹,當選項對象中沒有render渲染函數時,Vue構造函數首先通過將template模板編譯生成渲染函數,然后再渲染DOM樹,而當Vue選項對象中既沒有render渲染函數,也沒有template模板時,會通過el屬性獲取掛載元素的outerHTML來作為模板,並編譯生成渲染函數。
換言之,在進行DOM樹的渲染時,render渲染函數的優先級最高,template次之且需編譯成渲染函數,而掛載點el屬性對應的元素若存在,則在前兩者均不存在時,其outerHTML才會用於編譯與渲染。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="vue.js"></script> </head> <body> <div class="vapp-1">{{ info }}</div> <div class="vapp-2">{{ info }}</div> <div class="vapp-3">{{ info }}</div> <script> new Vue({ el: '.vapp-1', data: { info: '這是通過el屬性獲取掛載元素的outerHTML方式渲染。' }, template: '<div>這是template屬性模板渲染。</div>', render: function (h) { return h('div', {}, '這是render屬性方式渲染。') } }) new Vue({ el: '.vapp-2', data: { info: '這是通過el屬性獲取掛載元素的outerHTML方式渲染。' }, template: '<div>這是template屬性模板渲染。</div>' }) new Vue({ el: '.vapp-3', data: { info: '這是通過el屬性獲取掛載元素的outerHTML方式渲染。' } }) </script> </body> </html>
渲染結果:
二,template的三種寫法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="vue.js"></script> </head> <body> <div id="app1"></div> <div id="app2"></div> <div id="app3"></div> <script type="text/x-template" id="tem"> <div> <h1>{{message}}</h1> </div> </script> <template id="tem_t"> <div> <h1>{{message}}</h1> </div> </template> <script> //第一種(使用模板字符串) new Vue({ el: "#app1", template: '<div>\ <h1>{{message}}</h1>\ </div>', data: { message: '字符串拼接' } }) //第二種(使用script元素) new Vue({ el: "#app2", template: '#tem', data: { message: '使用script元素' } }) //第三種(使用template元素) new Vue({ el: "#app3", template: '#tem_t', data: { message: '使用template元素' } }) </script> </body> </html>
渲染結果:
三,render渲染函數
vue一般使用template來創建HTML,然后在有的時候,我們需要使用javascript來創建html,這時候我們需要使用render函數
例如:我現在要寫一個根據不同level顯示不同級別的標題
<div id="container"> <tb-heading :level="1"> <a href="#">Hello world!</a> </tb-heading> </div>
用render函數實現:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="vue.js"></script> </head> <body> <div id="container"> <tb-heading :level="level"> <a href="#">Hello world!</a> </tb-heading> </div> <script> //寫組件 Vue.component('tb-heading', { render: function (createElement) { return createElement( 'h' + this.level, // tag name 標簽名稱 this.$slots.default // 組件的子元素 ) }, props: { level: { type: Number, required: true } } }); new Vue({ el: "#container", data:{ level:2, } }) </script> </body> </html>
渲染結果:
四,render函數中的creatElement參數
createElement
接受的參數:
// @returns {VNode} createElement( // {String | Object | Function} // 一個 HTML 標簽名、組件選項對象,或者 // resolve 了上述任何一種的一個 async 函數。必填項。 'div', // {Object} // 一個與模板中 attribute 對應的數據對象。可選。 { // (詳情見下一節) }, // {String | Array} // 子級虛擬節點 (VNodes),由 `createElement()` 構建而成, // 也可以使用字符串來生成“文本虛擬節點”。可選。 [ '先寫一些文字', createElement('h1', '一則頭條'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
createElement的第二個參數的參數:深入數據對象
{ // 與 `v-bind:class` 的 API 相同, // 接受一個字符串、對象或字符串和對象組成的數組 'class': { foo: true, bar: false }, // 與 `v-bind:style` 的 API 相同, // 接受一個字符串、對象,或對象組成的數組 style: { color: 'red', fontSize: '14px' }, // 普通的 HTML attribute attrs: { id: 'foo' }, // 組件 prop props: { myProp: 'bar' }, // DOM property 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', // 其它特殊頂層 property key: 'myKey', ref: 'myRef', // 如果你在渲染函數中給多個元素都應用了相同的 ref 名, // 那么 `$refs.myRef` 會變成一個數組。 refInFor: true }
實現如下例子:
<ul v-if="items.length"> <li v-for="item in items">{{ item.name }}</li> </ul> <p v-else>No items found.</p>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="vue.js"></script> </head> <body> <div id="container"> <cm-ul :items="items"></cm-ul> </div> <script> //寫組件 Vue.component('cm-ul', { render: function (createElement) { //if-else判斷 if (this.items.length) { return createElement('ul', this.items.map(function (item) { return createElement('li', item.name) })) } else { return createElement('p', 'No items found.') } }, props: { items: { items:Array } } }); new Vue({ el: "#container", data: { items: [{name:'華為'},{name:'小米'},{name:'華為'}], } }) </script> </body> </html>
渲染結果: