slot
This page assumes that you have read Component Basics. If you don’t know much about components yet, I recommend you read it first.
In 2.6.0, we introduced a new unified syntax for named slots and scoped slots (the
v-slot
directive). It replacesslot
andslot-scope
which are currently deprecated but not removed and are still in the documentation. The origin of the new syntax can be found in this RFC.
Table of Contents
- # #Dynamic slot name
- Abbreviation of named slot
- Other examples
- Deprecated syntax
Vue implements a set of content distribution APIs. This set The design of the API is inspired by the
Web Components draft specification, using the
<slot> element as an outlet to carry distributed content. It allows you to synthesize components like this:
<navigation-link url="/profile"> Your Profile </navigation-link>Then in the template of
<navigation-link>
you might write:<a v-bind:href="url" class="nav-link" > <slot></slot> </a>
When the component is rendered,
<slot></slot> will be replaced with "Your Profile". The slot can contain any template code, including HTML: <navigation-link url="/profile"> <!-- 添加一个 Font Awesome 图标 --> <span class="fa fa-user"></span> Your Profile </navigation-link>
or even other components:
<navigation-link url="/profile"> <!-- 添加一个图标的组件 --> <font-awesome-icon name="user"></font-awesome-icon> Your Profile </navigation-link>
If <navigation-link>
does not contain a <slot>
element, any content between the component's start and end tags will be discarded.
Compile scope
When you want to use data in a slot , for example:
<navigation-link url="/profile"> Logged in as {{ user.name }} </navigation-link>
This slot can access the same instance properties (that is, the same "scope") as elsewhere in the template, but cannot access the scope of <navigation-link>. For example, the url is not accessible:
<navigation-link url="/profile"> Clicking here will send you to: {{ url }} <!-- 这里的 `url` 会是 undefined,因为 "/profile" 是 _传递给_ <navigation-link> 的而不是 在 <navigation-link> 组件*内部*定义的。 --> </navigation-link>
As a rule, please remember:
Everything in the parent template is in the parent scope Compiled; everything in a child template is compiled in the child scope.
fallback content
Sometimes set for a slot It is useful to have specific fallback (i.e. default) content that will only be rendered when no content is provided. For example, in a <submit-button>
component:
<button type="submit"> <slot></slot> </button>
We may want this <button>
to render the text "Submit" in most cases ". To have "Submit" as fallback, we can put it inside the <slot>
tag:
<button type="submit"> <slot>Submit</slot> </button>
Now when I use < in a parent component submit-button>
and when no slot content is provided:
<submit-button></submit-button>
The fallback content "Submit" will be rendered:
<button type="submit"> Submit </button>
But if we provide the content:
<submit-button> Save </submit-button>
Then the provided content will be rendered instead of the fallback content:
<button type="submit"> Save </button>
##Named Slot
Updated since 2.6.0. The deprecated syntax for using theSometimes we need multiple slots. For example, for aslot
feature is
here.
<base-layout> component with the following template:
<div class="container"> <header> <!-- 我们希望把页头放这里 --> </header> <main> <!-- 我们希望把主要内容放这里 --> </main> <footer> <!-- 我们希望把页脚放这里 --> </footer> </div>For such cases, the
<slot> element has a special attribute :
name. This feature can be used to define additional slots:
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div>A
<slot> outlet without a
name will have the implicit name "default" .
v-slot directive on a
<template> element and end it with
v The -slot parameter provides its name in the form:
<base-layout> <template v-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 v-slot:footer> <p>Here's some contact info</p> </template> </base-layout>Now all the content in the
<template> element will be passed into the corresponding slot. Anything not wrapped in
<template> with
v-slot will be treated as the contents of the default slot.
However, if you wish to be more explicit, you can still wrap the contents of the default slot in a <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>
Either way will render:
<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>
Note: v-slot
can only be added on a <template>
(only one exception), this is the same as Deprecated slot
features are different.
Scope slot
##Available since 2.6.0 renew. The deprecated syntax for using theSometimes it is useful to give slot content access to data that is only available in child components. For example, imagine aslot-scope
feature is
here.
<current-user> component with the following template:
<span> <slot>{{ user.lastName }}</slot> </span>We want its fallback content to display the user's first name, instead of the normal user's last name , as follows:
<current-user> {{ user.firstName }} </current-user>However, the above code will not work properly because only the
<current-user> component can access
user and the content we provide is in Rendered by the parent.
user available in the parent's slot content, we can make
user an attribute of the
<slot> element Bind it:
<span> <slot v-bind:user="user"> {{ user.lastName }} </slot> </span>The properties bound to the
<slot> element are called
slot prop. Now in the parent scope, we can give v-slot a value that defines the name of the slot prop we provide:
<current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> </current-user>In this example, we choose to include All slot prop objects are named
slotProps, but you can use any name you like.
Abbreviated syntax for exclusive default slot
In the above case, when the content is provided Only in the default slot, the component's label can be used as a template for the slot. In this way, we can usev-slot directly on the component:
<current-user v-slot:default="slotProps"> {{ slotProps.user.firstName }} </current-user>This way of writing can be simpler. Just like unspecified content is assumed to correspond to the default slot,
v-slot without an argument is assumed to correspond to the default slot:
<current-user v-slot="slotProps"> {{ slotProps.user.firstName }} </current-user>Note the abbreviated syntax for the default slot
Cannot be mixed with named slots as it will lead to ambiguity of scope:
<!-- 无效,会导致警告 --> <current-user v-slot="slotProps"> {{ slotProps.user.firstName }} <template v-slot:other="otherSlotProps"> slotProps is NOT available here </template> </current-user>Whenever multiple slots are present, always use the complete
<template> ; Syntax:
<current-user> <template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template> <template v-slot:other="otherSlotProps"> ... </template> </current-user>
Destructuring slot Prop
scope slot The inner workings is to wrap the contents of your slot in a function that takes a single argument:function (slotProps) { // 插槽内容 }
This means that the value of v-slot
can actually be any JavaScript expression that can be passed as a parameter in the function definition. So in a supported environment (Single File Component or Modern Browser), you can also use ES2015
Destructuring to pass in the specific The slot prop is as follows:
<current-user v-slot="{ user }"> {{ user.firstName }} </current-user>
This can make the template more concise, especially when the slot provides multiple props. It also opens up other possibilities for prop renaming, such as renaming user
to person
:
<current-user v-slot="{ user: person }"> {{ person.firstName }} </current-user>
You can even define fallback content for slot props It is undefined:
<current-user v-slot="{ user = { firstName: 'Guest' } }"> {{ user.firstName }} </current-user>
Dynamic slot name
2.6 .0 Added
Dynamic command parameters can also be used on v-slot
to define dynamic slot names:
<base-layout> <template v-slot:[dynamicSlotName]> ... </template> </base-layout>
Abbreviation for named slot
##2.6.0 NewLike
v-on and
v-bind,
v-slot also has an abbreviation, that is, all the content before the parameter (
v -slot:) is replaced with the characters
#. For example
v-slot:header can be rewritten as
#header:
<base-layout> <template #header> <h1>Here might be a page title</h1> </template> <p>A paragraph for the main content.</p> <p>And another one.</p> <template #footer> <p>Here's some contact info</p> </template> </base-layout>However, like other directives, this abbreviation is only used when it has parameters. Available. This means that the following syntax is invalid:
<!-- 这样会触发一个警告 --> <current-user #="{ user }"> {{ user.firstName }} </current-user>If you wish to use an abbreviation, you must always replace it with the explicit slot name:
<current-user #default="{ user }"> {{ user.firstName }} </current-user>
Other examples
Slot prop allows us to convert slots into reusable templates that can be rendered based on the input props Different content. This is most useful when designing reusable components that encapsulate data logic while allowing the parent component to customize part of the layout.
For example, we want to implement a<todo-list> component, which is a list and contains layout and filtering logic:
<ul> <li v-for="todo in filteredTodos" v-bind:key="todo.id" > {{ todo.text }} </li> </ul>We can add each todo As a slot of the parent component, control it through the parent component, and then bind
todo as a slot prop:
<ul> <li v-for="todo in filteredTodos" v-bind:key="todo.id" > <!-- 我们为每个 todo 准备了一个插槽, 将 `todo` 对象作为一个插槽的 prop 传入。 --> <slot name="todo" v-bind:todo="todo"> <!-- 后备内容 --> {{ todo.text }} </slot> </li> </ul>Now when we use
<todo-list> component, we can choose to define a different
<template> for todo as an alternative, and can get data from sub-components:
<todo-list v-bind:todos="todos"> <template v-slot:todo="{ todo }"> <span v-if="todo.isComplete">?</span> {{ todo.text }} </template> </todo-list>
This is just the tip of the iceberg of where scope slots come in handy. For more real-life usage of scoped slots, we recommend browsing libraries such as Vue Virtual Scroller, Vue Promised and Portal Vue.
Obsolete syntax
v The -slot
directive was introduced in Vue 2.6.0 to provide an API alternative with better support for theslot
andslot-scope
features.v-slot
For complete details, see this RFC. Theslot
andslot-scope
features will still be supported in all subsequent 2.x versions, but have been officially deprecated and will not appear in Vue 3.
##Named slot with slot attribute
slotDeprecated since 2.6.0. Please check here for the new recommended syntax.
##Use the special
attribute on <template>
to pass content from the parent to the named slot (put Here
mentioned <base-layout> component as an example):
Or directly use the <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>
attribute on an ordinary element Above:
There is actually an unnamed slot here, which is <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>
, capturing all unmatched content. The HTML rendering results of the above two examples are: <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>
slot-scope attribute Deprecated since 2.6.0. Please check
for the new recommended syntax. slot-scopeattribute on
<template> to receive props passed to the slot (put
hereMentioned
<slot-example> component as an example):
<slot-example> <template slot="default" slot-scope="slotProps"> {{ slotProps.msg }} </template> </slot-example>
The slot-scope
here declares that the received prop object will exist in the <template>
scope as a slotProps
variable. You can name slotProps
arbitrarily like you name JavaScript function parameters.
The slot="default"
here can be ignored as implicit writing:
<slot-example> <template slot-scope="slotProps"> {{ slotProps.msg }} </template> </slot-example>
slot-scope
The feature can also be used directly for non- <template>
Elements (including components): The value of
<slot-example> <span slot-scope="slotProps"> {{ slotProps.msg }} </span> </slot-example>
slot-scope
can accept any valid JavaScript that can appear in the parameter position of the function definition expression. This means that in supported environments (Single File Components or Modern Browsers), you can also use ES2015
Destructuring# in expressions ##, as follows:
<slot-example> <span slot-scope="{ msg }"> {{ msg }} </span> </slot-example>Use
heredescribed <todo-list> as an example, and its equivalent use
slot-scope The code for is:
<todo-list v-bind:todos="todos"> <template slot="todo" slot-scope="{ todo }"> <span v-if="todo.isComplete">?</span> {{ todo.text }} </template> </todo-list>