1. 程式人生 > >Vue.js(六)—— 元件:slot用法

Vue.js(六)—— 元件:slot用法

目錄

一、預設情況下(不使用slot)

二、單個slot

三、具名slot

四、編譯作用域

五、預設插槽的內容

六、作用域插槽

七、訪問slot


Vue 實現了一套內容分發的 API,將 <slot> 元素作為承載分發內容的出口。

簡單來講:預設情況下我們在父元件中加入到子元件的DOM是不會顯示的,但是如果我們需要插入一段DOM,那麼這段DOM是否顯示,如何顯示,顯示在什麼位置,就需要使用slot內容分發。

一、預設情況下(不使用slot)

正常情況下我們在引用子元件時另加的標籤是不會展示的,舉例說明:

<!-- 這是父元件 father.vue 的內容 -->
<template>
    <div class='app-container'>
       <son>
          <p>這是父元件想要放到子元件裡面的內容</p>
       </son>
    </div>
</template>
<script>
import son from './son';
export default {
  components: {
    son
  },
};
</script>


<!-- 這是子元件 son.vue 的內容 -->
<template>
    <div class='app-container'>
        <p>這是一個子元件--start--</p>
        <p>這是一個子元件--end--</p>
    </div>
</template>

雖然我們在<son></son>標籤內部加入了一段HTML程式碼,但是在渲染的過程中,這段程式碼是不會顯示的。渲染結果如下:

怎麼才能顯示出父元件想要放在子元件的內容呢?這就需要用到slot內容分發。

二、單個slot

如果我們在子元件內部添加了一個<slot></slot>標籤做一個佔位,就可以將父元件想要放在子元件的內容,放到想讓他顯示的地方(即slot標籤所在的地方);也就是說:父元件放在子元件裡的內容,插入到了子元件的<slot></slot>位置。

注意,即使有多個標籤,也會一起被插入,相當於用父元件放在子元件裡的所有標籤,替換了<slot></slot>這個標籤。

如:在上述示例的 son.vue 檔案中加入slot,具體如下:

此時的渲染結果就變成了如下的結果,成功的將父元件插入在子元件內的DOM顯示了出來。

三、具名slot

給<slot>元素指定一個name後可以分發多個內容,具名slot可以和單個slot共存。

<!-- 這是父元件 father.vue 的內容 -->
<template>
    <div class='app-container'>
       <son>
          <p slot="header">這是父元件想要插入到具名slot:header的內容</p>
          <p slot="footer">這是父元件想要插入到具名slot:footer的內容</p>
       </son>
    </div>
</template>
<script>
import son from './son';
export default {
  components: {
    son
  },
};
</script>


<!-- 這是子元件 son.vue 的內容 -->
<template>
    <div class='app-container'>
        <p>這是一個子元件--start--</p>
        <slot name="header"></slot>
        <p>這是子元件本身的內容</p>
        <slot name="footer"></slot>
        <p>這是一個子元件--end--</p>
    </div>
</template>

渲染結果如下,多個標籤分別渲染到了其對應的具名slot指向的位置,而父元件中沒有指定 slot="xxx" 的標籤會被統一渲染到不單個<slot></slot>位置: 

四、編譯作用域

父元件模板的所有東西都會在父級作用域內編譯;子元件模板的所有東西都會在子級作用域內編譯。

<p slot="header"></p>受父元件的控制,如果想要呼叫某個方法,則該方法需要被定義在父元件的methods當中。 

五、預設插槽的內容

很多時候,我們可以為 slot 設定預設內容,當父元件中有內容傳入的時候,會替換該預設內容;若是父元件中不傳入任何內容,則預設內容顯示。

<!-- 這是父元件 father.vue 的內容 -->
<template>
    <div class='app-container'>
       <son>
            <!-- 父元件什麼都不傳入 -->
       </son>
    </div>
</template>
<script>
import son from './son';
export default {
  components: {
    son
  },
};
</script>


<!-- 這是子元件 son.vue 的內容 -->
<template>
    <div class='app-container'>
        <p>這是一個子元件--start--</p>
        <button>
            <slot>預設為submit按鈕</slot>
        </button>
        <p>這是一個子元件--end--</p>
    </div>
</template>

結果如下: 

 若有傳入內容,則會替換掉預設內容:

六、作用域插槽

作用域插槽是一個特殊的slot,使用一個可以複用的模板替換已渲染的元素。

6.1 具體用法:

(1)在父元件中傳入由一個 <template></template> 標籤包裹的DOM元素,並且這個 template 標籤擁有 slot-scope="props" 屬性;(props 相當於一個臨時變數,有點類似於 v-for 裡面的 item,一般叫props,可以換成任何名稱)

(2)通過props就可以訪問來自子元件slot的資料;

<!-- 這是父元件 father.vue 的內容 -->
<template>
    <div class='app-container'>
        <son>
            <template slot-scope="props">
                <p>父元件傳入的內容</p>
                <p>{{props.msg}}</p>
            </template>
        </son>
    </div>
</template>
<script>
import son from './son';
export default {
    components: {
        son
    },
};
</script>


<!-- 這是子元件 son.vue 的內容 -->
<template>
    <div class='app-container'>
        <p>這是一個子元件--start--</p>
        <slot msg="子元件傳過來的msg"></slot>
        <p>這是一個子元件--end--</p>
    </div>
</template>

結果如下:

 在 2.5.0+,slot-scope 不再限制在 <template> 元素上使用,而可以用在插槽內的任何元素或元件上。

七、訪問slot

在子元件中可以通過 this.$slots 來獲取被 slot 訪問的內容(貌似沒有用到過這個==)

<!-- 子元件 son.vue -->
<template>
    <div class='app-container'>
        <p>這是一個子元件--start--</p>
        <slot name="header">123</slot>
        <slot name="footer">123</slot>
        <slot></slot>
        <p>這是一個子元件--end--</p>
    </div>
</template>
<script>
export default {
  mounted() {
    console.log(this.$slots);    // Object 所有的slot
    console.log(this.$slots.header);       // 獲取name=header的slot
    console.log(this.$slots.footer);
    console.log(this.$slots.default);      // 獲取所有具名slot之外的slot
  }
};
</script>