1、插槽内容
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!--使用 slots 进行内容分发-->
<div id="blog-post-demo">
<navigation-link url="/profile">
Your Profile
</navigation-link>
</div>
<script>
/*使用 slots 进行内容分发
* 通过 Vue 的 <slot> 自定义元素,实现在组件内插入内容
* */
Vue.component('navigation-link', {
props: ['url'],
template: `
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
`
})
new Vue({
el: '#blog-post-demo',
})
</script>
在 slot 位置,可以包含任何模板代码,也包括 HTML:
甚至,slot 位置也能包含其他组件:
如果 <navigation-link>
完全没有 <slot>
元素,则 slot 位置传递的所有内容都会被直接丢弃。
2、命名插槽(named slot)
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="blog-post-demo">
<!--为了给命名插槽提供内容,我们可以在父组件模板的 <template> 元素上使用 slot 特性(译注:这样可以将父组件模板中 slot 位置,
和子组件 slot 元素产生关联,便于插槽内容对应传递):-->
<base-layout>
<!--
<template slot="header">
<h1>这里是一个页面标题</h1>
</template>
<p>main 内容的一个段落。</p>
<p>main 内容的另一个段落。</p>
<template slot="footer">
<p>这里是一些联系信息</p>
</template>
-->
<!--也可以对某个普通元素,直接使用 slot 特性:-->
<h1 slot="header">这里是一个页面标题</h1>
<p>main 内容的一个段落。</p>
<p>main 内容的另一个段落。</p>
<p slot="footer">这里是一些联系信息</p>
</base-layout>
</div>
<script>
/*
* 在某些场景中,需要用到多个插槽
* 对于这种场景,<slot> 元素有一个特殊的 name 特性,可以用于定义除默认插槽以外的多余插槽:
*
* */
Vue.component('base-layout', {
template: `
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
`
})
new Vue({
el: '#blog-post-demo',
})
</script>
还有一个未命名插槽(unnamed slot),这是默认插槽,它是用于放置所有不匹配内容的插槽位置。
3、默认插槽内容(default slot content)
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="blog-post-demo">
<submit-button>
Upload
</submit-button>
</div>
<script>
/*
我们可以在 <slot> 元素内部指定一个默认内容。
用户也可以传入slot内容,覆盖默认内容
*/
Vue.component('submit-button', {
template: `
<button type="submit">
<slot>SubmitDefault</slot>
</button>
`
})
new Vue({
el: '#blog-post-demo',
})
</script>
4、编译时的作用域(compilation scope)
当你在 slot 内部想要使用当前作用域下的数据,例如:
|
这些插槽内容,可以访问与插槽模板之外其余部分模板,完全相同的实例属性(也就是处于同一“作用域”)。然而插槽内容无法访问 <navigation-link>
组件内部的作用域。例如,试图访问传入此组件内部的 url
,就会无法正常运行。牢记准则:
父组件模板的内容,全部在父组件作用域内编译;子组件模板的内容,全部在子组件作用域内编译。
5、作用域插槽
在某些场景中,需要提供一个具有「可以访问组件内部数据的可复用插槽(reusable slot)」的组件。例如,一个简单的 <todo-list>
组件,可能包含如下模板:
|
但是在我们应用程序的某些部分中,我们想要将 todo items 中的每一项,都渲染为不同于 todo.text
的内容。这就是引入作用域插槽的原因。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="blog-post-demo">
<todo-list v-bind:todos="todos">
<!--通过 slot-scope 特性访问子组件数据-->
<!-- 将 `slotProps` 作为插槽内容所在作用域(slot scope)的引用名称 -->
<template slot-scope="slotProps">
<!-- 为 todo items 定义一个模板, -->
<!-- 通过 `slotProps` 访问每个 todo 对象。 -->
<span v-if="slotProps.todo.isComplete">✓</span>
{{ slotProps.todo.text }}
</template>
</todo-list>
</div>
<script>
Vue.component('todo-list', {
props: ['todos'],
/*
* 我们为每个 todo 提供一个 slot 元素,然后,将 `todo` 对象作为 slot 元素的一个 prop 传入。
* */
template: `
<ul>
<li
v-for="todo in todos"
v-bind:key="todo.id"
>
<slot v-bind:todo="todo">
{{ todo.text }}
</slot>
</li>
</ul>
`
})
new Vue({
el: '#blog-post-demo',
data: {
todos: [
{id: 1, text: 'text1内容'},
{id: 2, text: 'text2内容', isComplete: true},
{id: 3, text: 'text3内容'}
]
}
})
</script>
在 2.5.0+,slot-scope
不再局限于 <template>
元素,而是可以在任何元素或任何组件中的插槽内容上使用。
5.1解构slot-scope
slot-scope
的值,实际上可以接收任何有效的 JavaScript 表达式,可以出现在函数定义中的参数所在位置。
|
这是让作用域插槽用法,变得思路清晰的好方法。