Vue中神奇的插槽slot

遇到的問題?

在使用uni開發(fā)小程序或者App的時候,會遇到各種彈窗的需求,基本上都是一個黑色蒙版,上面中間有一塊區(qū)域可以顯示內(nèi)容,不同的彈窗,只有中間這一塊區(qū)域顯示的內(nèi)容是不同的,但是整個彈窗的展示和隱藏是可以抽取為一個組件的。為了解決這個需求,特此了解并學(xué)習(xí)記錄了插槽slot的使用。

Vue中的插槽slot?

  • 是對組件的擴(kuò)展,通過slot插槽向組件內(nèi)部指定位置傳遞內(nèi)容(先占位,然后父組件去寫入內(nèi)容),通過slot可以父子傳參;
  • 插槽顯示與否、顯示內(nèi)容是由父組件來控制,而插槽在哪顯示就由子組件來進(jìn)行控制

怎么使用插槽?

1. 默認(rèn)使用

父組件:

<template>
  <div>
    我是父組件
    <slotOne1>
      <p style="color:red">我是父組件插槽內(nèi)容</p>
    </slotOne1>
  </div>
</template>

子組件:slotOne1

<template>
  <div class="slotOne1">
    <div>我是slotOne1組件</div>
    <slot><p>我是默認(rèn)顯示的內(nèi)容,父組件沒有設(shè)置內(nèi)容,那么我就會顯示</p></slot>
  </div>
</template>
顯示結(jié)果

注意事項(xiàng):

  1. 在slot標(biāo)簽添加樣式無效
  2. 在父組件引用的子組件中也可以寫入其他組件
  3. 如果子組件中有多個slot標(biāo)簽,那么內(nèi)容也會被插入多次
2. 具名插槽

上面??注意事項(xiàng)提到過《如果子組件中有多個slot標(biāo)簽(沒有名字), 那么內(nèi)容會被插入多次》,那我們想使用多個插槽,并且每個插槽有不同的內(nèi)容,可以使用slot的一個attribute:name,其實(shí)一個不帶name的slot也會帶有隱含的名字‘default’。

在向具名插槽提供內(nèi)容的時候,我們可以使用v-slot指令,并以v-slot參數(shù)的形式提供其名稱。

父組件:

<template>
    <child-page>
        <text>第一次沒有指定名字的內(nèi)容</text>
        <template v-slot:header>
            <text style="display: block;">我是父組件給的標(biāo)題</text>
        </template>
        <template v-slot:footer>
            <text style="display: block;">我是父組件第一次給的底部,不會顯示</text>
        </template>
        <text>|第二次沒有指定名字的內(nèi)容</text>
        <template v-slot:footer>
            <text style="display: block;">我是父組件第二次給的底部,會顯示</text>
        </template>
    </child-page>
</template>

子組件:

<template>
    <view>
        <text>這是child-page必顯示的標(biāo)題</text>
        <slot name="header">
            <text>header占位文本</text>
        </slot>
        <text style="display: block;">---我是中間的分割線---</text>
        <slot></slot>
        <slot name="footer"></slot>
    </view>
</template>
  • 具名插槽的縮寫

跟v-on和v-bind一樣,v-slot也有縮寫,就是把v-slot:替換為字符#, 例如v-slot:default#default, v-slot: header#header。

注意事項(xiàng):

  1. 父組件連續(xù)給指定v-slot:footer賦值,后者會覆蓋前者,v-slot:default也是一樣
  2. v-slot指令只能添加在<template>上(除了獨(dú)占默認(rèn)插槽的縮寫語法,下面會介紹到)
3. 作用域插槽
3.1 編譯作用域

這里要著重說一下編譯作用域:父級模板里的所有內(nèi)容都是在父級作用域中編譯的;子模板里的所有內(nèi)容都是在子作用域中編譯的。

比如:

<navigation-link url="/profile">
  Logged in as {{ user.name }}
</navigation-link>

這個user.name肯定是在父組件的屬性,也就是說這個插槽跟模板的其他地方一樣可以訪問相同的實(shí)例property(也就是相同的作用域),而不能訪問<navigation-link>的作用域。

3.2 作用域插槽

有時候我們需要讓插槽內(nèi)容能夠訪問子組件中才有的數(shù)據(jù),例如,有一個帶有如下模板的<current-user>組件:

<span>
// 父組件不指定內(nèi)容,默認(rèn)會顯示 user.lastName
  <slot>{{ user.lastName }}</slot>
</span>

我們在父組件中,可能想換掉備用內(nèi)容,用名非姓來顯示:

<current-user>
  {{ user.firstName }}
</current-user>

當(dāng)然,這樣的代碼是不會正常工作的,因?yàn)橹挥?lt;current-user>組件可以訪問到user而我們提供的內(nèi)容是在父級渲染的,具體可以看?? 3.1的介紹。

