咱們一塊兒學習Vue中的 slot 吧。

Vue 2.6 已經發布一段時間了,主要的更新就是slot(插槽)。可能不少人從始至終都沒用過slot,那多是你對它不夠了解,當你真正的瞭解它的時候,你就會知道當你封裝一個可複用插件的時候它是多麼的 perfect~html

代碼已放到Github上。能夠下載跟着練習一下。vue


咱們先看一個簡單的例子:git

<!--子組件-->
<template>
    <button class="custom-button">
        <slot></slot>
    </button>
</template>
<style>
.custom-button{
    color: #fff;
    background-color: #409eff;
    padding: 10px 20px;
    font-size: 14px;
    border-radius:6px;
    outline: none;
    border: 1px solid #dcdfe6;
}
</style>
複製代碼
<!--父組件-->
<template>
    <div class="button-list">
        <cus-bottom>肯定</cus-bottom>
    </div>
</template>
<script>
import customButton from './customButton.vue'
export default{
    components:{
        'cus-bottom':customButton
    }
}
</script>

複製代碼

最終渲染:github

<div class="button-list">
    <button class="custom-button">
        肯定
    </button>
</div>
複製代碼

當子組件渲染的時候,<slot></slot> 將會被替換爲「肯定」。slot是不會被渲染的,它是用來接收父組件傳過來的內容。bash

咱們來看一張圖,我以爲更容易理解插槽的概念:ide

遊戲卡就是父組件傳給的內容,插口就至關於子組件的 slot標籤,組合起來就是最終的渲染。

固然上述就是最簡單的slot的使用,咱們接着往下看。ui

插槽內容

<slot></slot>不只能夠接受字符串,還能夠接收Html模板:spa

<!--父組件-->
<div class="button-list">
    <cus-bottom>
        <span>肯定</span>
    </cus-bottom>
</div>
複製代碼

最終渲染:插件

<div class="button-list">
    <button class="custom-button">
        <span>肯定</span>
    </button>
</div>
複製代碼

還能夠接收其餘組件:code

<!--父組件-->
<div class="button-list">
    <cus-bottom> 
        <!-- cus-font 圖標組件 -->
        <cus-font></cus-font>
        <span>肯定</span>
    </cus-bottom>
</div>
複製代碼

編譯做用域

父級模板裏的全部內容都是在父級做用域中編譯的;子模板裏的全部內容都是在子做用域中編譯的。

咱們用例子來解釋一下什麼叫 編譯做用域

<!--父組件-->
<template>
    <div class="button-list">
        <cus-bottom>{{buttonText}}</cus-bottom>
    </div>
</template>
<script>
import customButton from './customButton.vue'
export default{
    components:{
        'cus-bottom':customButton
    },
    data(){
        return{
            buttonText:'保存'
        }
    }
}
</script>
複製代碼

{{buttonText}}是父組件中的編譯的,因此子組件獲取不到buttonText變量,反之在子組件內編譯的變量父組件也獲取不到。

默認內容

官網叫後備內容。我以爲有點怪,這裏就叫默認內容。

當咱們button默認內容就是「肯定」:

<button class="custom-button">
    <!--這裏的肯定就是默認內容-->
    <slot>肯定</slot>
</button>
複製代碼

如今當我在一個父級組件中使用<cus-button>而且按鈕也是「肯定」的時候,就能夠不提供任何內容:

<div class="button-list">
    <cus-bottom></cus-bottom>
</div>
複製代碼

固然若是咱們父組件裏的按鈕是「保存」的時候,還能夠這樣寫

<div class="button-list">
    <!--這裏的保存 會替換掉子組件的默認內容-->
    <cus-bottom>保存</cus-bottom>
</div>
複製代碼

最終渲染:

<div class="button-list">
    <button class="custom-button">
        保存
    </button>
</div>
複製代碼

具名插槽

具備名字的插槽。爲何要有這個東西呢?咱們在上面的例子中slot只有一個,因此父組件傳過來的內容都被子組件惟一的slot接收了。可是不少時候咱們須要有多個slot來分別接收父組件傳過來的 '多份' 內容。

這裏咱們使用官網的例子,帶有以下內容的 <base-layout> 組件:

<div class="container">
  <header>
    <!-- 咱們但願把頭部內容放在這裏 -->
  </header>
  <main>
    <!-- 咱們但願把主要內容放在這裏 -->
  </main>
  <footer>
    <!-- 咱們但願把頁腳放在這裏 -->
  </footer>
</div>
複製代碼

如今我須要三個slot(插槽),來接收父組件傳過來的三分內容。對於這樣的狀況,slot元素有一個特殊的特性:name。這個特性能夠用來定義額外切獨立的插槽:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
複製代碼

中間一個不帶 name 的 slot的插槽 會帶有隱含的名字「default」。至關於<slot name="default"></slot>。也就是說如今子組件裏有三個名爲:header default footer的插槽。

那麼如今父組件使用 <base-layout>組件的時候須要傳三分內容(都不是必須的),'header','default','footer'。這個時候就須要有個標識告訴子組件三分內容跟三個插槽如何對應上。

在向具名插槽提供內容的時候,咱們能夠在一個 <template> 元素上使用 v-slot 指令,並以 v-slot 的參數的形式提供其名稱:

