[Vue] slot詳解,slot、slot-scope和v-slot

夜雪暮歌發表於2019-04-12

v-slot

slot是什麼

slot,也稱插槽,可以類比為插卡式的FC遊戲機,遊戲機(子元件)暴露卡槽(插槽)讓使用者插入不同的遊戲磁條(自定義內容),遊戲機會讀取並載入磁條裡的遊戲。
Vue的slot,是元件的一塊HTML模版,這塊模版由使用元件者即父元件提供。可以說是子元件暴露的一個讓父元件傳入自定義內容的介面。

FC-slot

slot的作用

讓使用者可以擴充元件,去更好地複用元件和對其做定製化處理。
舉一些例子,比如佈局元件、表格列、下拉選項

slot怎麼用

slot的用法可以分為三類,分別是預設插槽、具名插槽和作用域插槽
子元件中:

  • 插槽用<slot>標籤來確定渲染的位置,裡面放如果父元件沒傳內容時的後備內容
  • 具名插槽name屬性來表示插槽的名字,不傳為預設插槽
  • 作用域插槽在作用域上繫結屬性來將子元件的資訊傳給父元件使用,這些屬性會被掛在父元件slot-scope接受的物件上。
// Child.vue
<template>
  <div>
    <main>
    <!-- 預設插槽 -->
        <slot>
          <!-- slot內為後備內容 -->
          <h3>沒傳內容</h3>
        </slot>
    </main>

    <!-- 具名插槽 -->
    <header>
        <slot name="header">
          <h3>沒傳header插槽</h3>
        </slot>
    </header>

    <!-- 作用域插槽 -->
    <footer>
        <slot name="footer" testProps="子元件的值">
          <h3>沒傳footer插槽</h3>
        </slot>
    <footer>
  </div>
</template>

<style scoped>
div{
 border: 1px solid #000;  
}
</style>
複製程式碼

父元件中在使用時:

  • 預設插槽的話直接在子元件的標籤內寫入內容即可
  • 具名插槽是在預設插槽的基礎上加上slot屬性,值為子元件插槽name屬性值
  • 作用域插槽則是通過slot-scope獲取子元件的資訊,在內容中使用。這裡可以用解構語法去直接獲取想要的屬性
// Parent.vue
<child>
  <!-- 預設插槽 -->
  <div>預設插槽</div>  
  <!-- 具名插槽 -->
  <div slot="header">具名插槽header</div>
  <!-- 作用域插槽 -->
  <div slot="footer" slot-scope="slotProps">
    {{slotProps.testProps}}
  </div>
</child>
複製程式碼

渲染結果為

slot-demo

v-slot

在vue2.6中,上述的API被軟廢棄(3.0正式廢棄),取而代之的是內建指令v-slot,可以縮寫為【#】

子元件用法保持不變,父元件中

  • slot屬性棄用,具名插槽通過指令引數v-slot:插槽名 的形式傳入,可以簡化為 #插槽名
  • slot-scope屬性棄用,作用域插槽通過v-slot:xxx="slotProps"的slotProps來獲取子元件傳出的屬性
  • v-slot屬性只能在<template>上使用,但在【只有預設插槽時】可以在元件標籤上使用
//Parent
<template>
  <child>
   <!--預設插槽-->
   <template v-slot>
     <div>預設插槽</div>
   </template>
   <!--具名插槽-->
   <template #header>
     <div>具名插槽</div>
   </template>
   <!--作用域插槽-->
   <template #footer="slotProps">
     <div>
      {{slotProps.testProps}}
     </div>
   </template>
  <child>
</template>
複製程式碼

擴充用法:

  1. 同樣可以通過解構獲取v-slot={user},
    還可以重新命名v-slot="{user: newName}"和定義預設值v-slot="{user = '預設值'}"
  2. 插槽名可以是動態變化的 v-slot:[slotName]

注意:

  1. 預設插槽名為default,可以省略default直接寫v-slot
    縮寫為#時不能不寫引數,寫成#default(這點所有指令都一樣,v-bind、v-on)
  2. 多個插槽混用時,v-slot不能省略default

作用域插槽的原理

slot本質上是返回VNode的函式,一般情況下,Vue中的元件要渲染到頁面上需要經過
template >> render function >> VNode >> DOM 過程。 元件掛載的本質就是執行渲染函式得到VNode,至於data/props/computed這些屬性都是給VNode提供資料來源。

在2.5之前,如果是普通插槽就直接是VNode的形式了,而如果是作用域插槽,由於子元件需要在父元件訪問子元件的資料,所以父元件下是一個未執行的函式 (slotScope) => return h('div', slotScope.msg) ,接受子元件的slotProps引數,在子元件渲染例項時會呼叫該函式傳入資料。

在2.6之後,兩者合併,普通插槽也變成一個函式,只是不接受引數了。

大綱速記:

outline

僅作學習記錄。如有錯漏之處,敬請指正

參考

vue文件-插槽
如何理解Vue.js的元件中的slot?
v-slot由來 - RFC

相關文章