Vue.js(六)—— 元件: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>