slot 插槽 ,是用在组件中,向组件分发内容。它的内容可以包含任何模板代码,包括HTML。
vue 在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot
指令)。它取代了 slot
和 slot-scope
这两个目前已被废弃但未被移除且仍有用的特性。但是将会在vue 3 中,被废弃的这两个,不会被支持即无效。
在 2.6.0之前,插槽的用法:
1. 匿名插槽。
以 .vue 这种单文件模块为例
//创建 testSlot.vue组件 <template> <div>
//slot里面也可以设置内容,这个可以设置不传内容时,slot有个默认值替换 <slot>这里面是slot的默认值</slot> <h3>子组件页面</h3> </div> </template> <script> export default { props:[], data:function(){ return {} } } </script> <style> </style>
//引用testSlot组件 <template> <div> <h1>引用testSlot组件的页面</h1> <testSlot> {{msg}} </testSlot> </div> </template> <script> import testSlot from '../components/testSlot' export default{ data () { return {
msg:'这是动态传入的slot的内容'
} }, components:{ testSlot } } </script> <style> </style>
结果:
注意事项:
1) 匿名的方式,就是指把在引用组件的时候,里面传的内容,全部一起传送到组件页面中 <slot></slot> 所在的位置。
2) 只要组件中有 <slot></slot> ,并且不管有多少个,都会全部渲染为传过来的内容。
3) <slot></slot>里面也可以设置内容,这个内容是保证引入组件的时候,有个默认值。当然,<slot></slot>里面不设置内容也可以,这样只是没有默认值,是不会报错的。
4) 传递的内容,也可以是动态的,如同上面一样。但是要注意的是,这个内容不能是 引用组件的时候组件上的内容,要注意作用域。可以查看官网 插槽编译作用域。
5) 如果传递的内容,没有slot 来接收,那么,传递的内容就会被抛弃掉,不会起作用。
5) 那这个时候,如果我想某个 <slot></slot> 传指定的 内容呢?那这个时候就需要具名插槽了。
2. 具名插槽,就是给插槽指定名称,然后 一 一对应
//引入组件的页面 <testSlot> <template slot='header'> <p>------------header----------------</p> <h3>这是header1的内容</h3> <p>这是header2的内容</p> </template> <template slot='footer'> <p>------------footer----------------</p> <h3>这是footer1的内容</h3> <p>这是footer2的内容</p> </template> <p>-----------default-----------------</p> <p>这是default剩下的内容1</p> <p>这是default剩下的内容2</p> </testSlot>
//组件当前页面 <slot>---默认内容---</slot> <h3>slot组件页面</h3> <slot name='header'>---header的默认内容---</slot> <slot name='footer'>---footer的默认内容---</slot>
结果:
注意事项:
1) 引入组件的页面,如果是多个内容,需要用template 包裹起来,并且添加 slot 属性和 自定义值 。
2) slot 的值 需要和 组件中 <slot name='xxx'></slot> name的值相对应。
3) 如果剩下的内容没有包裹起来并制定值的话,那么这些内容会被渲染到 组件中 所有的 <slot></slot> 所在的位置。
4) 如果 slot 设置为default 和 name 设置为default,那就和没设置slot与name是一样的。
5) 和vue 2.6.0 以后的具名插槽相比 template上的 slot='xxx' 只需要 改成 v-slot : xxx 就行了,等号改成了冒号,并且值没有引号,带引号反而会报错。
6) 具名插槽只需要 name值 与 slot的值 对应 ,插槽的顺序是没有关系的。
3. slot-scope 作用域插槽。
这个的作用,主要就是当向组件发送的内容需要和组件的props属性的内容有联系时,才使用这个作用域插槽。简单点来说就是:可以使用 子组件的数据 和 父组件传过来的props的值。
//引入组件的页面 <template> <div> <!--这里向组件传入props--> <slotScope :message='msg'> <!--这里的thing是随便取的名称,不与任何地方对应--> <div slot='sayWhat' slot-scope='thing'>说了:{{thing.said}}</div> <!--这里的val也是随便取的名称,不与任何地方对应--> <template slot='listbox' slot-scope='val'> <p>{{val.send.text}}</p> </template> </slotScope> </div> </template> <script> import slotScope from '../components/slotScope' export default{ data () { return { msg: '这是动态传入的slot的内容', } }, components:{slotScope } } </script> <style> </style>
//组件页面 <template> <div> <!--这里最重要的是 :send=value,send也是可以随便取的,表示要传过去的值--> <slot name='listbox' v-for='value in list' :send='value'></slot> <!--这里最重要的是 :said='message',said也是可以随便取的,表示要传过去的值--> <slot name='sayWhat' :said='message'></slot> <ul> <li v-for='item in list' :key='item.id'>{{item.text}}</li> </ul> </div> </template> <script> export default { props:['message'], data:function(){ return { list:[{ "id":10, "text":"苹果" },{ "id":20, "text":"香蕉" },{ "id":30, "text":"梨" },{ "id":40, "text":"芒果" }] } } } </script> <style> </style>
结果:
注意事项:
1) 作用域插槽主要是 使用子组件的任何数据 来达到自定义显示内容的目的
2) 作用域插槽最最最最最重要的一步,即是在<slot></slot> 上绑定数据 ,如果没有绑定数据,则父组件收到的,只是一个空对象{ }。
3) 作用域插槽中 <slot></slot> 上绑定数据,可以是写死的,也可以是动态绑定的。如果是动态绑定的,则也需要 v-bind:xxx
4) 作用域插槽中 <slot></slot> 上绑定的数据 也可以传一个定义好的有返回值的 mthods 方法。比如我定义了 <slot what='say()'></slot> ,然后say方法为: say:function(){ return '我说了' } 。最后得到的结果就是 "我说了",当然,动态绑定一定要加 v-bind:xxx。
5) 当 <slot></slot> 绑定上数据之后,引用组件的地方 中 发送的内容就能通过 slot-scope 来获取。获取到的内容,就是一个对象,比如 <slot name='sayWhat' said='message'></slot> 我这里绑定 said='message' 之后, 那边接收到的就是 { said:"xxxx"} 一个对象。
6) slot-scope 可以接收任何有效的可以出现在函数定义的参数位置上的 JavaScript 表达式。
vue 2.6.0之后 v-slot 只能用在 组件component 或者 template 上 ,用在 div 或 p 这种标签上是会报错的
1. 具名插槽的变化
<testSlot> <!--2.6.0以前的写法--> <template slot='header'> <p>------------header----------------</p> <h3>这是header1的内容</h3> <p>这是header2的内容</p> </template>
<!--2.6.0之后的写法--> <template v-slot:header> <p>------------header----------------</p> <h3>这是header1的内容</h3> <p>这是header2的内容</p> </template> </testSlot>
1) slot=' xxx ' 改成了 v-slot : xxx 并且冒号后面这个名称不能打引号
2) 组件页面中slot的内容没有变化
3) 2.6.0 之后 具名插槽 v-slot:header 可以缩写为 #header ,必须是有参数才能这样写!!! # = "xxx " 这样是不行的 #default = 'xxx' 这样才可以
2. 作用域插槽的变化
<slotScope :message='msg'> <!--2.6.0之前的写法--> <div slot='sayWhat' slot-scope='thing'>说了:{{thing.said}}</div> <template slot='listbox' slot-scope='value'> <p>{{value.send.text}}</p> </template> <!--2.6.0之前的写法,不能单独用在html标签上--> <template v-slot:sayWhat='thing'> <div>说了:{{thing.said}}</div> </template> <template v-slot:listbox='value'> <p>{{value.send.text}}</p> </template> </slotScope>
1) 两个属性合并成了一个 v-slot : 插槽名称 = ' 传过来的值 ' 。
2) 组件页面中slot的内容没有变化 。
3) v-slot 不能用在 html 标签上 。
4) 如果是默认插槽 可以写成 v-slot='xxx'。
5) 还增加了 可以解构插槽props 和 设置默认值的内容,具体的可以查看官网 解构插槽
3. 新增的还有 动态插槽名
什么是动态插槽名?大致就是动态指令参数也可以用在v-slot上,这个就要涉及到2.6.0新增的 动态参数
<template v-slot:[attrContent]='msg'> xxx </template>
这个 attrContent 会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。 比如这里attrContent 最终的值为 default 则渲染出来的结果 就是 v-slot:default='msg' 。
注意:
1) 单独在 [ ] 方括号中也可以使用表达式,但是不能存在引号和空格
2) 当然 这个动态的值 可以通过 方法,计算属性,或者 data数据 里面的内容。重要的是这个动态的值 是 引用组件的 作用域。简单点说就是父级组件的作用域。
例如,上面 v-slot:sayWhat='thing' 可以写成:
1) v-slot:[first+sec]='thing' 注意 加号两边不能留空格
2) v-slot:[attr]='thing'
3) v-slot:[attrs]='thing'
4) v-slot:[getattr()]='thing'
export default{ data () { return { msg: '这是动态传入的slot的内容', attr:'sayWhat', first:'say', sec:'What', } }, components:{ slotScope }, computed:{ attrs:function(){ return 'sayWhat' } }, methods:{ getattr(){ return 'sayWhat' } } }
到此,插槽的内容就介绍完毕了。^_^ Y