天天看點

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

什麼是插槽

插槽(

slot

)通俗的了解就是“占坑”,在元件模闆中占有位置,當使用該元件的時候,可以指定各個坑的内容。也就是我們常說的内容分發

值得一提的是,插槽這個概念并不是

Vue

提出的,而是

web Components

規範草案中就提出的,具體入門可以看 使用 templates and slots[1] ,

Vue

隻是借鑒了這個思想罷了

在 Vue 2.6.0 中,我們為具名插槽和作用域插槽引入了一個新的統一的文法 (即

v-slot

指令)。它取代了

slot

slot-scope

,這兩個目前已被廢棄但未被移除且仍在文檔中的 attribute

本文的例子基于 Vue 2.6.X,是以用的都是 v-slot 的文法。

本文

DEMO

已全部放到 Github[2] 和 沙箱[3] 中,供大家學習,如有問題,歡迎評論提出。

預設插槽

我們建立父元件

Parent

和子元件

Child

,結構如下:

父元件:

子元件:

父元件調用

Child

元件的時候,會在

Child

标簽中将内容傳入到子元件中的

标簽中,如下所示

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

也就是最後的渲染結果如下:

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

後備内容

我們可以在子元件中的

中加入一些内容,像下面一樣

當父元件調用的時候, 子元件标簽内沒有相關的内容時候,

标簽内的内容就會生效,否則就不會渲染,可以了解就是個“備胎”

如父元件調用上面子元件:

結果如下:

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

具名插槽

當然,插槽可以不止一個,這個主要是為了能夠靈活的控制插槽的位置以及元件的抽象。我們可以通過在子元件的

slot

标簽中設定

name

屬性,然後在父元件中通過

v-slot:

(或者使用簡寫

#

) + 子元件

name

屬性值的方式指定要插入的位置。如果是預設插槽的話,

v-slot:default

即可

如下父元件:

子元件

需要留意的是,最後渲染的順序是以子元件的順序為主,也就是上面的例子,渲染出來如下:

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件
vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

作用域插槽

有時候,我們想在一個插槽中使用子元件的資料和事件,類似如下(注意:

user

是定義在

Child3

元件中的資料):

會直接報錯:

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

原因在于父元件取不到子元件的資料,這裡記住一個原則:父級模闆裡的所有内容都是在父級作用域中編譯的;子模闆裡的所有内容都是在子作用域中編譯的。

那我們怎樣才能擷取到子元件的資料或者事件呢?我們可以直接在子元件中通過

v-bind

的方式将資料或者事件傳遞給父元件中,如下所示

然後在父元件中的插槽内,通過類似

v-slot:default="slotProps"

接受子元件傳遞過來的資料

以上

slotProps

可以自定義,而且可以使用解構指派的文法

執行個體:解耦業務邏輯和視圖

我們經常會遇到一個場景,就是兩個元件的業務邏輯是可以複用的,但是視圖卻不一樣,比如我們經常會有類似切換開關的需求,功能包括:

  • 關閉開關
  • 打開開關
  • 切換開關
  • 開關關閉或者打開的時候不一樣的内容

我們可以很快的寫出它的一個

JS

業務邏輯代碼:

但是可能現在我的樣式一是這樣的

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

然而另外一個地方的樣式是這樣的(隻是舉個例子,現實可能更加的複雜,甚至有可能一些按鈕直接就隐藏掉了)

vue slot scope使用_【Vue 進階】從 slot 到無渲染元件

這個時候,插槽就派上了用場。上面提到作用域插槽可以将資料和事件從子元件傳遞給父元件,這就相當于對外暴露了接口。而且可以将

HTML

中的

DOM

以及

CSS

交給父元件(調用方)去維護,子元件通過

标簽插入的位置即可,主要邏輯如下:

子元件:

父元件:

我們現在采用的是單檔案的方式書寫的,實際上子元件還是會有相關的

HTML

結構,如何做到子元件完全不需要渲染自己的

HTML

呢?那得了解下無渲染元件的實作

進階:無渲染元件的實作

無渲染元件(renderless components)是指一個不需要渲染任何自己的

