父組件模板的內容在父組件做用域內編譯;子組件模板的內容在子組件做用域內編譯。
父子組件的編譯相互獨立,編譯時只能使用各自做用域中的屬性和方法,例如,你不能夠在父組件模板內,將一個指令綁定到子組件的屬性或方法上。若是這麼作控制檯會報一個屬性未定義的錯誤。javascript
若是想要綁定一個指令以便控制子組件的行爲,那麼你能夠在子組件的模板內,將一個指令綁定到子組件的屬性或方法上;或者在父組件的模板內,將指令綁定到父組件的屬性或方法上。java
new Vue({ el: '#app-2', data: { makeChildShow: true }, components: { "component-2-1": { template: '<span>I am an sub component.</span>', data: function () { return { childIsShow: true } } }, "component-2-2": { template: '<span v-show="childIsShow">I am an sub component.</span>', data: function () { return { childIsShow: true } } } } })
<div id="app-2"> <ul> <li>綁定到子組件屬性:<component-2-1 v-show="childIsShow"></component-2-1></li> <li>綁定到父組件屬性:<component-2-1 v-show="makeChildShow"></component-2-1></li> <li>在子組件模板內將指令綁定到子組件屬性:<component-2-2></component-2-2></li> </ul> </div>
列表第一項,因爲父組件找不到屬性childIsShow
,將不會顯示。es6
將父組件的內容插入子組件模板的方式,咱們稱爲內容分發。
默認狀況下,在子組件中插入的父組件內容是不顯示的。app
new Vue({ el: '#app-1', data: { message: 'I come from parent.' }, components: { "component-1": { template: '<p>I am an sub component.</p>', } } })
<div id="app-1" class="demo"> <component-1> {{ message }} </component-1> </div>
內容分發失敗,message
不會顯示。spa
若是想使用內容分發,將父組件內容插入到子組件的模板中,必須在子組件的模板內標記一個<slot>備選內容</slot>
,父組件將找到這個<slot>備選內容</slot>
標記,並將本身的內容替換<slot>備選內容</slot>
。
若是父組件沒有待分發的內容,備選內容
成爲最終渲染的結果。3d
new Vue({ el: '#app-3', components: { "component-3": { template: '\ <ul>\ <li>子組件內容</li>\ <li>子組件內容</li>\ <slot><li>插口備選內容</li></slot>\ <li>子組件內容</li>\ <li>子組件內容</li>\ </ul>' } } })
<div id="app-3"> <h5>父組件標題</h5> <component-3> <li>父組件插入內容</li> </component-3> </div>
單插口模式作內容分發,只能一股腦把套入子模板的內容插入到有<slot></slot>
標記的地方。
而具名插口在內容和slot
上都作上標記,對應的內容只能分發到對應的slot
上。
標記內容用slot="tag"
; 標記slot
用 <slot name="tag">
code
new Vue({ el: '#app-4', components: { "component-4": { template: '\ <div>\ <header>\ <slot name="header"></slot>\ </header>\ <article>\ <slot></slot>\ </article>\ <footer>\ <slot name="footer"></slot>\ </footer>\ <section><slot></slot></section>\ </div>' } } })
<div id="app-4"> <component-4> <h5 slot="header">我來組成頭部</h5> <p>沒被標記的slot都我插</p> <div slot="footer">我來組成腿部</div> </component-4> </div>
以上定義了兩個個不具名的插口,雖然這裏顯示正確,可是控制檯報錯,說定義重複的默認插口會有不預期的錯誤component
根據具名插口,再來看個組件做用域的例子對象
new Vue({ el: '#app-7', methods: { parentMethod: function () { console.log("It is the parent's method"); } }, components:{ "component-7":{ methods:{ childMethod: function(){ console.log("It is the child's method") } }, template:"\ <button>\ <slot name='first'></slot>\ <span @click='childMethod'>子組件模板定義部分①|</span>\ <slot name='second'></slot>\ <span @click='childMethod'>子組件模板定義部分②</span>\ </button>" } } })
<div id="app-7"> <component-7> <span slot="first" @click="parentMethod">內容分發部分①|</span> <span slot="second" @click="parentMethod">內容分發部分②|</span> </component-7> </div>
內容分發部分屬於父組件做用域,所以點擊按鈕的內容分發部分,會調用父組件方法,輸出"It is the parent's method"
。
子組件模板定義屬於子組件做用域,點擊這個部分,會調用子組件方法,輸出"It is the child's method"
blog
在內容分發的過程當中,父組件分發的內容可使用定義在子組件模板<slot>
上的屬性(即插口做用域上定義的屬性)。如<slot slotval="值"></slot>
,在父組件分發內容上,能夠經過slot-scope="obj"
獲取到全部在插口上定義的屬性,經過{{obj.slotval}}
就能夠在slot-scope
內部使用這個數據。
特殊的,在<template>
標籤中使用slot-scope
,<template>
自身是不會在頁面上顯示,只起到傳遞數據媒介的做用。
new Vue({ el: '#app-5', components: { "component-5":{ template: '<div class="child">\ <slot slotvala="a、來自插口做用域上的數據" slotvalb="b、來自插口做用域上的數據"></slot>\ </div>' } } })
<div id="app-5"> <component-5> <!--這裏能夠是其餘標籤,但會被渲染到頁面,如<div slot-scope="">--> <template slot-scope="slot_data_obj"> <span>{{slot_data_obj.slotvala}}</span> <span>{{slot_data_obj.slotvalb}}</span> </template> </component-5> </div>
因爲slot-scope的值本質上只是個javascript對象,所以可使用es6的解構語法進行<slot>
屬性的映射。
以上又能夠怎麼寫
<template slot-scope="{slotvala,slotvalb}"> <span>{{slotvala}}</span> <span>{{slotvalb}}</span> </template>
插口不只能夠經過自身屬性傳遞數據給分發的內容,還能夠在其上定義v-for
指令,從而將迭代的特性也傳遞給分發的內容。
new Vue({ el: '#app-6', components: { "component-6":{ data:function(){ return { items: [ {id:1,text:"哪都通快遞"}, {id:2,text:"龍虎山天師府"}, {id:3,text:"曜星社"} ] } }, template: '\ <ul>\ <slot name="item" v-for="item in items" v-bind:text="item.text" v-bind:id="item.id"></slot>\ </ul>' } } })
<div id="app-6"> <component-6> <li slot="item" slot-scope="{text,id}"> {{ id+"、"+text }} </li> </component-6> </div>
內容分發中的<li>
被插入slot
中,而且由於slot
中的v-for
指令而進行迭代,迭代以後經過slot-scope
獲取slot
上的屬性數據。
當使用子組件的內聯特性——inline-template
時,父組件的內容分發部分就被解釋爲子組件的模板,而子組件的template
屬性也將被這個部分取代(取代後template
失效),而且做用域也屬於子組件。
new Vue({ el:'#app-8', components:{ 'component-8':{ template:'...'//所有被替換 data:function(){ return { childMsg:'child\'s data' } } } } })
<div id="app-8"> <component-8 inline-template> <div> <p>這些將做爲組件自身的模板。</p> <p>而非父組件透傳進來的內容。</p> <p>子組件數據: {{ childMsg }}</p> </div> </component-8> </div>
"child's data"
來自子組件的childMsg
因爲其特色,在使用內聯模板時,最容易產生的誤區就是混淆做用域。