1. 程式人生 > >Vue學習筆記入門篇——組件的內容分發(slot)

Vue學習筆記入門篇——組件的內容分發(slot)

節點 pan 如何 new 深入 接收 span 初始 特殊屬性

本文為轉載,原文:Vue學習筆記入門篇——組件的內容分發(slot)

介紹

為了讓組件可以組合,我們需要一種方式來混合父組件的內容與子組件自己的模板。這個過程被稱為 內容分發 (或 “transclusion” 如果你熟悉 Angular)。Vue.js 實現了一個內容分發 API,使用特殊的 ‘slot’ 元素作為原始內容的插槽。

編譯作用域

在深入內容分發 API 之前,我們先明確內容在哪個作用域裏編譯。假定模板為:

<child-component>
    {{ message }}
</child-component>

message 應該綁定到父組件的數據,還是綁定到子組件的數據?答案是父組件。組件作用域簡單地說是:

父組件模板的內容在父組件作用域內編譯;
子組件模板的內容在子組件作用域內編譯。

一個常見錯誤是試圖在父組件模板內將一個指令綁定到子組件的屬性/方法:

<!-- 無效 -->
<child-component v-show="someChildProperty"></child-component>

假定 someChildProperty 是子組件的屬性,上例不會如預期那樣工作。父組件模板不應該知道子組件的狀態。
如果要綁定作用域內的指令到一個組件的根節點,你應當在組件自己的模板上做:

Vue.component(‘child-component‘, {
  // 有效,因為是在正確的作用域內
  template: ‘<div v-show="someChildProperty">Child</div>‘,
  data: function () {
    return {
      someChildProperty: true
    }
  }
})

類似地,分發內容是在父作用域內編譯。

單個slot

除非子組件模板包含至少一個 ‘slot’ 插口,否則父組件的內容將會被丟棄。當子組件模板只有一個沒有屬性的 slot 時,父組件整個內容片段將插入到 slot 所在的 DOM 位置,並替換掉 slot 標簽本身。
最初在 ‘slot’ 標簽中的任何內容都被視為備用內容。備用內容在子組件的作用域內編譯,並且只有在宿主元素為空,且沒有要插入的內容時才顯示備用內容。
示例代碼:

<div id="app">
    <h1>我是父組件的標題</h1>
    <my-component>
        <p>初始內容1</p>
        <p>初始內容2</p>
    </my-component>
</div>
Vue.component(‘my-component‘,{
    template:`
    <div>
        <h2>我是子組件的標題</h2>
        <slot>
            只有在沒有要分發的內容是才出現。
        </slot>
    <div>
`,
})
new Vue({
    el:‘#app‘
})

運行結果如下:
技術分享
將html部分代碼修改為以下代碼:

<div id="app">
    <h1>我是父組件的標題</h1>
    <my-component>
    </my-component>
</div>

則運行結果如下:
技術分享

具名slot

‘slot’ 元素可以用一個特殊的屬性 name 來配置如何分發內容。多個 slot 可以有不同的名字。具名 slot 將匹配內容片段中有對應 slot 特性的元素。
仍然可以有一個匿名 slot,它是默認 slot,作為找不到匹配的內容片段的備用插槽。如果沒有默認的 slot,這些找不到匹配的內容片段將被拋棄。
如以下例子:

<div id="app">
    <my-component>
        <h1 slot="header">這是標題</h1>
        <p>第一個段落</p>
        <p>第二個段落</p>
        <p>第三個段落</p>
        <p slot="footer">聯系信息</p>
    </my-component>
</div>
Vue.component(‘my-component‘,{
    template:`
    <div class="container">
        <header>
            <slot name="header"></slot>
        </header>
        <main>
            <slot></slot>
        </main>
        <footer>
            <slot name="footer"></slot>
        </footer>
    <div>
`,
})
new Vue({
    el:‘#app‘
})

運行結果如下:
技術分享
在組合組件時,內容分發 API 是非常有用的機制。

作用域插槽

2.1.0新增

作用域插槽是一種特殊類型的插槽,用作使用一個 (能夠傳遞數據到) 可重用模板替換已渲染元素。
在子組件中,只需將數據傳遞到插槽,就像你將 props 傳遞給組件一樣。
示例代碼:

<div id="app">
    <my-component>
        <template scope="props">
            <p>hello from parent</p>
            <p>{{props.text}}</p>
        </template>
    </my-component>
</div>
Vue.component(‘my-component‘,{
    template:`
    <div class="child">
        <slot text="hello from child"></slot>
    <div>
`,
    props:[‘text‘]
})
new Vue({
    el:‘#app‘
})

運行結果:
技術分享
在父級中,具有特殊屬性 scope 的 <’template’> 元素必須存在,表示它是作用域插槽的模板。scope 的值對應一個臨時變量名,此變量接收從子組件中傳遞的 props 對象。

作用域插槽更具代表性的用例是列表組件,允許組件自定義應該如何渲染列表每一項:

<div id="app">
    <my-component :items="items">
        <template slot="item" scope="props">
            <li>{{props.text}}</li>
        </template>
    </my-component>
</div>
Vue.component(‘my-component‘,{
    template:`
    <ul>
        <slot name="item" v-for="item in items" :text="item.text"></slot>
    </ul>
`,
    props:[‘text‘,‘items‘]
})
new Vue({
    el:‘#app‘,
    data:{
        items:[
            {text:‘item1‘},
            {text:‘item2‘},
            {text:‘item3‘},
        ]
    }
})

作用域插槽也可以是具名的
運行結果:
技術分享

本文為原創,轉載請註明出處。
上一節:Vue學習筆記入門篇——組件的通訊
返回目錄
下一節:Vue學習筆記入門篇——組件雜項

Vue學習筆記入門篇——組件的內容分發(slot)