vue的內建元件slot

南風知我意NY發表於2019-03-28

vue的內建元件slot

vue有很多內建的元件,有component,transition, transition-group, keep-alive, slot;其中slot(插槽)官方文件的解釋為內容分發的出口,官方解釋很抽象,我們不如直接來根據名字插槽來理解,即留出一個位置,你可以插入任何你想顯示的東西例如文字或者hml標籤

為什麼要用slot?

vue最大的特性就是元件化,在實際專案開發中都會封裝公用元件,增強程式碼複用性。而公用元件就是要可以在多處引用,這就要求網站多處的渲染解構或效果要完全一樣,才能把一樣的這部分拿出來封裝成一個公用元件多處引用,但實際專案開發中設計出來的網站很少有多處效果完全一樣的情況,往往都是大體效果類似,並不完全一樣,多少會有一些差別。這時候就會用到元件的slot了,封裝公用元件的時候把不一樣的地方作為一個插槽留出來,在引用元件的時候插入什麼就顯示什麼。這樣就實現了元件的高度複用。

使用場景

假如我現在要畫兩幅畫,第一幅是一個籃子裡裝著蘋果,第二幅是一個籃子裡裝著橘子,如果兩幅畫的籃子裡裝著一樣的,我只需要畫一幅,然後複製貼上就好了。slot的解決辦法:畫一個籃子把蘋果或者橘子的空位留出來,複製貼上出來兩個籃子,當我要用第一幅畫的時候,給籃子裡畫上蘋果,用第二幅畫的時候給籃子裡畫上橘子。

例如網站裡,有很多像如下這樣的tab標籤

vue的內建元件slot

vue的內建元件slot

這樣定義公用元件myTab.vue:

<div>
	<div class="mytab">
	  <span v-for="item in showItems" :key="item.name">{{item.label}}</span>  
	  <slot></slot>   // 插槽,給蘋果或橘子留出來的位置
	</div>
</div>
複製程式碼

第一個地方呼叫:

import myTab from '@/components/myTab/myTab.vue'  //匯入元件
... //此處省略其他語句
 components: {
      myTab  //註冊元件
 },
...
//呼叫
<my-tab :showItems="showItems">
	<i class="iconfont">&#xe63a;</i>  // 插入篩選圖示(畫蘋果)
</my-tab>

最終渲染結果:
<div>
	<div class="mytab">
	  <span v-for="item in showItems" :key="item.name">{{item.label}}</span>  
	  <i class="iconfont">&#xe63a;</i> 
	</div>
</div>

複製程式碼

第二個地方呼叫:

import myTab from '@/components/myTab/myTab.vue'  //匯入元件
...
 components: {
      myTab  //註冊元件
 },
...
//呼叫
<my-tab :showItems="showItems">
	<span class="slotHandle"> // 插入退出檢視按鈕(畫橘子)
	  退出檢視
	  <i class="iconfont">&#xe61a;</i>
	</span>
</my-tab>

最終渲染結果:
<div>
	<div class="mytab">
	  <span v-for="item in showItems" :key="item.name">{{item.label}}</span>  
	  <span class="slotHandle">
	  退出檢視
	  <i class="iconfont">&#xe61a;</i>
	</span> 
	</div>
</div>

複製程式碼

當然了,用v-if通過prop傳參也完全可以實現這個效果: 定義公用元件myTab.vue:

<div>
	<div class="mytab">
	  	<span v-for="item in showItems" :key="item.name">{{item.label}}</span>  
		<i class="iconfont"  v-if="type === '蘋果'">&#xe63a;</i>  // 插入篩選圖示(畫蘋果)

		<span class="slotHandle" v-if="type === '橘子'"> // 插入退出檢視按鈕(畫橘子)
		  退出檢視
		  <i class="iconfont">&#xe61a;</i>
		</span>
	</div>
</div>

...
export default{
	prop: ['type']
}

複製程式碼

但是如果頁面上有一百類似的地方要呼叫這個元件,定義元件的時候就要寫一百個v-if來判斷到底該顯示什麼,這樣元件就顯得臃腫不直觀

