閱讀之前
本文主要參照了Vue官方文檔的插槽部分說明,中間加入的自己的理解,寫的比較簡潔易懂。各位看官可以對照官方文檔和本文的介紹來理解slot插槽語法。
Vue 插槽(2.60版本以后)
插槽可以讓通用組件更加多樣化,它類似React中的children。
聲明:以下所有內(nèi)容以父級(通用)組件和應(yīng)用(調(diào)用)組件的關(guān)系舉例說明。
-
最簡單的使用
比如你想聲明一個帶有特殊border的div作為一個通用組件BorderedDiv。
<template>
<div class="some-border-class">
// 這里是包裹的不同的內(nèi)容
// 可能你很想使用this.props.children(如果你曾是React使用者)
</div>
</template>
在使用該組件時
<bordered-div>
<p>被包裹的文字</p>
</bordered-div>
這時你會想到:這個文字如何傳遞給父級組件呢?
直接這樣寫就好:
<template>
<div class="some-border-class">
// 這里是包裹的不同的內(nèi)容
<slot></slot>
</div>
</template>
-
作用域
<common-component :data="[1,2,3]">
{{ data }}
<!--
這里的 `data` 會是 undefined,因為數(shù)組是 **傳遞給**
<common-component> 的而不是 在 <common-component> 組件
**內(nèi)部**定義的
-->
</common-component >
父級模板里的所有內(nèi)容都是在父級作用域中編譯的;子模板里的所有內(nèi)容都是在子作用域中編譯的。
簡單來說:你不能在寫children的時候直接使用父級組件中的數(shù)據(jù),考慮當前環(huán)境。
-
后備內(nèi)容
在<slot></slot>標簽中的內(nèi)容將在沒有匹配到插槽內(nèi)容時渲染
<slot>如果沒有children,我就會渲染</slot>
如果父級模板中聲明了插槽,但是應(yīng)用組件卻沒有包裹任何內(nèi)容,它便會渲染為備用內(nèi)容。
-
具名
可以給<slot></slot> 傳遞name屬性
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot name="default"></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
然后這樣向?qū)?yīng)的插槽傳遞內(nèi)容:
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
// 可以不用包裹template 直接傳遞給default slot
<template v-slot:default>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
其中:<template v-slot:default>父節(jié)點可以省略。
注意:
v-slot指令只能使用在<template>上,除非只需要傳遞默認插槽。(也就是你的父級模板中只有一個沒有name屬性的插槽)
這時它可以用在父組件上。
盡管如此,它也只是<template v-slot:default></template>的縮寫。
在傳遞多個插槽時,還是需要使用完整的語法。
-
作用域插槽
在通用組件中聲明的模板如下:
<span>
// 給slot聲明了一個屬性
// 該屬性可以在對應(yīng)的插槽內(nèi)容中訪問
// 省略了 name = "default"
<slot v-bind:user="user"></slot>
</span>
在應(yīng)用組件中:
<common-component>
<!-- v-slot是v-slot:default的縮寫 -->
<template v-slot="slotProps">
// 插槽上聲明的user可以這樣訪問
{{ slotProps.user.name }}
</template>
</common-component>
在“裝載插槽”時,slot上聲明的屬性綁定的數(shù)據(jù)會以函數(shù)的參數(shù)形式傳遞給插槽
function (slotProps) {
// 插槽的內(nèi)容
}
因此可以在編寫插槽內(nèi)容時獲取到common-component(父組件)中的數(shù)據(jù)。
由于slotProps是以函數(shù)參數(shù)的形式傳遞的,因此各種簡寫也就可以理解了。
// 解構(gòu)傳參
<template v-slot:default="{ user }">
{{ user.name }}
</template>
// 重命名
<template v-slot:default="{ user: person }" >
{{ person.name }}
</template>
// 默認值
<template v-slot:default="{ user={ firstname: 'test' } }">
{{ user.name }}
</template>
-
縮寫
在向具名(聲明了name屬性的)插槽傳遞內(nèi)容時,(應(yīng)用組件中)可以使用縮寫:
<common-layout>
// 等同于:v-slot:header
<template #header>
// 以下模板內(nèi)容會傳遞給name = header的插槽
<p>this is header</p>
</template>
// 注意: 不可以 直接#
<template #default>
// 以下內(nèi)容會傳遞給沒有聲明name的插槽,也就是默認插槽
<p>this is default slot</p>
</template>
</common-layout>
當然如果common-layout模板中如果只有一個默認插槽的話,你可以直接這樣做:
// 相當于: v-slot:default="slotProps"
// default不可省略,否則引發(fā)警告
<common-layout #default="slotProps">
{{ slotProps.user.name }}
</common-layout>
-
其他示例
請先看官方給出的示例:todoList示例
關(guān)鍵點:
通用組件中這樣聲明:
<!--
我們?yōu)槊總€ todo 準備了一個插槽, 將 `todo` 對象作為一個
插槽的 prop 傳入.
-->
<slot name="todo" v-bind:todo="todo">
<!-- 后備內(nèi)容 -->
{{ todo.text }}
</slot>
應(yīng)用組件中這樣使用:
<todo-list v-bind:todos="todos">
// 或者簡寫為: #todo
<template v-slot:todo="{ todo }">
<span v-if="todo.isComplete">?</span>
{{ todo.text }}
</template>
</todo-list>
這樣使用就將li中的內(nèi)容動態(tài)化。
- 理解
slot的基本用法簡單來說就是(我的理解):
在你聲明一個通用的組件時,將通用的部分聲明為模板,動態(tài)的內(nèi)容,也就是各個應(yīng)用組件不一致的地方,或者說可能需要動態(tài)渲染的部分聲明為插槽slot,并給該插槽定義name,prop,以方便應(yīng)用組件獲取數(shù)據(jù)和對號入座。
參考:
Vue官方文檔: https://cn.vuejs.org/v2/guide/components-slots.html