<current-user> {{ user.firstName }} </current-user>
<!-- current-user這一組件的內部實現 --> <span> <slot> {{ user.lastName }} </slot> </span>
這兩段代碼,就已經有了兩個不一樣的Vue做用域,一個是 使用current-user
模塊 的頁面或模塊所具備的Vue實例與對應的做用域,另外一個則是current-user
這一模塊自身對應的Vue實例與對應做用域。html
這兩個做用域彼此互相隔離,再不加任何額外設置的狀況下,沒法訪問到彼此Vue實例,所以不要說什麼data
,methods
之類的,Vue實例所具備的成員通通都是沒法交互的。vue
正是在此基礎上,當咱們須要達成這兩個做用域能彼此知曉一些信息的目標時,不得不採起一些設置。這設置裏就包括了做用域插槽。同時,這兩個做用域能夠認爲存在父子關係,即第一段代碼中使用current-user
模塊的頁面或模塊(好比說,第一段代碼是一個index.html
的節選。)的Vue做用域是第二段代碼的被調用的current-user
模塊(好比說,這段代碼是一個currentuser.vue
文件的節選)的Vue做用域的父做用域(index.html
引入了currentuser.vue
從而使用<curent-user></curent-user>
。在這篇文章裏,稱index.html
的Vue實例是currentuser.vue
的Vue實例的父親)。基於此,當咱們想要讓兩個不能輕易交互但有使用關係的Vue實例交互彼此的信息,那麼有兩種狀況:第一,父知曉子的信息;第二,子知曉父的信息。segmentfault
一開始誤覺得做用域插槽的目的是讓子能知曉父的信息,讓我始終沒法理解做用域插槽。但若是帶着做用域插槽的目的是讓父知子這一想法去看,就以爲官方文檔豁然開朗了。官方文檔傳送門。數組
圖中的user從何而來?這麼來的ide
current-user.vue <template> <span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span> </template> <script> export default { data(){ return { user:{ firstName:"張", lastName:"飛", } } } } </script> <style></style>
是的,這個user
打一開始就是在current-user
這個模塊(current-user.vue
這個文件)內部的Vue做用域(想一想咱們以前說的父和子,也就是說user
數據在子模塊中)中,官方文檔這一章節想要解決的不是模塊內部的{{user.lastName}}
的user
須要父傳入,而是父中{{ user.firstName }}
的user
須要子告知父!測試
通過解析這幅圖上的映射關係,咱們就能明白父爲什麼可以知曉子中的信息。ui
首先,父在使用組件時,不能像原來同樣舒舒服服地直接寫上想要替換掉<slot>
的內容,而是要先用一個<template>
spa
其次,父親必需要知道想要了解的子的名字,若是隻有一個孩子,那這個孩子確定叫'defualt',此時在子中不寫明無所謂,在父中不寫明也無所謂。即圖中的name="default"
和v-slot:default="slotProps"
的:defualt
都可刪去。3d
而後,父親想要知道子中的數據,子必需孝順(開發者必需事先考慮到)而準備好一個slot
標籤並帶上v-bind:[key]="dataOfMine"
屬性。code
如今,如前述所言,孝順的子考慮到父親須要知道本身的數據而作好了準備——而在本身的模塊中寫一個<slot></slot>
併爲它帶上v-bind:[key]="dataOfMine"
屬性。對每個帶v-bind:[key]="dataOfMine"
屬性的<slot>
元素。根據父親的<template></template>
中的屬性v-slot:childname="propertiesSentByChild"
,子告知父的信息(經過v-bind:[key]="dataOfMine"
屬性的<slot>
元素告知的,至於怎麼回事兒你繼續往下看。)會被裝入一個名爲propertiesSentByChild
的父Vue實例做用域內可訪問的對象(或者乾脆理解成Map好了,畢竟最典型的行爲是經過鍵獲得值。),這個對象經過propertiesSentByChild
來引用,經過propertiesSentByChild。key
(對沒錯,這裏的key就是上面幾行那個v-bind:[key]="dataOfMine"
裏的key)獲得dataOfMine
(對沒錯,這裏的key就是上面幾行那個v-bind:[key]="dataOfMine"
裏的dataOfMine),而這個dataOfMine
就是子Vue實例中的數據。好比這裏把dataOfMine
寫成user
的話,那麼那個firstname爲張,lastname爲飛的對象就在父中被propertiesSentByChildkey.key
獲得啦,若是你console.log(propertiesSentByChild.key.firstName)
,你還能獲得「張」的輸出呢。另外這裏的propertiesSentByChild
也是任由開發者本身寫的,只要先後對應一致便可。
到此,做用域插槽的真正目的和寫法已經講明白了。接下來讓咱們看看它的實際使用。
ElementUI的table組件的」自定義列模板「樣式中操做列的按鈕使用了做用域插槽
這裏就只貼有關部分代碼了
<el-table-column label="操做"> <template slot-scope="scope"> <el-button size="mini" @click="handleEdit(scope.$index, scope.row)">編輯</el-button> <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">刪除</el-button> </template> </el-table-column>
這裏使用的時已經廢棄的寫法,貼一下廢棄寫法轉換爲目前推薦寫法的對應關係
仍是老樣子,若是隻有一個<slot>
則 default 寫不寫無所謂。
那麼在這個ElementUI的實例中,能夠看到它對做用域插槽的使用:scope.$index
,這說明$index
是<el-table-column>
模塊內部的一個數據,通過console.log()
大法測試,發現這個對應的就是被點擊刪除的按鈕所在行的行數減一。
這樣一想還挺合理的,<el-table-column>
中的數據遍歷<el-table>
的:data=
綁定的數組而不斷生成,每次生成,其內部(也就是子)都存在一個序號$index
來記錄本身是第幾個,此時咱們想在父中訪問這個數據,就要用到做用域插槽了。