插槽 Slots详解(看了不懂我陪)

插槽 Slots详解(看了不懂我陪)插槽是什么 插槽就是子组件中的提供给父组件使用的一个占位符 用表示 父组件可以在这个占位符中填充任何模板代码 如 HTML 组件等 填充的内容会替换子组件的标签

大家好,欢迎来到IT知识分享网。

目录

插槽内容与出口

方案1

方案2

渲染作用域

默认内容

具名插槽

动态插槽名

作用域插槽

默认作用域插槽

具名作用域插槽

 无渲染组件


插槽是什么?
插槽就是子组件中的提供父组件使用的一个占位符,用<slot></slot> 表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot></slot>标签。简单理解就是子组件中留下个“坑”,父组件可以使用指定内容来补“坑”。

插槽内容与出口

方案1

举例来说,这里有一个 <FancyButton> 组件,可以像这样使用:

<script> import FancyButton from './FancyButton.vue' export default { components: { FancyButton } } </script> <template> <FancyButton> Click me <!-- slot content 插槽内容 --> </FancyButton> </template>

而 <FancyButton> 的模板是这样的:

<template> <button class="fancy-btn"> <slot/> <!-- slot outlet <!-- 插槽出口 --> --> </button> </template> <style> .fancy-btn { color: #fff; background: linear-gradient(315deg, #42d392 25%, #647eff); border: none; padding: 5px 10px; margin: 5px; border-radius: 8px; cursor: pointer; } </style>

<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。插槽 Slots详解(看了不懂我陪)

 最终渲染出的 DOM 是这样: 

 插槽 Slots详解(看了不懂我陪)

<button class="fancy-btn">Click me</button>

方案2

通过使用插槽,<FancyButton> 仅负责渲染外层的 <button> (以及相应的样式),而其内部的内容由父组件提供。理解插槽的另一种方式是和下面的 JavaScript 函数作类比,其概念是类似的:

// 父元素传入插槽内容 FancyButton('Click me!') // FancyButton 在自己的模板中渲染插槽内容 function FancyButton(slotContent) { return `<button class="fancy-btn"> ${slotContent} </button>` }

插槽内容可以是任意合法的模板内容,不局限于文本。例如我们可以传入多个元素,甚至是组件: 

<FancyButton> <span style="color:red">Click me!</span> <AwesomeIcon name="plus" /> </FancyButton>

案例: 

<script> import FancyButton from './FancyButton.vue' import AwesomeIcon from './AwesomeIcon.vue' export default { components: { FancyButton, AwesomeIcon } } </script> <template> <FancyButton> Click me </FancyButton> <FancyButton> <span style="color:cyan">Click me! </span> <AwesomeIcon /> </FancyButton> </template>

 FancyButton组件

<template> <button class="fancy-btn"> <slot/> </button> </template> <style> .fancy-btn { color: #fff; background: linear-gradient(315deg, #42d392 25%, #647eff); border: none; padding: 5px 10px; margin: 5px; border-radius: 8px; cursor: pointer; } </style>

  AwesomeIcon组件 

<!-- using an emoji just for demo purposes --> <template>❤️</template>

 效果:

插槽 Slots详解(看了不懂我陪)

渲染作用域

父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。

默认内容

在外部没有提供任何内容的情况下,可以为插槽指定默认内容。比如有这样个 <SubmitButton> 组件:

template

<button type="submit"> <slot></slot> </button> 

如果我们想在父组件没有提供任何插槽内容时在 <button> 内渲染“Submit”,只需要将“Submit”写在 <slot> 标签之间来作为默认内容:

template

<template> <button type="submit"> <slot> Submit <!-- fallback content --> </slot> </button> </template>

现在,当我们在父组件中使用 <SubmitButton> 且没有提供任何插槽内容时:

template

<SubmitButton /> 

“Submit”将会被作为默认内容渲染:

html

<button type="submit">Submit</button> 

但如果我们提供了插槽内容:

template

<SubmitButton>Save</SubmitButton> 

那么被显式提供的内容会取代默认内容:

html

<button type="submit">Save</button>
<script> import SubmitButton from './SubmitButton.vue' export default { components: { SubmitButton } } </script> <template> <!-- use fallback text --> <SubmitButton /> <!-- provide custom text --> <SubmitButton>Save</SubmitButton> </template>

插槽 Slots详解(看了不懂我陪)

具名插槽

这类带 name 的插槽被称为具名插槽 (named slots)。没有提供 name 的 <slot> 出口会隐式地命名为“default”。

案例:

BaseLayout组件 

<template> <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template> <style> footer { border-top: 1px solid #ccc; color: #666; font-size: 0.8em; } </style>

app组件

<script> import BaseLayout from './BaseLayout.vue' export default { components: { BaseLayout } } </script> <template> <BaseLayout> <template #header> <h1>Here might be a page title</h1> </template> <template #default> <p>A paragraph for the main content.</p> <p>And another one.</p> </template> <template #footer> <p>Here's some contact info</p> </template> </BaseLayout> </template>

效果图: 

插槽 Slots详解(看了不懂我陪)

 流程图:插槽 Slots详解(看了不懂我陪)

动态插槽名

动态指令参数在 v-slot 上也是有效的,即可以定义下面这样的动态插槽名:

动态指令参数:这里的 dynamicSlotName会作为一个 JavaScript 表达式被动态执行,计算得到的值会被用作最终的参数。举例来说,如果你的组件实例有一个数据属性 dynamicSlotName,其值为 "href",那么这个绑定就等价于 v-bind:href

<base-layout> <template v-slot:[dynamicSlotName]="url"> ... </template> <!-- 缩写为 --> <template #[dynamicSlotName]="url"> ... </template> </base-layout>

相似地,你还可以将一个函数绑定到动态的事件名称上:

<a v-on:[eventName]="doSomething"> ... </a> <!-- 简写 --> <a @[eventName]="doSomething">

在此示例中,当 eventName 的值是 "focus" 时,v-on:[eventName] 就等价于 v-on:focus

注意这里的表达式和动态指令参数受相同的语法限制。

语法限制:1、动态参数值的限制:动态参数中表达式的值应当是一个字符串,或者是 null。特殊值 null 意为显式移除该绑定。其他非字符串的值会触发警告。

2、动态参数语法的限制:动态参数表达式因为某些字符的缘故有一些语法限制,比如空格引号,在 HTML attribute 名称中都是不合法的

作用域插槽

渲染作用域:插槽的内容无法访问到子组件的状态

某些场景下:插槽的内容可能想要同时使用父组件域内和子组件域内的数据,这时作用域插槽出场了。

模板

<!-- <MyComponent> 的模板 --> <div> <slot :text="greetingMessage" :count="1"></slot> </div>

接收插槽 props 时,默认插槽具名插槽的使用方式有一些小区别:

默认作用域插槽

如何接受 props,通过子组件标签上的 v-slot 指令,直接接收到了一个插槽 props 对象:   

    MyComponent组件 

<script> export default { data() { return { greetingMessage: 'hello' } } } </script> <template> <div> <slot :text="greetingMessage" :count="1"></slot> </div> </template>

引入组件

<script> import MyComponent from './MyComponent.vue' export default { components: { MyComponent } } </script> <template> <MyComponent v-slot="slotProps"> { 
  { slotProps.text }} { 
  { slotProps.count }} </MyComponent> </template> //v-slot="slotProps" 可以类比这里的函数签名,和函数的参数类似, 我们也可以在 v-slot 中使用解构: <template> <MyComponent v-slot="{ text, count }"> { 
  { text }} { 
  { count }} </MyComponent> </template> 

流程图: 

插槽 Slots详解(看了不懂我陪)

结果:

插槽 Slots详解(看了不懂我陪)

具名作用域插槽

具名作用域插槽的工作方式也是类似的,插槽 props 可以作为 v-slot 指令的值被访问到:v-slot:name="slotProps"

FancyList组件

<script> export default { props: ['api-url', 'per-page'], data() { return { items: [] } }, mounted() { // mock remote data fetching setTimeout(() => { this.items = [ { body: 'Scoped Slots Guide', username: 'Evan You', likes: 20 }, { body: 'Vue Tutorial', username: 'Natalia Tepluhina', likes: 10 } ] }, 1000) } } </script> <template> <ul> <li v-if="!items.length"> Loading... </li> <li v-for="item in items"> <slot name="item" v-bind="item"/> </li> </ul> </template>

引入组件 

<script> import FancyList from './FancyList.vue' export default { components: { FancyList } } </script> <template> <FancyList api-url="url" :per-page="10"> <template #item="{ body, username, likes }"> <div class="item"> <p>{ 
  { body }}</p> <p class="meta">by { 
  { username }} | { 
  { likes }} likes</p> </div> </template> </FancyList> </template> <style scoped> .meta { font-size: 0.8em; color: #42b883; } </style>

 效果图:

插槽 Slots详解(看了不懂我陪)

 无渲染组件

MouseTracker组件

<script> export default { data() { return { x: 0, y: 0 } }, methods: { update(e) { this.x = e.pageX this.y = e.pageY } }, mounted() { window.addEventListener('mousemove', this.update) }, unmounted() { window.removeEventListener('mousemove', this.update) } } </script> <template> <slot :x="x" :y="y"/> </template>

引入组件 

<script> import MouseTracker from './MouseTracker.vue' export default { components: { MouseTracker } } </script> <template> <MouseTracker v-slot="{ x, y }"> Mouse is at: { 
  { x }}, { 
  { y }} </MouseTracker> </template>
  • 组件的slot上动态绑定一个值( :key=’value’)
  • 父组件通过v-slot : name = ‘values ’的方式将这个值赋值给 values
  • 最后通过{
    { values.key }}的方式获取数据

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/155650.html

(0)
上一篇 2025-02-17 21:05
下一篇 2025-02-17 21:10

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信