Vue插槽(Slots)用于向组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。插槽也是属于一种父组件到子组件的组件间通行的方式。
Vue插槽有以下3种类型:
- 默认插槽。
- 具名插槽。
- 作用域插槽。
默认插槽
使用默认插槽时,只需在子组件模板中,将要从外部传入的模板内容,使用<slot>
进行占位即可。
例如有一个名为display-frame
的组件,其模板内容如下:
<div class="display-frame">
<h3>{{title}}</h3>
<!-- 默认插槽,等待组件的使用者进行填充 -->
<slot>
默认插槽内容。使用者没有传递结构时,会显示。
</slot>
</div>
该组件的使用方式如下:
<display-frame title="用户信息">
<!--
在组件标签体中的内容,
会被插入到组件中使用了 <slot> 的位置
-->
<ul>
<li>姓名:{{ user.name }}</li>
<li>性别:{{ user.sex }}</li>
<li>年龄:{{ user.age }}</li>
</ul>
</display-frame>
注:插槽在使用过程中,
<slot>
标签并不限制使用次数,意味着可以在模板中显示两个相同的插槽内容。并且,在使用标签内容插入模板时,标签内容并不需要像组件模板一样需要在外部有一个作为根的元素。
具名插槽
具名插槽就是指给组件插槽位置指定一个名称。外部在使用组件标签时,可以通过插槽名称指定模板要插入到组件中的位置。
定义插槽名称使用的是<slot>
标签的name
属性:
<div class="display-frame">
<slot name="header">
<div>Header</div>
</slot>
<slot name="main">
<div>Main</div>
</slot>
<slot name="footer">
<div>Footer</div>
</slot>
</div>
上方定义了3个插槽,分别是header
、main
和footer
。使用方式有两种:
-
slot
属性:slot="slot-name"
<display-frame> <h3 slot="header">{{ title }}</h3> <img slot="main" src="https://blog.linner.asia/images/avatar.jpg"> <ul slot="main"> <li>姓名:{{ user.name }}</li> <li>性别:{{ user.sex }}</li> <li>年龄:{{ user.age }}</li> </ul> <template slot="footer"> <a href="https://blog.linner.asia">博客主页</a> <a href="https://blog.linner.asia/about/">个人信息</a> <a href="https://blog.linner.asia/contact/">联系用户</a> </template> </display-frame>
slot
属性可以作用在普通元素标签上,也可以作用在<template>
上。并且同个插槽可以同时存放多个元素(模板),只需要定义多个具有相同的slot
属性的元素,或者使用<template>
将它们包裹起来即可。 -
v-slot
指令:v-slot:slot-name
<display-frame> <template v-slot:header> <h3 slot="header">{{ title }}</h3> </template> <template v-slot:main> <img src="https://blog.linner.asia/images/avatar.jpg"> <ul> <li>姓名:{{ user.name }}</li> <li>性别:{{ user.sex }}</li> <li>年龄:{{ user.age }}</li> </ul> </template> <template v-slot:footer> <a href="https://blog.linner.asia">博客主页</a> <a href="https://blog.linner.asia/about/">个人信息</a> <a href="https://blog.linner.asia/contact/">联系用户</a> </template> </display-frame>
v-slot
指令在使用时,只能在<template>
上使用,不能在其它元素标签上使用。
默认插槽就是没有提供
name
的<slot>
。没有提供name
的<slot>
出口会隐式地命名为default
。
渲染作用域
插槽内容可以访问到父组件的数据作用域,因为插槽内容本身是在父组件模板中定义的。例如:
<span>{{ message }}</span>
<display-frame>{{ message }}</display-frame>
两个标签中的{{ message }}
插值表达式渲染的内容都是一样的。
需要注意的是,插槽的内容无法访问子组件的数据(无法直接访问)。因为Vue模板中的表达式只能访问其定义时所处的作用域,这和JavaScript的词法作用域规则是一致的。
也就是说,在哪个文件中定义的模板,其数据的作用域就在哪个文件,其表达式访问的也是该文件中的数据。
作用域插槽
作用域插槽可以让组件在定义插槽位置时,将组件中的一些数据,通过插槽<slot>
,像props
传递数据那样,将数据传递给父组件使用。
向父组件传递数据:
<template>
<div class="user-info">
<slot :username="name" :age="18" :sex="男">
</div>
</template>
<script>
export default {
name: 'user-info',
data() {
name: '张三',
age: 18,
sex: '男',
},
}
</script>
父组件接收数据,并为子组件定义插槽模板,有3种方式:
-
scope
:<user-info> <template scope="userInfo"> <ul> <li>姓名:{{userInfo.username}}</li> <li>性别:{{userInfo.sex}}</li> <li>年龄:{{userInfo.age}}</li> </ul> </template> </user-info>
-
slot-scope
:<user-info> <template slot-scope="userInfo"> <ol> <li>姓名:{{userInfo.username}}</li> <li>性别:{{userInfo.sex}}</li> <li>年龄:{{userInfo.age}}</li> </ol> </template> </user-info>
-
v-slot
:<user-info> <template v-slot="userInfo"> <h3>姓名:{{userInfo.username}}</h3> <h3>性别:{{userInfo.sex}}</h3> <h3>年龄:{{userInfo.age}}</h3> </template> </user-info>
与前两种不同的是,
v-slot
可以指定插槽位置:<template> <div class="user-info"> <slot name="main" :username="name" :age="18" :sex="男"> </div> </template>
<user-info> <template v-slot:main="userInfo"> <ul> <li>姓名:{{userInfo.username}}</li> <li>性别:{{userInfo.sex}}</li> <li>年龄:{{userInfo.age}}</li> </ul> </template> </user-info>
scope
和slot-scope
指定卡槽需要配合slot
属性。v-slot
可以直接在组件标签上使用:<user-info v-slot="userInfo"> <ol> <li>姓名:{{userInfo.username}}</li> <li>性别:{{userInfo.sex}}</li> <li>年龄:{{userInfo.age}}</li> </ol> </user-info>
这3种使用方式都支持解构赋值:
<user-info>
<template slot-scope="{username, sex, age}">
<h2>姓名:{{username}}</h2>
<h4>性别:{{sex}}</h4>
<h4>年龄:{{age}}</h4>
</template>
</user-info>
<user-info v-slot="{username, sex, age}">
<h2>姓名:{{username}}</h2>
<h4>性别:{{sex}}</h4>
<h4>年龄:{{age}}</h4>
</user-info>
<user-info>
<template scope="{username, sex, age}">
<h2>姓名:{{username}}</h2>
<h4>性别:{{sex}}</h4>
<h4>年龄:{{age}}</h4>
</template>
</user-info>
适用于:数据在组件中定义,但根据数据生成的结构需要组件的使用者来决定。
评论