vue插槽slot、slot-scope、v-slot的区别以及嵌套插槽的使用
slot在英语中作为名词时表示:(可投入东西的)狭长孔,狭槽;(在一系列事件中为某事安排的)时间,空档;(组织、团体等中的)位置,职位。
slot在vue中翻译成插槽:vue实现了一套内容分发的API,这套API的设计灵感源自WebComponents规范草案,将slot元素作为承载分发内容的出口。
可以将slot理解成一个占位的东西,我们提前在模板中放置一个占位的标记,当其他地方要使用模板时就可以通过标记再传进来具体的内容,这样就可以实现更强的复用能力。
slot在和2.x版本中都是支持的,但vue3中已经被官方废弃了。
slot-scopescope英语翻译成:范围,领域。slot-scope也就是插槽作用域,你可能会有疑问为什么会用这么个东西?
在vue中父组件通过slot传入子组件时,父组件中的slot里的内容只能访问父组件作用域里的数据(父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的),但是此时如果我们又想访问子组件中的数据怎么办呢?这就要用到slot-scope这个家伙了。
印象最深的应该就是element-ui中的table组件了,在渲染表格行时我们经常需要用到slot-scope来获取当前行的数据,其实这里就是我们上面说到的场景:
templateel-table:data="tableData"el-table-columnlabel="序号"templateslot-scope="scope"span{{scope.$index+1}}/span/template/el-table-columnel-table-columnlabel="姓名"templateslot-scope="scope"span{{}}/span/template/el-table-columnel-table-columnlabel="年龄"!--支持直接通过{}去解构数据--templateslot-scope="{row}"span{{}}/span/template/el-table-column/el-table/templateslot-scope主要也是配合slot一块使用,在2.x版本中都是支持的,但vue3中已经被官方废弃了。
v-slot中引入,为具名插槽和作用域插槽提供新的统一的语法v-slot指令,用来代替slot和slot-scope,所以如果vue使用的是2.6之后的版本就推荐直接使用v-slot了。
单个插槽单个插槽最简单,一般适用于比较简单的单个自定义内容渲染,子组件:
divclass="son"h3我是子组件/h3slot我是默认内容,如果爸爸你不给我传东西我就显示这里的内容/slot/divscriptexportdefault{name:'Child'}/script父组件:
divclass="father"h3我是父组件/h3Childp儿子,我是爸爸给你传的内容/p/Child/divscriptimportChildfrom'./'exportdefault{components:{Child}}/script具名插槽有时我们需要在子组件中提前定义多个占位符,这样就需要为每个占位符起一个名字,然后父组件中就可以直接通过这个名字来找到自己的位置了。也就是多个slot时,我们就需要给每个slot加一个name名字,允许有一个不加名字(其实如果不加他有一个默认的default名字,父组件中没有被其他slot包含的内容都会被当成这个没有名字的default里的内容)。子组件:
divclass="son"headerslotname="header"/slot/headermainslotname="main"/slotslot/slot/mainfooterslotname="footer"/slot/footer/divscriptexportdefault{name:'Child'}/script父组件:
divclass="father"h3我是父组件/h3Childtemplateslot="header"h1我是header/h1/templatetemplatev-slot:mainp我是main/p/templatetemplatev-slot:defaultpAparagraphforthemaincontent./p/templatetemplate进一步来简写,就相当与@代替v-on,冒号:代替v-bind一样。没有名字的默认插槽可以通过slot="default"或者v-slot:default去找到自己的位置,或者啥也不写Child标签中只要没有被其他slot包裹的内容都是默认插槽的。作用域插槽
也就是我们上面说到的slot-scope,只不过新旧语法上有点差异,在子组件中直接在slot标签上绑定上数据属性:
divclass="son"h3我是子组件/h3slot:user="user"/slot/divscriptexportdefault{name:'Child',data(){return{user:{name:'zhou',age:18}}}}/script父组件:
divclass="father"h3我是父组件/h3!--旧语法,2.6之后不推荐使用了--Childtemplateslot-scope="scope"p姓名:{{}}/pp年龄:{{}}/p/template/Child!--新语法--Childtemplatev-slot="scope"p姓名:{{}}/pp年龄:{{}}/p/template/Child/divscriptimportChildfrom'./'exportdefault{components:{Child}}/script嵌套作用域插槽一般用于第三方组件的二次封装,我们需要在一个作用域插槽中再嵌套一个作用域插槽,比如在element-ui的table组件上二次封装:
divclass="son"el-table:data="tableData"el-table-columnlabel="序号"templateslot-scope="scope"span{{scope.$index+1}}/span/template/el-table-columnel-table-columnv-if="$"label="操作"templateslot-scope="{row}"slotname="action":row="row"//template/el-table-column/el-table/divscriptexportdefault{name:'Child',data(){return{tableData:[]}}}/script$slots用来访问被插槽分发的内容,每个具名插槽有其相应的property(例如:v-slot:foo中的内容将会在vm.$中被找到),所以上面我们可以通过$来判断父组件中有这个插槽时才渲染。
父组件:
divclass="father"h3我是父组件/h3Childtemplateslot="action"slot-scope="{row}"span@click="handleEdit(row)"编辑/span/template/Child/divscriptimportChildfrom'./'exportdefault{components:{Child},methods:{handleEdit(row){(row)}}}/script注意上面父组件中我们并没有用推荐的最新的v-slot指令,是因为我项目中用到的element-ui版本是2.13.2,刚开始想用v-slot发现一直没效果,最终翻源码才发现版本中的vue是2.5的,而v-slot是中才引入的,所以如果想在插槽中使用最新的v-slot指令,记得看下vue的版本哟。