slot的name屬性

有時候在一個元件裡我們需要用到多個插槽,這時候就要用到slot的name屬性

<div class="container">
  <header>
  ... //其他佈局
    <slot name="header"></slot>
  ... //其他佈局
  </header>
  <main>
  ... //其他佈局
    <slot name='main'></slot>
  ... //其他佈局
  </main>
  <footer>
  ... //其他佈局
    <slot name="footer"></slot>
  ... //其他佈局
  </footer>
</div>

複製程式碼

呼叫時使用template標籤以及v-slot來匹配slot的name(v-slot是vue2.6及以上版本支援的語法,vue2.6以下版本請檢視文件):

<container>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  // 不是必須寫的,沒有要插入的內容就不寫

  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</container>
複製程式碼

slot訪問子元件的變數

slot是子元件留出來的插槽,插入的內容是由父元件定義的,也相當於插入的是父元件的標籤,這些要被插入的標籤當然可以隨意的訪問父元件的data屬性了

父元件:father.vue

<my-tab :showItems="showItems">
	// 插入的內容開始
	<span class="slotHandle">
	  {{btnText}}   // 可以渲染出 退出檢視 按鈕
	  <i class="iconfont">&#xe61a;</i>
	</span>
	//插入的內容結束
</my-tab>
...
import myTab from '@/components/myTab/myTab.vue'  //匯入元件
...
 components: {
      myTab  //註冊元件
 },
 data () {
 	return {
 		btnText: '退出檢視'
 	}
 }
...
複製程式碼

如果要插入的標籤裡需要訪問子元件的變數(以下是vue2.6及以上版本支援的語法,vue2.6以下版本請檢視文件

定義包含slot的子元件myTab.vue:

<div>
	<div class="mytab">
	  <span v-for="item in showItems" :key="item.name">{{item.label}}</span>  
	  <slot :sonCount='count'></slot>   // 在子元件中可以隨意在slot上新增屬性(sonCount)
	</div>
</div>

...
data () {
	return {
		count: 1
	}
}
複製程式碼

父元件呼叫father.vue:

<my-tab :showItems="showItems" v-slot="myTabSlot"> ,// 注意時=,相當於: v-slot:default="myTabSlot"
	// 插入的內容開始
	{{myTabSlot.sonCount}}   // 訪問到了tab.vue裡的count:1
	//插入的內容結束
</my-tab>
...
import myTab from '@/components/myTab/myTab.vue'  //匯入元件
...
 components: {
      myTab  //註冊元件
 }
...
複製程式碼

還記得v-slot是幹嘛的嗎?子元件有多個slot時用來匹配slot的name的,也就是v-slot的值是slot的name屬性,這樣就好理解了,我呼叫子元件的時候給子元件裡的slot起了個名字(myTabSlot),我給子元件中的slot上新增了個屬性(sonCount),繫結了count,用myTabSlot.sonCount就可以訪問到count變數了,感覺和ref很類似~

這裡有要注意的點: 官方說法: 當只有預設插槽時,元件的標籤才可以被當作插槽的模板來使用,這樣我們就可以把 v-slot 直接用在元件上。 翻譯解說: 當子元件定義slot時只有一個slot,且沒有給這一個slot新增name屬性,這個slot插槽就是預設插槽(其實預設插槽有一個預設的name為default),呼叫子元件時,子元件標籤(my-tab)可以代替template標籤,v-slot可以用在(my-tab)上,否則v-slot只能用在template標籤上

語法糖:

跟 v-on 和 v-bind 一樣,v-slot 也有縮寫,即把引數之前的所有內容 (v-slot:) 替換為字元 #,注意是v-slot:(有冒號)

例如上邊程式碼:v-slot:default="myTabSlot" 可以寫成 #default="myTabSlot",#後跟的是slot的name,如果是預設插槽,name為default,不能省略

----------------------------------------------------------完結--------------------------------------------------------

若有理解錯誤請指正,後續其他內建元件 ~~~

相關文章