当前位置: 首页 > news >正文

vue3 组合式API:插槽

一、内容与出口

1、<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。插槽内容可以是任意合法的模板内容不局限于文本,可以是多个元素,甚至是组件

// 插槽内容可以是多个元素,也可以是组件
<FancyButton><span style="color:red">Click me!</span><AwesomeIcon name="plus" />
</FancyButton>

<FancyButton>Click me! <!-- 插槽内容 -->
</FancyButton>// <FancyButton> 模板
<button class="fancy-btn"><slot></slot> <!-- 插槽出口 -->
</button>// 最终渲染出的 DOM 是这样:
<button class="fancy-btn">Click me!</button>

二、渲染作用域

1、插槽内容可以访问到父组件的数据作用域,因为插槽内容本身就是在父组件模板中定义的

//两个 {{ message }} 插值表达式渲染的内容都是一样的
<span>{{ message }}</span>
<FancyButton>{{ message }}</FancyButton>

2、插槽内容无法访问子组件的数据。Vue 模板中的表达式只能访问其定义时所处的作用域,换言之:父组件模板中的表达式只能访问父组件的作用域;子组件模板中的表达式只能访问子组件的作用域。

三、默认内容:在外部没有提供内容的情况下,可以为插槽指定默认内容。

//例如:<SubmitButton> 组件<button type="submit"><slot></slot>
</button>//如果想在父组件没有提供插槽内容时,在<button>内渲染 “Submit” ,只需将 “Submit”放在<solt>
//标签之间,来作为默认内容<button type="submit"><slot>Submit <!-- 默认内容 --></slot>
</button>上述案例就可以在父组件中没有提供内容时 <SubmitButton /> 被渲染成 
<button type="submit">Submit</button>//但是如果提供了内容Save,那么显示提供的内容就会取代默认内容
<SubmitButton>Save</SubmitButton>
//渲染成:
<button type="submit">Submit</button>

四、具名插槽

        场景:在父组件中使用的子组件中有多个插槽出口时,为了将内容精准的注入子组件的插槽出口时,此时就需要用到具名插槽

        1、如果一个组件中有多插槽,那么给各个插槽配唯一的ID就成了必要(内容精准的传入到各自目标插槽),<slot>元素有个特殊的attribute name,这类带 name 的插槽被称为具名插槽,没有提供name的 <slot> 出口会隐式的命名为default
