Vue Slots

Vue:2.5

Slot 是一種 內容分配(Content Distribution) 的元件。通常在實務使用上,元件應用錯綜複雜,元件包著元件使用是常見的問題,而 Slot 就像一種插槽,可以將你想要的內容直接嵌入預留的空間。

基本使用

在使用 Slot 之前,要先瞭解 編譯作用域(Compilation Scope),不然很容易搞錯變數。

就先以一個簡單的範例熟悉一下 Slot 操作。

以下範例為製作 sayhello 元件,say 傳入 hello 元件,而 hello 則是傳入 vm.name

範例

<div id="app">
    <!-- 傳入 hello 元件-->
    <say>
        <!-- 在這個階段,都是使用 Vue-Model 的變數(傳入 vm.name) -->
        <hello>{{ name }}</hello>
    </say>
</div>
Vue.component('say', {
    template: `
        <div class="say">
            <h1>Say Component</h1>
            <!-- Slot 預留空間,可以傳入語言元件 -->
            <slot></slot>
        </div>
    `
});

Vue.component('hello', {
    template: `
        <div class="hello">
            <h3>Hello Component</h3>
            <p>
                <!-- Slot 預留空間,可以傳入人名 -->
                Hello,<slot></slot>
            </p>
        </div>
    `
});

const vm = new Vue({
    el: '#app',
    data: {
        name: 'Johnson Lu',
    }
});

實際看產出的 HTML 應該可以比較好理解:

<div id="app">
    <div class="say">
        <h1>Say Component</h1>
        <!-- 原本的 say.slot 被填入 hello 元件 -->
        <div class="hello">
            <h3>Hello Component</h3>
            <!-- 原本的 hello.slot 被填入人名 -->
            <p>Hello,Johnson Lu</p>
        </div>
    </div>
</div>

既然是插槽,當沒有傳入任何東西時,可以指定預設值。
範例

<div id="app">
    <say></say>
</div>
Vue.component('say', {
    template: `
        <div class="say">
            <h1>Say Component</h1>
            <!-- Slot 預留空間 -->
            <slot>我無話可說</slot>
        </div>
    `
});

Named Slots

上面提到的 Slot 例子,都是按照順序去填入,但如果自己不是元件的作者,在溝通上面就顯得困難。因此就要透過具名的 Slot 定義標準,讓大家知道怎麼把想要的資料填入 Slot

範例

<div id="app">
    <mail>
        <h4 slot="subject">You're fired</h4>
        <p slot="content">
            太不乖惹
        </p>
    </mail>
</div>
Vue.component('mail', {
    template: `
        <div class="mail">
            <slot name="subject">信件標題</slot>
            <slot name="content">
                信件內容
            </slot>
            <slot name="footer">Best regards</slot>
        </div>
    `
});

const vm = new Vue({
    el: '#app',
    data: {}
});

Scoped Slots

最後,Slot 可以做大範圍的宣告和資料傳遞,方法很類似元件的 Props Down,最常見的例子就是動態產生清單。

先看一個基本資料傳遞的範例:

<div id="app">
    <hello>
        <!-- 透過 <template> 宣告 slot name 及要使用 slot 的 data-->
        <template slot="say" scope="props">
            <span>{{ props.message }}</span>
        </template>
    </hello>
</div>
Vue.component('hello', {
    data: function () {
        return {
            message: 'Hello JohnsonLu'
        }
    },
    template: `
        <div>
            <!-- Slot 預設先 bind message -->
            <slot name="say" :message="message"></slot>
        </div>
    `
});

我們要插入的 Slot 內容為 <span> Data </span>,而其中 Data 是設定在 Component 的變數,因此需要透過宣告 scope="props" 將變數代出來使用。

動態產生清單的範例:

<div id="app">
    <!-- Pass Props 給 component -->
    <list :items="items">
        <!-- 透過 template 宣告這是 Scoped Slots 的範圍,並且要使用 Props 的變數-->
        <template slot="item" scope="props">
            <!-- 使用 slot 的 text -->
            <li>@{{ props.text }}</li>
        </template>
    </list>
</div>
Vue.component('list', {
    props: ['items'],
    template: `
        <ul>
            <!-- 用 v-for 爬出資料,並寫入 bind text -->
            <slot name="item" v-for="item in items" :text="item.text"></slot>
        </ul>
    `
});

const vm = new Vue({
    el: '#app',
    data: {
        items: [
            {id: 1, text: 'Hello'},
            {id: 2, text: 'Hey'},
            {id: 3, text: 'Haha'}
        ]
    }
});
Categories: Vue