<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
来记录本身是第几个,此时咱们想在父中访问这个数据,就要用到做用域插槽了。