例如:<BaseLayout>组件
<div class="container"><header><!-- 标题内容放这里 --></header><main><!-- 主要内容放这里 --></main><footer><!-- 底部内容放这里 --></footer>
</div>//改为具名插槽后
<div class="container"><header><slot name="header"></slot></header><main><slot></slot></main><footer><slot name="header"></slot></footer>
</div>
       2、为具名插槽传入内容,需要使用一个含有v-slot指令<template>的元素,将目标插槽的名字传给v-slot指令 ( v-slot 可简写为 # )
//例如2
<BaseLayout><template v-slot:header></template>
</BaseLayout>//简写
<BaseLayout><template #header><h1>Here might be a page title</h1></template>//带 name 叫具名插槽,没有提供name的 <slot> 出口会隐式的命名为default。<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>
3、如果一个组件中同时接收默认、具名插槽时所有位于顶级的非 <template> 节点都被 “隐式” 视默认插槽的内容(所以就可以省略<template #default>这个标签)
<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><BaseLayout><template #header><h1>Here might be a page title</h1></template><!-- 隐式的默认插槽:位于顶级的非 <template> 节点都被隐式地视为默认插槽的内容 --><p>A paragraph for the main content.</p><p>And another one.</p><template #footer><p>Here's some contact info</p></template>
</BaseLayout>

上述被渲染为

<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>

五、条件插槽:有时候根据内容是否被传入了插槽来渲染某些内容,可以使用 $slots 属性结合 v-if 来实现

<template><div class="card"><div v-if="$slots.header" class="card-header"><slot name="header" /></div><div v-if="$slots.default" class="card-content"><slot /></div><div v-if="$slots.footer" class="card-footer"><slot name="footer" /></div></div>
</template>

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

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

七、作用域插槽名:插槽的内容无法访问到子组件的状态,某些场景下插槽的内容可能想要同时使用父组件、子组件域内的数据,这是需要让子组件在渲染时将一部分数据提供给插槽(可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes

        1、默认插槽:子组件传入插槽的 props 作为了 v-slot 指令的值,可以在插槽内的表达式中访问。

//<MyComponent> 模板<div><slot :text="greetingMessage" :count="1"></slot>
</div>//默认插槽如何接受 props
<MyComponent v-slot="soltProps">{{soltProps.text}} {{soltProps.count}}
</MyComponent>// v-slot="slotProps" 可以类比这里的函数(具体函数参考插槽-作用域插槽)签名,和函数的参数类似
//,我们也可以在 v-slot 中使用解构<MyComponent v-slot="{ text, count }">{{ text }} {{ count }}
</MyComponent>
        2、具名作用域:工作方式也是类似的,插槽 props 可以作为 v-slot 指令的值被访问到:v-slot:name="slotProps"
<MyComponent><template #header="headerProps">{{ headerProps }}</template><template #default="defaultProps">{{ defaultProps }}</template><template #footer="footerProps">{{ footerProps }}</template>
</MyComponent>//向具名插槽中传入 props:
<slot name="header" message="hello"></slot>//注意插槽上的 name 是一个 Vue 特别保留的 attribute,不会作为 props 传递给插槽。因此最终 //headerProps 的结果是 { message: 'hello' }。
        3、同时使用了具名插槽与默认插槽,则需要为默认插槽使用显式的 <template> 标签。尝试直接为组件添加 v-slot 指令将导致编译错误。这是为了避免因默认插槽的 props 的作用域而困惑
<!-- <MyComponent> template -->
<div><slot :message="hello"></slot><slot name="footer" />
</div>//无法使用的错误示范
<!-- 该模板无法编译 -->
<MyComponent v-slot="{ message }"><p>{{ message }}</p><template #footer><!-- message 属于默认插槽,此处不可用 --><p>{{ message }}</p></template>
</MyComponent>//正确的
<MyComponent><!-- 使用显式的默认插槽 --><template #default="{ message }"><p>{{ message }}</p></template><template #footer><p>Here's some contact info</p></template>
</MyComponent>
4、高级列表组件示例

场景:渲染一个列表,并同时会封装一些加载远端数据的逻辑、使用数据进行列表渲染、或者是像分页或无限滚动这样更进阶的功能。然而我们希望它能够保留足够的灵活性,将对单个列表元素内容和样式的控制权留给使用它的父组件

<FancyList :api-url="url" :per-page="10"><template #item="{ body, username, likes }"><div class="item"><p>{{ body }}</p><p>by {{ username }} | {{ likes }} likes</p></div></template>
</FancyList>//在 <FancyList> 之中,我们可以多次渲染 <slot> 并每次都提供不同的数据 (注意我们这里使用了 v-bind 来传递插槽的 props):
<ul><li v-for="item in items"><slot name="item" v-bind="item"></slot></li>
</ul>

无渲染组件


http://www.mrgr.cn/news/93450.html

相关文章:

  • C++智能指针`shared_ptr`详解
  • uploadlabs通关思路
  • LeetCode 解题思路 11(Hot 100)
  • docker-compose部署mongodb副本集集群
  • AI绘画软件Stable Diffusion详解教程(7):图生图基础篇(改变图像风格)
  • Oracle SQL优化实战要点解析(11)——索引、相关子查询及NL操作(1)
  • vue基本功
  • Manus AI使用指南(从说到做,知行合一)
  • GCC RISCV 后端 -- GCC Passes 注释
  • Tomcat之 配置https协议即SSL证书
  • Ubuntu 安装docker docker-compose
  • ubuntu 20.04下ZEDmini安装使用
  • 4.2 使用说明:手册写作利器VNote的使用
  • 【AIGC系列】6:HunyuanVideo视频生成模型部署和代码分析
  • nuxt2 打包优化使用“compression-webpack-plugin”插件
  • java中小型公司面试预习资料(一):基础篇
  • “深入浅出”系列之Linux篇:(13)socket编程实战+TCP粘包解决方案
  • 数据可视化大屏产品设计方案(附Axure源文件预览)
  • DeepSeek私有化部署5:openEuler 24.03-LTS-SP1安装docker
  • 每日一题----------枚举的注意事项和细节