HTML

的元件。相反,它隻管理狀态和行為。它會暴露一個單獨的作用域,讓父元件或消費者完全控制應該渲染的内容。

Vue

中,提供了單檔案元件的寫法。像上面的示例一樣,我們始終還是在子元件中進行了一些渲染的操作,那如何做到真正的不渲染元件呢?

比如上面的

toggle

例子,我們已經做到了子元件暴露一個單獨的作用域,讓父元件或消費者完全控制應該渲染的内容。現在我們需要将單檔案中的

template

結構(

slot

标簽外層的

div

)完全交給父元件,但單檔案元件中

slot

标簽是不能作為

template

的根元素的

這個時候,我們需要了解一下 Vue 渲染函數(

render function

)

歸根結底,

Vue

及其所有的元件都隻是

JavaScript

。單檔案元件最後會被建構工具,如

webpack

,将

CSS

抽取形成一個檔案,其他的内容會被轉換成  

JavaScript

,類似如下:

當然,這個不是它的最終形态,模闆編譯器會提取

template

屬性内容并将其内容編譯為

JavaScript

,然後通過

render

函數添加到元件對象中。最終形态應該是如下:

具體的渲染函數可參見官網[4],雖然寫

render

函數的成本會高一些,但是它的性能會比單檔案元件好很多。

以上的例子,隻有插槽的時候,我們隻需要在

render

函數中,使用

this.$scopedSlots.default

代替掉

标簽即可

代碼如下:

以上就可以做到子元件完全不渲染自己的

HTML

總結

本文介紹了一些

Vue

插槽的基本知識,包括

  • 預設插槽
  • 後備内容
  • 具名插槽
  • 作用域插槽

然後介紹了一下,如何通過插槽實作業務邏輯和視圖的解耦,再結合渲染函數實作真正的無渲染函數

本文

DEMO

已全部放到 Github[5] 和 沙箱[6] 中,供大家學習,如有問題,可以評論提出。

這麼用心了,求個贊,哈哈

希望對大家有所幫助~

往期優秀文章推薦

  • 【Vue進階】——如何實作元件屬性透傳?[7]
  • 前端應該知道的 HTTP 知識【金九銀十必備】[8]
  • 最強大的 CSS 布局 —— Grid 布局[9]
  • 如何用 Typescript 寫一個完整的 Vue 應用程式[10]
  • 前端應該知道的web調試工具——whistle[11]

參考:

  • Vue 插槽(slot)使用(通俗易懂)[12]
  • vue 2.6 中 slot 的新用法[13]
  • (譯)函數式元件在Vue.js中的運用[14]
  • Building “Renderless” Vue Components[15]

參考資料

[1]

使用 templates and slots: https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_templates_and_slots

[2]

Github: https://github.com/GpingFeng/vue-slot

[3]

沙箱: https://codesandbox.io/s/hopeful-nash-id826?file=/src/main.js

[4]

官網: https://cn.vuejs.org/v2/guide/render-function.html

[5]

Github: https://github.com/GpingFeng/vue-slot

[6]

沙箱: https://codesandbox.io/s/hopeful-nash-id826?file=/src/main.js

[7]

【Vue進階】——如何實作元件屬性透傳?: https://juejin.im/post/6865451649817640968

[8]

前端應該知道的 HTTP 知識【金九銀十必備】: https://juejin.im/post/6864119706500988935

[9]

最強大的 CSS 布局 —— Grid 布局: https://juejin.im/post/6854573220306255880

[10]

如何用 Typescript 寫一個完整的 Vue 應用程式: https://juejin.im/post/6860703641037340686

[11]

前端應該知道的web調試工具——whistle: https://juejin.im/post/6861882596927504392

[12]

Vue 插槽(slot)使用(通俗易懂): https://juejin.im/post/6844903920037281805

[13]

vue 2.6 中 slot 的新用法: https://juejin.im/post/6844903885476200461

[14]

(譯)函數式元件在Vue.js中的運用: https://juejin.im/post/6844903752164442120

[15]

Building “Renderless” Vue Components: https://css-tricks.com/building-renderless-vue-components/