官網描述的場景當咱們開始寫一個經過 level prop 動態生成 heading 標籤的組件,你可能很快想到這樣實現:html
<script type="text/x-template" id="anchored-heading-template"> <h1 v-if="level === 1"> <slot></slot> </h1> <h2 v-else-if="level === 2"> <slot></slot> </h2> <h3 v-else-if="level === 3"> <slot></slot> </h3> <h4 v-else-if="level === 4"> <slot></slot> </h4> <h5 v-else-if="level === 5"> <slot></slot> </h5> <h6 v-else-if="level === 6"> <slot></slot> </h6> </script> Vue.component('anchored-heading', { template: '#anchored-heading-template', props: { level: { type: Number, required: true } } })
在這種場景中使用 template 並非最好的選擇:首先代碼冗長,爲了在不一樣級別的標題中插入錨點元素,咱們須要重複地使用 <slot></slot>。java
雖然模板在大多數組件中都很是好用,可是在這裏它就不是很簡潔的了。那麼,咱們來嘗試使用 render 函數重寫上面的例子:express
Vue.component('anchored-heading', { render: function (createElement) { return createElement( 'h' + this.level, // tag name 標籤名稱 this.$slots.default // 子組件中的陣列 ) }, props: { level: { type: Number, required: true } } })
簡單清晰不少!簡單來講,這樣代碼精簡不少,可是須要很是熟悉 Vue 的實例屬性。在這個例子中,你須要知道當你不使用 slot 屬性向組件中傳遞內容時,好比 anchored-heading 中的 Hello world!,這些子元素被存儲在組件實例中的 $slots.default中。api
createElement參數介紹數組
接下來你須要熟悉的是如何在 createElement 函數中生成模板。這裏是 createElement 接受的參數:app
createElement( // {String | Object | Function} // 一個 HTML 標籤字符串,組件選項對象,或者 // 解析上述任何一種的一個 async 異步函數,必要參數。 'div', // {Object} // 一個包含模板相關屬性的數據對象 // 這樣,您能夠在 template 中使用這些屬性。可選參數。 { // (詳情見下一節) }, // {String | Array} // 子節點 (VNodes),由 `createElement()` 構建而成, // 或使用字符串來生成「文本節點」。可選參數。 [ '先寫一些文字', createElement('h1', '一則頭條'), createElement(MyComponent, { props: { someProp: 'foobar' } }) ] )
深刻 data 對象dom
有一件事要注意:正如在模板語法中,v-bind:class 和 v-bind:style ,會被特別對待同樣,在 VNode 數據對象中,下列屬性名是級別最高的字段。該對象也容許你綁定普通的 HTML 特性,就像 DOM 屬性同樣,好比 innerHTML (這會取代 v-html 指令)。ssh
{ // 和`v-bind:class`同樣的 API 'class': { foo: true, bar: false }, // 和`v-bind:style`同樣的 API style: { color: 'red', fontSize: '14px' }, // 正常的 HTML 特性 attrs: { id: 'foo' }, // 組件 props 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 } } ], // Scoped slots in the form of // { name: props => VNode | Array<VNode> } scopedSlots: { default: props => createElement('span', props.text) }, // 若是組件是其餘組件的子組件,需爲插槽指定名稱 slot: 'name-of-slot', // 其餘特殊頂層屬性 key: 'myKey', ref: 'myRef' }
條件渲染異步
既然熟讀以上api接下來我們就來點實戰。async
以前這樣寫
//HTML <div id="app"> <div v-if="isShow">我被你發現啦!!!</div> </div> <vv-isshow :show="isShow"></vv-isshow> //js //組件形式 Vue.component('vv-isshow', { props:['show'], template:'<div v-if="show">我被你發現啦2!!!</div>', }); var vm = new Vue({ el: "#app", data: { isShow:true } });
render這樣寫
//HTML <div id="app"> <vv-isshow :show="isShow"><slot>我被你發現啦3!!!</slot></vv-isshow> </div> //js //組件形式 Vue.component('vv-isshow', { props:{ show:{ type: Boolean, default: true } }, render:function(h){ if(this.show ) return h('div',this.$slots.default); }, }); var vm = new Vue({ el: "#app", data: { isShow:true } });
列表渲染
以前是這樣寫的,並且v-for 時template內必須被一個標籤包裹
//HTML <div id="app"> <vv-aside v-bind:list="list"></vv-aside> </div> //js //組件形式 Vue.component('vv-aside', { props:['list'], methods:{ handelClick(item){ console.log(item); } }, template:'<div>\ <div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>\ </div>', //template:'<div v-for="item in list" @click="handelClick(item)" :class="{odd:item.odd}">{{item.txt}}</div>',錯誤 }); var vm = new Vue({ el: "#app", data: { list: [{ id: 1, txt: 'javaScript', odd: true }, { id: 2, txt: 'Vue', odd: false }, { id: 3, txt: 'React', odd: true }] } });
render這樣寫
//HTML <div id="app"> <vv-aside v-bind:list="list"></vv-aside> </div> //js //側邊欄 Vue.component('vv-aside', { render: function(h) { var _this = this, ayy = this.list.map((v) => { return h('div', { 'class': { odd: v.odd }, attrs: { title: v.txt }, on: { click: function() { return _this.handelClick(v); } } }, v.txt); }); return h('div', ayy); }, props: { list: { type: Array, default: () => { return this.list || []; } } }, methods: { handelClick: function(item) { console.log(item, "item"); } } }); var vm = new Vue({ el: "#app", data: { list: [{ id: 1, txt: 'javaScript', odd: true }, { id: 2, txt: 'Vue', odd: false }, { id: 3, txt: 'React', odd: true }] } });
v-model
以前的寫法
//HTML <div id="app"> <vv-models v-model="txt" :txt="txt"></vv-models> </div> //js //input Vue.component('vv-models', { props: ['txt'], template: '<div>\ <p>看官你輸入的是:{{txtcout}}</p>\ <input v-model="txtcout" type="text" />\ </div>', computed: { txtcout:{ get(){ return this.txt; }, set(val){ this.$emit('input', val); } } } }); var vm = new Vue({ el: "#app", data: { txt: '', } });
render這樣寫
//HTML <div id="app"> <vv-models v-model="txt" :txt="txt"></vv-models> </div> //js //input Vue.component('vv-models', { props: { txt: { type: String, default: '' } }, render: function(h) { var self=this; return h('div',[h('p','你猜我輸入的是啥:'+this.txt),h('input',{ on:{ input(event){ self.$emit('input', event.target.value); } } })] ); }, }); var vm = new Vue({ el: "#app", data: { txt: '', } });