為了讓user在父級的插槽內(nèi)容中可以訪問到,我們需要2步操作:

  1. user作為<slot>元素的一個attribute綁定上去, 綁定在<slot>元素上的attribute被稱為插槽prop
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>
  1. 在父級作用域中,我們可以使用帶值的v-slot來定義我們提供的插槽prop的名字:
<current-user>
  <template v-slot:default="slotProps(這個是可以隨意命名的)">
    {{ slotProps.user.firstName }}
  </template>
</current-user>
3.3 獨(dú)占默認(rèn)插槽的縮寫語法

在上述情況下,當(dāng)被提供的內(nèi)容只有默認(rèn)插槽時,組件的標(biāo)簽才可以被當(dāng)做插槽的模板來使用,就是可以把v-slot直接用在組件上,可以跟上面對比一下代碼的不同:

<current-user v-slot:default="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

你認(rèn)為這就是最簡單了嗎?當(dāng)然不是。。。

<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
</current-user>

我們把default去掉,不帶參數(shù)的v-slot被假定對應(yīng)默認(rèn)插槽。

注意:默認(rèn)插槽的縮寫語法不能和具名插槽混用,因?yàn)樗鼤?dǎo)致作用域不明確,需要為所有的插槽使用完整的基于<template>的語法.

錯誤?的代碼:

<!-- 無效,會導(dǎo)致警告 -->
<current-user v-slot="slotProps">
  {{ slotProps.user.firstName }}
  <template v-slot:other="otherSlotProps">
    slotProps is NOT available here
  </template>
</current-user>

正確?的代碼:

<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</current-user>
3.4 解構(gòu)插槽Prop

首先,我們要明白一下:作用域插槽的內(nèi)部工作原理是將你的插槽內(nèi)容包括在一個擁有單個參數(shù)的函數(shù)里:

function (slotProps) {
  // 這里是插槽內(nèi)容,我們可以直接使用slotProps
}

so,意味著v-slot的值實(shí)際上可以是任何能夠作為函數(shù)參數(shù)的JavaScript表達(dá)式。

I think : 這只是一個錦上添花的功能,可以讓模板更加簡潔。

大概了解一下吧,在支持的環(huán)境下(單文件組件或現(xiàn)代瀏覽器),可以使用ES2015解構(gòu)來傳入具體的插槽prop,如下:

  • 讓模板更簡潔
<current-user v-slot="{ user }">
  {{ user.firstName }}
</current-user>
  • 將prop重命名
<current-user v-slot="{ user: person }">
  {{ person.firstName }}
</current-user>
  • 定義默認(rèn)顯示內(nèi)容
<current-user v-slot="{ user = { firstName: 'Guest' } }">
  {{ user.firstName }}
</current-user>
4. 動態(tài)插槽名 2.6.0新增

動態(tài)指令參數(shù)也可以用在v-slot上,來定義動態(tài)的插槽名:

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>
5. 其他示例

插槽prop允許我們將插槽轉(zhuǎn)換為可復(fù)用的模板,這些模板可以基于輸入的prop渲染除不同的內(nèi)容。這在設(shè)計(jì)封裝數(shù)據(jù)邏輯同時允許父級組件自定義部分布局的可復(fù)用組件是最有用的。

例如,我們要實(shí)現(xiàn)一個 <todo-list> 組件,它是一個列表且包含布局和過濾邏輯:

<ul>
  <li
    v-for="todo in filteredTodos"
    v-bind:key="todo.id"
  >
    {{ todo.text }}
  </li>
</ul>

我們可以將每個todo作為父級組件的插槽,以此通過父級組件對其進(jìn)行控制,然后將todo作為一個插槽prop進(jìn)行綁定,這樣可以在不同的父級組件中,對todo數(shù)據(jù)進(jìn)行不同的展示:

<ul>
  <li
    v-for="todo in filteredTodos"
    v-bind:key="todo.id"
  >
    <!--
    我們?yōu)槊總€ todo 準(zhǔn)備了一個插槽,
    將 `todo` 對象作為一個插槽的 prop 傳入。
    -->
    <slot name="todo" v-bind:todo="todo">
      <!-- 后備內(nèi)容 -->
      {{ todo.text }}
    </slot>
  </li>
</ul>

現(xiàn)在當(dāng)我們使用 <todo-list> 組件的時候,我們可以選擇為 todo 定義一個不一樣的template作為替代方案,并且可以從子組件獲取數(shù)據(jù):

<todo-list v-bind:todos="todos">
  <template v-slot:todo="{ todo }">
    <span v-if="todo.isComplete">?</span>
    {{ todo.text }}
  </template>
</todo-list>

只是為了學(xué)習(xí)&記錄&自己的一點(diǎn)理解,附上:
Vue.js官方文檔連接。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容