组件定义出来实际上就是一个html标签,通过props为这个标签定义属性,通过自定义事件为这个标签添加change等等事件,插槽(slot)就是把这个html标签内的内容显示出来(可以是html,也可以是别的组件)。如果没有插槽这个html标签内的内容会被抛弃。
1.插槽内容
有一个写好的组件<navigation-link>,在它的模板中这样写
<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>
然后在组件渲染的时候,<navigation-link>这个标签内包含的任何内容会把<slot>这个元素替换掉。
如果<navigation-link>
没有包含一个 <slot>
元素,则任何传入它的内容都会被抛弃。
2.具名插槽
如果我们需要的个插槽,就需要多个<slot>元素,哪组件传入的内容怎么区分呢?<slot>元素有一个特殊的特性:name,可以解决这种问题。
我们有一个组件<base-layout>,模板如下:
<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>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template slot="footer">
<p>Here's some contact info</p>
</template>
</base-layout>
还有另外一种使用,就是将<slot>的特性直接用在普通元素上。
<base-layout>
<h1 slot="header">Here might be a page title</h1>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<p slot="footer">Here's some contact info</p>
</base-layout>
如上,我们有一个未命名的插槽,这个插槽是默认插槽,所有未被分配的内容,会被分配到这个插槽上。
3.编译作用域
父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译。
<navigation-link url="/profile">
Logged in as {{ user.name }}
</navigation-link>
如上所示,如果在插槽内访问url是不会工作的。url通过props传到了子组件<navigation-link>中,只能在这里访问。
4.作用域插槽
上面说,没法在插槽内访问url,我们可以使用slot-scope特性从子组件获取数据。
<navigation-link url="/profile">
<template slot-scope="scope">
{{scope.a}}{{scope}}
</template>
</navigation-link>
<navigation-link>组件
<template>
<a>
<slot :a="url"></slot> //这里用什么属性接收数据,在父组件插槽中,就用什么属性
</a>
</template>
<script>
export default {
props: ["url"],
};
</script>
这样scope.a会渲染成/profile,scope渲染成{"a":"/profile"}.
在插槽中调用数据,取决你传给插槽是用的什么属性。slot接收到数据,被定义成scope这个对象,对象里的属性为slot接受数据时使用的属性。
在 2.5.0+,slot-scope
不再限制在 <template>
元素上使用,而可以用在插槽内的任何元素或组件上。