春節Vue-2.6.0發佈後,對slot插槽進行了必定的優化,那麼對於插槽,你真正的瞭解嗎?如下是我使用中總結的拙見,歡迎批評指正+++++html
最近在作業務組件的時候,用到三種slot,被叫作」默認插槽「,」具名插槽「,」做用域插槽「。瀏覽器
子組件ide
<a v-bind:href="url" class="nav-link"> <slot>content</slot> </a>
父組件post
<navigation-link url="/profile"> Your Profile </navigation-link>
若是父組件爲這個插槽提供了內容Your Profile,則默認的內容content會被替換掉。優化
若是子組件中的多個位置都須要父組件塞進不一樣的內容時,你須要使用具名插槽。url
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot name-"main"></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
子組件在header main footer三處須要塞入不一樣的內容,在父組件的 <template> 元素上使用 slot特性:spa
<base-layout> <template slot="header"> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template slot="footer"> <p>Here's some contact info</p> </template> </base-layout>
看起來具名插槽能解決大部分的問題了,可是,在這種狀況面前使用具名插槽會報錯:code
<div v-for="(item, index) in resultList" :key="index"> <div class="list-content"> <p class="content" v-html="item.content"/> <slot name="content"></slot> </div> </div>
當使用v-for迭代,同一具名插槽重複出現的時候,瀏覽器就會報錯
這時咱們不得不使用做用域插槽component
在 <template> 上使用特殊的 slot-scope 特性,能夠接收傳遞給插槽的 prophtm
子組件內兩處地方放置兩處插槽
<!--位置1--> <slot name="tips" :tips="item.access"></slot> <!--位置2--> <slot name="content" :content="item.content"></slot>
父組件-使用時,slot=name 具名,調用scope.[name]
<template slot="tips" slot-scope="scope"> <span class="item-header-state" v-if="scope.tips === true"><i class="el-icon-check" />已認證</span> </template> <template slot="content" slot-scope="scope"> <el-tag v-for="(tag, index) in scope.content.labels" :key="index" closable type="info" size="small" :disable-transitions="false" @close="handleCloseTag(tag, scope.content)"> {{tag.label}} </el-tag> </template>
But 自 2.6.0 起以上被廢棄。新推薦的語法請查閱這裏。
父組件以另一種方式(不是經過常規的 Props 屬性傳遞機制)向子組件傳遞信息。我發現把這種方法同常規的 HTML 元素聯繫起來頗有幫助。
好比說 HTML 標籤。
<a href=」/sometarget">This is a link</a>
若是這是在 Vue 環境中而且 <a>
是你的組件,那麼你須要發送「This is a link」信息到‘a’組件裏面,而後它將被渲染成爲一個超連接,而「This is a link」就是這個連接的文本。
讓咱們定義一個子組件來展現它的機制是怎樣的:
<template> <div> <slot></slot> </div> </template>
而後在父組件咱們這麼作:
<template> <div> <child-component>This is from outside</child-component> </div> </template>
這時候屏幕上呈現的就應該和你預期的同樣就是「This is from outside」,但這是由子組件所渲染出來的。
咱們還能夠給子組件添加默認的信息,以避免到時候這裏出現什麼都沒有傳入的狀況,就像這樣子:
<template> <div> <slot>Some default message</slot> </div> </template>
而後若是咱們像這樣子建立咱們的子組件:
<child-component> </child-component>
咱們能夠看到屏幕上會呈現「Some default message」。
具名插槽和常規插槽很是相似,惟一的差異就是你能夠在你的目標組件多個位置傳入你的文本。
咱們把子組件升級一下,讓它有多個具名插槽
<template> <div> <slot>Some default message</slot> <br/> <slot _name_="top"></slot> <br/> <slot _name_="bottom"></slot> </div> </template>
這樣,在咱們的子組件中就有了三個插槽。其中 top 和 bottom 插槽是具名插槽。
讓咱們更新父組件以使用它。
<child-component _v-slot:top_> Hello there! </child-component>
注意 —— 咱們在這裏使用新的 Vue 2.6 語法來指定咱們想要定位的插槽:v-slot:theName
。
你如今認爲會在屏幕上看到什麼呢?若是你說是「Hello Top!」,那麼你就只說對了一部分。
由於我沒有爲沒有具名的插槽賦予任何值,咱們所以也還會獲得默認值。因此咱們真正會看到的是:
Some default message
Hello There!
其實真正意義上沒有具名的插槽是被看成‘default’,因此你還能夠這麼作:
<child-component _v-slot:default_> Hello There! </child-component>
如今咱們就只會看到:
Hello There!
由於咱們已經提供了值給默認(也就是未具名)插槽,所以具名插槽‘top’和‘bottom’也都沒有默認值。
你發送的並不必定只是文本,還能夠是其餘組件或者 HTML。你能夠發送任意你想展現的內容。
我認爲插槽和具名插槽相對簡單,一旦你稍微玩玩就能夠掌握。可另外一方面,做用域插槽雖然名字類似但又有些不一樣之處。
我傾向於認爲做用域插槽有點像一個放映機(或者是一個我歐洲朋友的投影儀)。如下是緣由。
子組件中的做用域插槽能夠爲父組件中的插槽的顯示提供數據。這就像一我的帶着放映機站在你的子組件裏面,而後在父組件的牆上讓一些圖像發光。
這有一個例子。在子組件中咱們像這樣設置了一個插槽:
<template> <div> <slot _name_="top" _:myUser_="user"></slot> <br/> <slot _name_="bottom"></slot> <br/> </div> </template> <script> data() { _return_ { user: "Ross" } } </script>
注意到咱們的具名插槽‘top’如今有了一個名爲‘myUser’的屬性,而後咱們綁定了一個動態的值在‘user’中。
在咱們的父組件中就像這樣子設置子組件:
<div> <child-component _v-slot:top_="slotProps">{{ slotProps }}</child-component> </div>
咱們在屏幕上看到的就是這樣子:
{ 「myUser」: 「Ross」 }
仍是使用放映機的類比,咱們的子組件經過 myUser 對象將其用戶字符串的值傳遞給父組件。它在父組件上投射到的牆就被稱爲‘slotProps’。
我知道這不是一個完美的類比,但當我第一次嘗試理解這個機制的時候,它幫助我以這種方式思考。
Vue 的文檔很是好,並且我也已經看到了一些其餘關於做用域插槽工做機制的說明。但不少人採起的方法彷佛是將父組件中的全部或部分屬性命名爲與子組件相同,我認爲這會使得數據很難被追蹤。
在父組件中使用 ES6 解構,咱們這樣子寫還能夠將特定 user 對象從插槽屬性(你能夠隨便怎麼稱呼它)解脫出來:
<child-component _v-slot:top_="{myUser}">{{ myUser }}</child-component>
或者甚至就只是在父組件中給它一個新的名字:
<child-component _v-slot:top_="{myUser: aFancyName}">{{ aFancyName }}</child-component>
全部都是經過 ES6 解構,與 Vue 自己並無什麼關係。
若是你正開始使用 Vue 和插槽,但願這可讓你起步並解決一些棘手的問題。