這篇文章不是單純把文檔的話和api拿來翻譯和演示,而是談談我對於slot-scope的使用場景的我的理解,若是理解錯誤,歡迎討論!vue
Vue的插槽slot,分爲3種ajax
前兩種很好理解,不管就是子組件裏定義一個slot佔位符,父組件調用時,在slot對應的位置填充模板就行了。vuex
做用域插槽的慨念,文檔卻只有一句簡單的描述element-ui
有的時候你但願提供的組件帶有一個可從子組件獲取數據的可複用的插槽。api
網絡上大多數文章,也是千篇一概的翻譯這句話,但是僅憑這一句話,我想象不到slot-scope的使用場景。數組
介紹了寫這篇文章的來由,接下來簡述一下本文的脈絡網絡
下面是2個父子的vue組件,先解釋一下2個組件作了什麼事情ui
我建議從數據流動的角度,理解插槽做用域的使用方式,(先學會怎麼用,暫時不用理解爲何要這麼用,使用場景是第二部分)spa
因此數據的流動經歷了翻譯
好啦,這就是slot-scope的使用方法,就這麼簡單,完結撒花~
我貼出所有代碼,方便你們本身研究
父組件的源碼,也就是調用者
<template> <todo-list :todos="todos"> <template slot-scope="slotProps"> <span v-if="slotProps.todo.isComplete">✓</span> <span>{{slotProps.todo.text}}</span> </template> </todo-list> </template> <script> import todoList from './todoList' export default { data () { return { todos: [ { id: 0, text: 'ziwei0', isComplete: false }, { text: 'ziwei1', id: 1, isComplete: true }, { text: 'ziwei2', id: 2, isComplete: false }, { text: 'ziwei3', id: 3, isComplete: false } ] } }, components: { todoList }, } </script>
子組件源碼,也就是封裝組件的人
<template> <ul> <li v-for="todo in todos" :key="todo.id"> <slot :todo="todo"> </slot> </li> </ul> </template> <script> export default { props: { todos: { type: Array } } } </script>
想象一個場景:
當你要給同事封裝一個列表組件,你就須要使用做用域插槽(注意是列表或者相似列表的組件)
你開發的這個列表組件要如何使用呢?
通常來講做爲列表組件的調用者,你的同事先作ajax請求,拿到一個這樣的數組
todos: [ { id: 0, text: 'ziwei0', isComplete: false }, { text: 'ziwei1', id: 1, isComplete: true }, { text: 'ziwei2', id: 2, isComplete: false }, { text: 'ziwei3', id: 3, isComplete: false } ]
以後會把todso傳遞給列表組件吧,那麼列表組件內部作什麼事情呢?
列表內部確定會v-for去幫你的同事渲染這個數組嘛。 就相似element-ui裏的table組件同樣
問題的關鍵就在這裏
列表組件的循環,是發生在組件內部的,因此經過 v-for="todo in todos" ,列表組件很容易拿到每一項todo,但列表拿到數據沒用呀,列表只是一個瓜皮,它又不懂業務邏輯
這個數據是你同事的業務數據,因此這個數據必須得交給組件的調用者,也就是把數據交給你的同事纔對。
那麼你怎樣才能把每一項的todo數據給傳遞出去呢?
你會發現沒有辦法!
不管是用$emit、vuex仍是localStorage,能夠考慮一下,會發現沒有合適的時機,能讓你把todo傳遞出去
因此爲了應對這個場景下,發明了做用域插槽,列表組件能夠經過<slot :todo="todo"></slot>傳遞todo出去
你的同事能夠經過 slot-scope="slotsProps"拿到todo。
回答幾個疑問,其實若是你看懂上面的問題,應該能夠回答下面的問題。這也是我曾經的疑問
疑問1:通常不是咱們傳參數來調用組件嗎?爲何組件還把數據傳遞回來?
的確,調用ui組件時通常是咱們傳遞配置參數給他們。 可是就像elemnt-ui的table組件,你把數組傳遞給table後,是否是有時候須要拿到某一行的row對象 並根據row對象裏的字段,來判斷一些內容的顯示隱藏? 由於循環的過程發生在table組件內部,因此table組件能夠方便的獲取到每一項數據,可是這些數據最終不是給組件的,而是咱們本身要用的業務數據。因此也須要一個方式,讓調用者能拿到本身想要的數據
疑問2: 既然子組件最終還要把我給他的數據,再返還給我,那我當初還幹嗎給它,能不能就本身在父組件裏玩?
若是你不把數據給子組件固然能夠。可是就等於拋棄掉了子組件的封裝,只能你直接在父組件本身寫一個列表 畢竟你不把數據給子組件,子組件還渲染個錘子?沒有父子關係的話,也就不用什麼插槽了。 可是咱不是爲了封裝後,能夠複用嘛,總不能永遠不用組件嘛
疑問3: 父組件須要子組件的數據?那不會有$emit和vuex嘛,爲何要有slot-scope?
$emit和vuex是數據傳遞的一種方法,可是你能夠嘗試用$emit和vuex把todo傳遞給父組件。 你會發現的確沒有合適的鉤子、時機來$emit數據
我認爲幾種說法是不太恰當的,也是給我形成一些困惑的
這種說法,會讓我以爲slot-scope跟emit和vuex是一類東西
這些舉例子的不恰當之處,我以爲是不該該把數據定義在子組件裏。
由於真正的使用場景下,子組件的數據都是來自父組件的。做爲組件內部應該保持純淨。
就像element-ui裏的table組件,確定不會定義一些數據在組件內部,而後傳遞給你。
table組件的數據都是來自調用者的,而後table會把每一行的row,在開發者須要時,傳遞出去。
這些例子雖然不是錯誤,可是我以爲反而不利於理解slot-scope