Vue.js 从 2.6.0 版本起,已废弃的使用 slot 属性语法。
有时我们需要多个插槽,例如:对于一个带有如下模板的 <base-layout> 组件,我们需要在 <header>、<main> 和 <footer> 中添加插槽:
<div class="container"> <header> <!-- 我们希望把页头放这里 --> </header> <main> <!-- 我们希望把主要内容放这里 --> </main> <footer> <!-- 我们希望把页脚放这里 --> </footer> </div>
对于这样的情况,站在使用 <base-layout> 组件的角度,我们该如何区分这些插槽呢?幸运的是 <slot> 元素有一个特殊 name 属性。该属性可以用来为插槽定义唯一名称,如下:
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>
注意:一个不带 name 属性的 <slot> 插槽会带有隐含的默认名字 “default”。
<base-layout> 组件定义如上,我们该怎样去使用它呢?在向指定名称的插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并通过 v-slot 指令指定具体插槽的名称,如下:
<base-layout> <!-- 这是提供给名为 header 插槽的默认值 --> <template v-slot:header> <h1>Here might be a page title</h1> </template> <!-- 默认插槽,名为 default 插槽的默认值 --> <p>A paragraph for the main content.</p> <p>And another one.</p> <!-- 这是提供给名为 footer 插槽的默认值 --> <template v-slot:footer> <p>Here's some contact info</p> </template> </base-layout>
现在 <template> 元素中的所有内容都将会被传入相应的插槽。任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容。
然而,如果你希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容,如下:
<base-layout> <template v-slot:header> <h1>Here might be a page title</h1> </template> <template v-slot:default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> <template v-slot:footer> <p>Here's some contact info</p> </template> </base-layout>
上面的任何一种写法都会渲染出如下 HTML:
<div class="container"> <header> <h1>Here might be a page title</h1> </header> <main> <p>A paragraph for the main content.</p> <p>And another one.</p> </main> <footer> <p>Here's some contact info</p> </footer> </div>
注意:v-slot 只能添加在 <template> 上 (只有一种例外情况),这一点和已经废弃的 slot 属性不同。
Vue.js 中 2.6.0 新增。跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 (v-slot:) 替换为字符 #。例如 v-slot:header 可以被重写为 #header,例如:
<base-layout> <template #header>...</template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template #footer>...</template> </base-layout>
然而,和其它指令一样,该缩写只在其有参数的时候才可用。这意味着以下语法是无效的:
<!-- 这样会触发一个警告 -->
<current-user #="{ user }">
{{ user.firstName }}
</current-user>如果你希望使用缩写的话,你必须始终以明确插槽名取而代之:
<current-user #default="{ user }">
{{ user.firstName }}
</current-user>Vue.js 中 2.6.0 新增。动态指令参数也可以用在 v-slot 上,来定义动态的插槽名,例如:
<base-layout> <template v-slot:[dynamicSlotName]> ... </template> </base-layout>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue</title>
<!-- 使用 CDN 引入 Vue 库 -->
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.7.9/vue.js"></script>
</head>
<body>
<div id="app">
<base-layout>
<!-- 这是提供给名为 header 插槽的默认值 -->
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<!-- 默认插槽,名为 default 插槽的默认值 -->
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<!-- 这是提供给名为 footer 插槽的默认值 -->
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
</div>
<script type="text/javascript">
Vue.component('base-layout', {
template: `
<div>
<header style="background:red;">
<slot name="header"></slot>
</header>
<main style="background:green;">
<slot></slot>
</main>
<footer style="background:blue;">
<slot name="footer"></slot>
</footer>
</div>
`
});
var app = new Vue({
el: "#app",
data: {}
});
</script>
</body>
</html>运行效果如下图:
