目录
插槽 slot
Vue 实现了一套内容分发的 API,将<slot>
元素作为承载分发内容的出口。这个自定义的<slot>
元素,可以让我们向一个组件传递自定义的内容。
插槽基本使用
在子组件中,使用特殊的元素<slot>
就可以为子组件开启一个插槽。
该插槽插入什么内容取决于父组件如何使用。
我们可以看一个简单的例子:
<div id="app">
<!-- 默认内容 -->
<my-component></my-component>
<!-- 按钮替换内容 -->
<my-component><button type="button">按钮</button></my-component>
</div>
<template id="my-component">
<div>
<h1>我是组件标题</h1>
<p>我是组件内容</p>
<slot><p>我是 slot 默认内容</p></slot>
</div>
</template>
<script type="text/javascript">
Vue.component('my-component', {
template: '#my-component'
})
const app = new Vue({
el: '#app'
})
</script>
<slot>
中的内容表示,如果没有在该组件中插入任何其他内容,就默认显示该内容。 给该组件添加内容,添加的内容会替换<slot></slot>
。
具名插槽
自 2.6.0 起有所更新。
slot
attribute 已废弃,官方推荐我们使用v-slot
来替代。
当子组件的功能复杂时,子组件的插槽可能并非是一个。比如我们封装一个导航栏的子组件,可能就需要三个插槽,分别代表左边、中间、右边。对于这样的情况,<slot>
元素有一个特殊的 attribute:name
。这个 attribute 可以用来定义额外的插槽:
· <div id="app">
<my-nav-bar></my-nav-bar>
<my-nav-bar>
<a slot="left">返回</a>
<input slot="center" type="text" value="" placeholder="search ..."/>
<button slot="right" type="button">查询</button>
</my-nav-bar>
</div>
<template id="my-nav-bar">
<div>
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script type="text/javascript">
Vue.component('my-nav-bar', {
template: '#my-nav-bar'
})
const app = new Vue({
el: '#app'
})
</script>
在向具名插槽提供内容的时候,我们可以在一个 <template>
元素上使用 v-slot
指令,并以 v-slot
的参数的形式提供其名称:
<div id="app">
<my-nav-bar>
<template v-slot:left>
<a>返回</a>
</template>
<template v-slot:center>
<input type="text" value="" placeholder="search ..."/>
</template>
<template v-slot:right>
<button type="button">查询</button>
</template>
</my-nav-bar>
</div>
注意:
v-slot
只能添加在一个<template>
上,只有默认插槽时,组件的标签才可以被当作插槽的模板来使用。
v-slot
也有语法糖,即把参数之前的所有内容 v-slot:
替换为字符#
:
<div id="app">
<my-nav-bar>
<template #left>
<a>返回</a>
</template>
<template #center>
<input type="text" value="" placeholder="search ..."/>
</template>
<template #right>
<button type="button">查询</button>
</template>
</my-nav-bar>
</div>
作用域插槽
自 2.6.0 起有所更新。
slot-scope
attribute 已废弃,官方推荐我们使用v-slot
来替代。
作用域插槽是 slot 一个比较难理解的点,而且官方文档说的又有点不清晰。
这里,我们用一句话对其做一个总结:父组件替换插槽的标签,但是内容数据由子组件来提供。
例如,子组件中包括一组数据,比如languages : ['Java', 'JavaScript', 'Python', 'Go']
:
<div id="app">
<my-component></my-component>
</div>
<template id="my-component">
<div>
<slot>
<div v-for="lang in languages"> {{ lang }}</div>
</slot>
</div>
</template>
<script type="text/javascript">
Vue.component('my-component', {
template: '#my-component',
data() {
return {
languages : ['Java', 'JavaScript', 'Python', 'Go']
}
}
})
const app = new Vue({
el: '#app'
})
</script>
需要在多个界面进行展示:某些界面是以水平方向一一展示的,某些界面是以列表形式展示的,某些界面直接展示一个数组。
这时利用 slot 作用域插槽就可以了。
<div id="app">
<my-component></my-component>
<my-component>
<template slot-scope="data">
<div>{{ data.data.join(' ') }}</div>
</template>
</my-component>
</div>
<template id="my-component">
<div>
<slot :data="languages">
<div v-for="lang in languages"> {{ lang }}</div>
</slot>
</div>
</template>
在父组件使用我们的子组件时,从子组件中拿到数据:我们通过 <template slot-scope="data">
获取到data
属性,再通过data.data
就可以获取到刚才我们传入的data
了。
绑定在 <slot>
元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot
来定义我们提供的插槽 prop 的名字:
<template v-slot="data">
<div>{{ data.data.join(' ') }}</div>
</template>
一个不带 name
的 <slot>
出口会带有隐含的名字default:
<template v-slot:default="data">
<div>{{ data.data.join(' ') }}</div>
</template>
<!-- 缩写 -->
<template #default="data">
<div>{{ data.data.join(' ') }}</div>
</template>