vue作用域插槽


  • slot大家看看文檔都懂了,無非就是在子組件中挖個坑,坑里面放什么東西由父組件決定。
// 子組件 <template> <slot>來啊,我這里挖了個坑</slot> </template> // 父組件 <template> <child> <!-- 傳入子組件的自定義內容,會填入到子組件的slot插槽中 --> <span>我在這放個span,樂意的話,放個組件都行</span> </child> </template> 
  1. 給slot傳入普通文本
 
slot傳入普通文本
  1. 給slot傳入了一個圖像處理組件

 
slot傳入組件
  • 具名插槽也很簡單,比如有多個插槽,我作為父組件,肯定想區別子組件中的幾個插槽,那就要用slot標簽的name屬性來標識了,而父組件要決定在什么插槽里面放什么內容,就要將name的值賦值給slot屬性傳遞給對應的插槽。如果slot沒有name屬性,就是匿名插槽了,而父組件中不指定slot屬性的內容,就會被丟到匿名插槽中。
// 子組件 <template> <section> <slot name="article-title">這里放標題</slot> <slot>這里放作者</slot> <slot name="article-content">這里放文章內容</slot> </section> </template> // 父組件 <template> <section> <slot-child> <h1 slot="article-title">vue作用域插槽,你真的懂了嗎?</h1> <p slot="article-content">好像有點懂了</p> <div>王五</div> </slot-child> </section> </template> 
  • 最難理解的是作用域插槽。看了文檔說明的朋友可能還會有點暈,大概是說在作用域插槽內,父組件可以拿到子組件的數據。子組件可以在slot標簽上綁定屬性值,如:
<slot :nickName="'Tusi'"></slot> 

而父組件通過slot-scope綁定的對象下拿到nickName的值。

<template> <section> <slot-child> <template slot-scope="scope"> <div>{{scope.nickName}}</div> </template> </slot-child> </section> </template> 

這里大家應該都有疑問。這有什么用?我在子組件用$emit向父組件傳遞數據不就行了?

關於作用域插槽的一點理解

我覺得要從組件之間的數據流向來思考作用域插槽的應用場景。

假設第一個場景,需要你寫一個商品卡片組件,並通過循環去展示多個卡片,並且要求能響應每個卡片上的圖片或者其他內容的點擊事件而跳轉到商品詳情頁,你會怎么寫?

 
淘寶商品列表

我會使用如下的處理方式,首先將商品卡片寫成一個組件Commodity.vue,而在CommodityList.vue中用一個v-for來處理商品卡片列表的展示。

<commodity v-for="(item,index) in commodities" @clickCommodity="onCommodityClick"></commodity> 

Commodity組件通過$emit像父組件傳遞clickCommodity事件,並攜帶商品數據,父組件即可在onCommodityClick方法中得到數據,進行業務處理,這樣便完成了一個基本的由子到父的數據傳遞。

如果再往上抽象一下呢?比如我有多個運營欄目,像淘寶首頁有“有好貨”,“愛逛街”這樣兩個欄目,每個欄目下都需要有一個商品卡片列表,那么商品卡片列表CommodityList.vue就要抽成組件了。而這個包含多個運營欄目的vue組件我假設它叫ColumnList.vue,在其中通過v-for調用了CommodityList組件。

 
淘寶運營欄目列表

注意:業務來了,我希望把點擊商品卡片的業務放在ColumnList.vue中處理。你們想象一下要怎么做?一種土辦法就是商品按鈕點擊時,Commodity組件$emit通知CommodityList.vue,而CommodityList接着把事件用$emit往上拋,那么ColumnList.vue就能處理這個點擊事件了。這樣做完全沒有問題,但是顯得子組件很不純粹,跟業務都扯上關系了。

那么如何優雅地解決這個問題呢?這個時候,作用域插槽真正派上用場了。

通過作用域插槽將本應該由CommodityList處理的商品卡片點擊業務onCommodityClick提升到ColumnList處理。

<el-row :gutter="20"> <el-col :span="12" v-for="(column, index) in columnList" :key="index"> <el-card class="box-card card-column"> <div slot="header" class="clearfix"> <span>{{column.columnName}}</span> </div> <commodity-list :commodities="column.commodityList"> <template slot-scope="scope"> <!-- 這里只需要給Commodity組件傳入數據,響應Commodity組件的clickCommodity事件即可。 事件不必攜帶參數,完全符合父到子的數據流向,而不會發生子組件又給父組件反向發數據的情況 --> <commodity :modityData="scope.row" @clickCommodity="onCommodityClick(scope.row)"></commodity> </template> </commodity-list> </el-card> </el-col> </el-row> 

而CommodityList組件內部應該是改造成這樣,slot接收來自父組件的商品卡片組件,這里面不涉及關於商品組件的業務,只關注其他業務和布局即可。最終就實現了組件和業務的剝離,這也是組件化的精髓所在吧。不知道有沒有幫到您呢?

<el-row :gutter="20"> <el-col :span="8" v-for="(item, index) in commodities" :key="index" style="margin-top:20px;"> <slot :row="item"></slot> </el-col> </el-row> 

這是我實現的效果,忽略樣式吧,原理都懂了,做個漂亮的卡片有多難?


 
DIY欄目列表

 
DIY欄目列表點擊商品卡片

總結一下,作用域插槽適合的場景是至少包含三級以上的組件層級,是一種優秀的組件化方案!




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM