天天看點

Vue3 插槽使用詳解前言-認識slot一、作用域插槽二、具名插槽總結

Vue在2.6.0,版本更新了有關插槽的大量内容,具名插槽和作用域插槽引入了一個新的文法v-slot來取代slot和slot-scope這兩個已廢棄但未移除的屬性。

目錄

  • 前言-認識slot
  • 一、作用域插槽
    • 動态指令參數與插槽
  • 二、具名插槽
  • 總結

前言-認識slot

< slot>< /slot>一般被寫在子元件裡,可以被父元件内寫的東西"插"滿,把它看作是一個幫 [未來要填充的東西] 提前占位的空框,就像那些一個人占了自習室一整排的可惡的家夥.

我想我用程式裡的名詞來比喻可能比較好了解?slot就像子元件裡一個可以傳入參數的函數,你可以從父元件裡往裡傳各種标簽作為它的參數.

感謝你浪費一分鐘生命讀完了這段廢話,我們開始吧 doge)

先說下父子元件的概念吧,打個比方,如果父元件是App.vue,子元件就可以是components裡的各種.vue檔案.

一、作用域插槽

或許一個插槽會需要在父元件内不同的地方多次調用,但是卻需要以不同的渲染結果出現,又或者插槽填充物需要通路子元件中的資料才能正常工作;

這時候就可以用作用域插槽了,作用域插槽的渲染是在子元件完成,利用這個特點,在子元件的slot上利用v-bind / v-for什麼的綁定上填充物需要的各種資料,這樣填充完成後在子元件渲染時就可以從子元件拿資料來渲染了.

綁定在 < slot> 上的屬性被稱為"插槽prop",也就是此處的user屬性了

//這是在子元件内;
<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>
           

而在父級作用域内使用v-slot屬性來取代已經被官方廢棄的slot-scope屬性;

//這是在父元件内;
<current-user>
//current-user:子元件;
  <template v-slot:default="slotProps(可自定義)">
  /* !!我還是推薦你用簡寫:<template v-slot="slotProps">,
    那個:default看起來很奇怪!! */
  /* 使用template來包裹用于填充slot的html結構,
    非具名插槽不能填名字 */
  /* (估計這slotProps就是子元件的user) */
  
    {{ slotProps.user.firstName }}
    //此處內插補點表達式明顯需要使用子元件内的資料來渲染;
  </template>
</current-user>

           

作用域插槽會被解析為一個傳入了slotProps作參的函數:

function (slotProps) {
  // 插槽内容
}
           

v-slot 的值實際上可以是任何 [能作為函數的參數來傳入] 的東西;

<template v-slot="{ user }">
  /* 這裡給v-solt賦了個對象 */ 
    {{ slotProps.user.firstName }}
  </template>
           

動态指令參數與插槽

從 2.6.0 開始,可以用方括号括起來的JS表達式作為一個指令(v-bind啥的)的參數,比如在此例中

//随便定義一個變量randomName,這個變量是動态變化的;
<a v-bind:[randomName]="user"> ... </a>
           

或者:

//對不同的事件綁定處理函數;
<a v-on:[randomEventName]="differentFunction"> ... </a>
           

在2.6版本新增的内容中,動态指令參數也可以用在 v-slot 上,來定義動态的插槽名:

<base-layout>
  <template v-slot:[動态指令參數]>
  /* 動态指令參數,就像前面的randomEventName */
    ...
  </template>
</base-layout>
           

二、具名插槽

有name屬性的就是具名插槽了,沒有的就是匿名插槽(這麼說作用域插槽也屬于匿名插槽?).

有時我們會需要在子元件某處寫一堆的插槽,又需要在父元件各處分别使用這些插槽.某些方面計算機是很笨的,它不會看得出哪個插槽該填什麼東西,也不知道你在這裡填的東西是要給哪個插槽,這就得給它規定一下,不然…不然這傲嬌它就直接不給你填了.

2.6版本之前具名插槽有直接使用name屬性來規定目标的方法(廢棄,但沒移除),但是今天試了下,好像已經不行了(我沒有成功…),那這裡就隻記錄官方推的新方法了.

總之隻要出現使用多個插槽的情況,那就用具名插槽吧!

使用< template>來包裹某插槽的填充物,在template标簽的v-slot屬性後面寫上對應插槽的name屬性值.

先來看看子元件吧:

<template>
  <div class="tab-bar-item">
    <slot name="item-icon"></slot>
    <slot name="item-text"></slot>
  <!-- 插槽slot最終會被父元件裡傳入的html元素替換,在插槽上寫樣式類的東西不會生效,可以用div來包裹slot,利用樣式繼承性來完成樣式修改 -->
  </div>
</template>
           

父元件:

//這是在父元件内
  <tab-bar-item>
  
    <template v-slot:item-icon>
    /* !!2.6新增:可簡寫為<template #item-icon> !!*/
         /* 這部分填充入插槽:item-icon */
      <img src="#" />
    </template>
  
    <template v-slot:item-text>
        /* !!2.6新增:可簡寫為<template #item-text>!! */
        /* 這部分填充入插槽:item-text */
      <div>首頁</div>
    </template>
    
  </tab-bar-item>
           

這樣所有在template包裹下的填充内容都會被填入對應的插槽,但如果沒有被template包裹呢?

那樣就相當于寫了個這:

<template v-slot:default>
  /* 隐含的名字“default”(預設) */
    <p>我是内容</p>
  </template>
           

Vue官方文檔:沒有被包裹在帶有 v-slot 的 中的内容都會被視為預設插槽的内容.

它的填充物的CSS樣式将受到父元件的影響.

總結

注意 v-slot 隻能添加在 上 (隻有一種例外情況);

我為什麼要把這些玩意兒寫在插槽裡,這麼麻煩為什麼不直接寫那些标簽?

是,我一開始也在問我自己為什麼不直接寫标簽而要寫插槽,跟套娃一樣.

後來我意識到這些放在插槽裡的東西可以讓插槽所在區域的内容動态化,"不寫死"的思想又一次在這裡得到了展現,隻不過這次的變量是插槽裡的那段html代碼;

而且,如果直接向父元件中的子元件裡填充html結構,沒有slot占位是渲染不出來(無法建立)的(其實在子元件内的slot上寫樣式也是不行的,slot一旦渲染就會被替換成填充物,自己的樣式就跟着一塊被替換下去了,啥都看不見,我們得拿個div什麼的把slot包起來然後在div上寫樣式,讓樣式繼承到未來的填充物上.

寫了仨小時,回頭看了一眼,崩潰了,參考的是2.6的文檔.

馬上滾去看了v3的文檔,幸虧差的不多,改動也大多都在v2.6完成了,這波是老天幫忙.

以上是我據本階段的學習得出的一些經驗與心得,如果幫到了您,在下十分榮幸;若是您發現了不足,您可以在評論區指出, 我會感謝您的指點的!