<base-layout>
  <template v-slot:header>
    <h1>這是header插槽的內容</h1>
  </template>

  <p>這裏是default插槽的內容</p>
  <p>這裏也是default插槽的內容</p>

  <template v-slot:footer>
    <p>這是footer插槽的內容</p>
  </template>
</base-layout>
複製代碼

v-slot :後面就是子組件對應的slotname。由於子組件main標籤裏的slot沒有name,默認name = default,因此還能夠這樣寫

<base-layout>
  <template v-slot:header>
    <h1>這是header插槽的內容</h1>
  </template>

  <template v-slot:default>
    <p>這裏是default插槽的內容</p>
    <p>這裏也是default插槽的內容</p>
  </template>

  <template v-slot:footer>
    <p>這是footer插槽的內容</p>
  </template>
</base-layout>
複製代碼

最終渲染:

<div class="container">
  <header>
    <h1>這是header插槽的內容</h1>
  </header>
  <main>
    <p>這裏是default插槽的內容</p>
    <p>這裏也是default插槽的內容</p>
  </main>
  <footer>
    <p>這是footer插槽的內容</p>
  </footer>
</div>

複製代碼

具名插槽的縮寫

v-onv-bind 同樣,v-slot 也有縮寫,即把參數以前的全部內容 (v-slot:) 替換爲字符 #。例如 v-slot:header 能夠被重寫爲 #header

<base-layout>
    <template #header>
        <h1>這是header插槽的內容</h1>
    </template>
    
    <template #default>
        <p>這裏是default插槽的內容</p>
        <p>這裏也是default插槽的內容</p>
    </template>
    
    <template #footer>
        <p>這是footer插槽的內容</p>
    </template>
</base-layout>
複製代碼

做用域插槽

這裏講做用域插槽我以爲叫插槽傳值更貼切。

例如,設想一個帶有以下模板的 <current-user> 組件:

<template>
    <span>
        <slot>{{ userInfo.name }}</slot>
    </span>
</template>

<script>
export default{
    data(){
        return{
            userInfo:{
                name:'erdong',
                sex:'boy',
                age:'26'
            }
        }
    }
}
</script>
複製代碼

包括當前用戶的全部信息。插槽的默認內容是name。當咱們使用 <current-user> 組件時:

父組件:

<current-user></current-user>
複製代碼

最終渲染:

<span>
    erdong
</span>
複製代碼

可是我想讓父組件裏顯示sex該怎麼辦呢?很簡單,改變子組件的插槽的默認內容:

<span>
    <slot>{{ userInfo.sex }}</slot>
</span>
複製代碼

可是這樣達不到咱們封裝組件的特性:可複用性。

若是說父組件能拿到子組件裏的infoData的值,那咱們就能夠這樣寫:

<!--父組件-->
<current-user>
    {{infoData.sex}}
</current-user>
複製代碼

這樣就能覆蓋子組件裏的默認內容。可是咱們在上面提到了 編譯做用域 父組件是取不到子組件的變量的。

想讓父組件取到infoData該怎麼辦呢?

這個時候咱們須要更改子組件:

<!--子組件-->
<span>
    <slot v-bind:userInfo="userInfo" name='user'>{{ userInfo.sex }}</slot>
</span>
複製代碼

父組件:

<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}
    </template>
</current-user>
複製代碼

最終渲染:

<span>
    boy
</span>
複製代碼

子組件v-bind:userInfo="userInfo" name='user' 第一個userInfo是傳給父組件的變量名稱,第二個userInfo是傳給父組件的值。name就是該slot的名稱

父組件v-slot:user="infoData" user就是對應子組件的slotname,infoData就是接收該slot傳過來的值的集合的變量名稱。爲何叫集合呢?由於子組件一個slot能夠傳多個值:

<!--子組件-->
<template>
   <span>
       <slot v-bind:userInfo="userInfo" v-bind:address='address' name='user'>{{ userInfo.name }}</slot>
   </span>
</template>

<script>
export default{
   data(){
       return{
           userInfo:{
               name:'erdong',
               sex:'boy',
               age:'26'
           },
           address:{
               city:'上海市',
           }
       }
   }
}
</script>
複製代碼
<!--父組件-->
<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}{{infoData.address.city}}
    </template>
</current-user>
複製代碼

最終渲染:

<span>
    boy上海市
</span>
複製代碼

解構插槽 Prop

<!--父組件-->
<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}{{infoData.address.city}}
    </template>
</current-user>
複製代碼

上面提到了 infoData是子組件名爲user的插槽傳過來的值得集合。 即:

infoData = {
    userInfo:{
        name:'erdong',
        sex:'boy',
        age:'26'
    },
    address:{
        city:'上海市',
    }
}
複製代碼

因此咱們能夠用ES6的語法來解構它:

<!--父組件-->
<current-user>
    <template v-slot:user="{userInfo,address}">
        {{userInfo.sex}}{{address.city}}
    </template>
</current-user>
複製代碼

總結

到這裏咱們基本上就把Vueslot(插槽)使用過了一遍,還有一些沒有提到,可是若是這些你所有學會的話,能夠說你已經掌握了slot的使用。若是報錯請查看你的Vue.js版本是不是2.6.x。

課後做業

在上面咱們用封裝button的例子來說slot的基本用法。有興趣的同窗能夠完善一下。封裝一個相似於element UIbutton組件。能夠留着本身項目使用。

相關文章
相關標籤/搜索