插槽
含义
插槽(slot)是vue为组件的封装者提供的能力,允许在封装组件时,把不确定的,希望由用户指定的部分定义为插槽。可以理解为组件封装期间,为用户预留的内容占位符。
封装组件的目的是为了实现UI结构的复用
假设在一个组件<myCount>
中,需要有一个部分,这个部分是不确定的,可能是<div>,<p>,<ul>,<table>
...
在使用<myCount>
标签中,直接在<myCount></myCount>
内输入自定义的内容,此内容替代组件封装中的<slot>
基本使用
vue官方规定,每一个slot插槽,都要有一个name名称,如果省略了slot的name属性,则默认名称为default
<!-- 子组件中预留插槽 --> <template> <div class="contianer"> <h1>这是子组件</h1> <slot name="default"></slot> </div> </template> <!-- 父组件使用子组件时,向插槽填充内容 --> <child-comp> <p>填充到插槽的内容</p> </child-comp>
v-slot/#
假设组件有多个插槽,需要将内容放到指定的某一个插槽中。
v-slot,v-开头说明这是一个指令,它不能直接用在元素身上,v-slot只能用于<template>
中,所以必须<template v-slot="">
,引号内是插槽的名字。
<template>
是一个虚拟的标签,只起到包裹性质的作用,不会被渲染成任何实质上的元素。
如果子组件没有预留插槽,那么父组件填充给子组件的自定义内容会被丢弃
具名插槽
-
#:包裹一个
<template>
标签,同时在<template>
中通过v-slot:名称
指明插槽的名称。简写形式为#名称
,且v-slot
只能使用在<template>
和组件标签上,普通 HTML 标签不行 -
v-slot:
v-slot="名称"
指明插槽名称 -
如果不指定插槽名称,那么自定义内容会被填充到所有的
default
插槽当中 -
同一插槽填充多个内容,是追加不是覆盖
后备内容
子组件可以为插槽提供后备(默认)内容,当父组件没有提供自定义内容时,后备内容就会生效。
<!-- 子组件提供后备内容 --> <template> <div class="contianer"> <h1>这是子组件</h1> <slot>这是后备内容,父组件没有提供自定义内容就会生效</slot> </div> </template> <!-- 父组件没有提供自定义内容 --> <child-comp> </child-comp>
子组件预留多个具名插槽
<template> <div class="contianer"> <h1>这是子组件</h1> <slot name="title">title 具名插槽</slot> <hr /> <slot name="content">content 具名插槽</slot>> <hr /> <slot>没有设置 name 名称则默认为 default</slot> <slot name="default"></slot> </div> </template>
父组件向具名插槽提供自定义内容
在child标签内加入template。
<child-comp> <h1 slot="title">《赠汪伦》</h1> <template v-slot:title> <h1>《静夜思》</h1> </template> <!-- 简写形式 --> <template #content> <p>床前明月光,疑是地上霜。</p> <p>举头望明月,低头思故乡。</p> </template> <template> <p>这段内容没有指定名称,会被填充到所有 default 插槽中。</p> </template> </child-comp>
作用域插槽
在封装组件时,为预留的<slot>
提供属性对应的值。这种用法叫做作用域插槽。
定义在子组件中的数据,在父组件中使用。
子:<slot name="content" msg="abcde"></slot>
父:<template #content="obj"> <p>{{ obj }}</p> </template>
此时页面显示的内容为:{ "msg": "abcde" }
一个对象。
通过父组件插槽获得了子元素的数据。
如果子组件中没有为插槽指定任何数据,那么父组件获得的就是一个空对象{}
。
建议使用scope接收数据,eg:<template #content="scope">
scope是一个对象,以键值对的形式存在,键为子元素的"msg"。
解构赋值
-
组件可以为插槽绑定自定义属性
props
,这种插槽叫作用域插槽 -
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定
<!-- 子组件为插槽绑定 props 数据 --> <template> <slot v-for="item in list" :user="item"></slot>//定义的user属性。 </template>
export default { data() { return { list: [ { id: 1, name: 'Lily', state: true, }, { id: 2, name: 'Ben', state: false, }, { id: 3, name: 'Water', state: true, }, ], } }, }
父组件向插槽提供自定义内容时,可以接收作用域插槽提供的数据:
<child-comp> <template #default="scope"> <p>作用域插槽提供的数据:{{ scope }}</p> </template> </child-comp>
其中接收到的数据 scope
是一个对象。
// scope 的内容 { "user": { "id": 1, "name": "Lily", "state": true } } { "user": { "id": 2, "name": "Ben", "state": false } } { "user": { "id": 3, "name": "Water", "state": true } }
在接收作用域插槽提供的数据时可以使用解构赋值。
<child-comp> <template #default="{user}"> <p>id:{{ user.id }}</p> <p>name:{{ user.name }}</p> <p>state:{{ user.state }}</p> </template> </child-comp>
获得数组中某一项的数据
子:<slot name="footer" :user="list" ></slot>
父:<template #footer="{user}"> <p>{{ user[2] }}</p> </template>