插槽内容
vue实现了一套内容分发的api,这套api基于当前的webcomponents规范草案,将<slot>元素作为承载分发内容的出口。
它允许你想这样合成组件
<navigation-link url="/profile">
ddddd</navigation-link>
然后你再<navigation-link>的模板中可能会写为
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
当组件渲染的时候,这个<slot>元素将会被替换为"your profile"。插槽内可以包含任何模板代码,包括html
<navigation-link url="/profile">
<!-- 添加一个 Font Awesome 图标 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>
甚至其他组件
<navigation-link url="/profile">
<!-- 添加一个图标的组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>
如果<navigation-link>没有包含一个<slot>元素,则任何传入他的内容都会被抛弃。
具名插槽
有些时候我们需要多个插槽。例如,一个假设的<base-layout>组件多模块如下:
<div class="container">
<header>
我们希望把页头放这里
</header>
<main>
我们希望把主要内容放这里
</main>
<footer>
</footer>
</div>
对于这样的情况,<slot>元素有一个特殊的特性:name
这个特性可以用来定义额外的插槽。
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
在向具名插槽提供内容的时候,我们可以在一个父组件<template>元素上使用slot特性
<base-layout>
<template slot="header">
<h1>fasdfasd</h1>
</template>
<p>aaaa</p>
<template slot="footer">
<p>顶顶顶顶</p>
</template>
</base-layout>
另一种slot特性的方法是直接用在一个普通的元素上
<base-layout>
<h1 slot="header">dddddd</h1>
<p>dddd</p>
<h1 slot="footer">dddddd</h1>
</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>
插槽的默认内容
有的时候为插槽提供默认地内容是很有用的。
一个<submit-button>组件可能希望这个按钮的默认内容是"submit",但是同时允许用户覆写为"save"、"upload"或别的内容
你可以在<slot>标签内部制定默认地内容来做到这一点
<button type="submit">
<slot>submit</slot>
</button>
如果父组件为这个插槽提供了内容,则默认地内容会被替换掉。
编译作用域
当你想在插槽内使用数据时,例如,
<navigation-link url="/profile">
dfasdfsdfa{{user.name}}
</navigation-link>
该插槽可以访问跟这个模板的其他地方相同的实例属性也就是说作用域是相同的。但这个插槽不能访问<navigation-link>的作用域,例如尝试url是不会工作的。牢记一条准则
父组件模板的所有东西都会在父级作用域内编译。子组件模板的所有东西都会在子级作用域内编译
作用域插槽
有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽。例如一个简单的<todo-list>组件的模板可能包含了如下代码
<ul>
<li
v-for=“todo in todos”
v-bind:key="todo.id">
{{todo.text}}
</li>
</ul>
但是在我们应用的某些部分,我们希望每个独立的待办项渲染出和todo.text不太一样的东西。这也是作用于插槽的用武之地
为了让这个特性成为可能。你需要做的全部事情就是将待办项内容包裹在一个<slot>元素上,然后将所有和其上下文相关的书传递给这个插槽,在这个例子中这个数据时todo对象;
<ul>
<li
v-for="todo in todos"
v-bind:key="todo.id"
>
<!-- 我们为每个 todo 准备了一个插槽,-->
<!-- 将 `todo` 对象作为一个插槽的 prop 传入。-->
<slot v-bind:todo="todo">
<!-- 回退的内容 -->
{{ todo.text }}
</slot>
</li>
</ul>
现在当我们使用<todo-list>组件的时候,我们可以选择为待办项定义一个不一样的<template>z作为替代方案,并且可以通过slot-scope特性从子组件获取数据
<todo-list v-bind:todos="todos">
将slotprops定义为插槽作用域的名字
<template slot-scope="slotProps">
为待办项自定义一个模板
通过slotprops定制每个待办项
<span v-if="slotProps.todo.isComplete"></span>
</template>
</todo-list>
slot-scope不再限制在<template>元素上使用,而可以用在插槽内的任何元素或组件上
解构slot-scope
如果一个javascript表达式在一个函数定义的参数位置有效,那么这个表达式实际上就可以被slot-scope接受。也就是说你可以在支持的环境下(单文件组件或现代浏览器),在这些表达式中使用es2015结构语法
<todo-list v-bind:todos="todos">
<template slot-scope="{ todo }">
<span v-if="todo.isComplete">✓</span>
{{ todo.text }}
</template>
</todo-list>
这样使作用域插槽变得更干净些