首页 > 其他分享 >Vue3-slot

Vue3-slot

时间:2024-07-09 15:57:20浏览次数:12  
标签:slot 插槽 具名 默认 内容 Vue3 组件

描述

      为了能在当前组件中使用其他组件中的内容,并且可以改变其他组件中的内容结构。使用的技术就叫做“插槽”
      在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。举例:

  • 子组件<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>
    
  • 父组件

    <script setup>
    import FancyButton from './FancyButton.vue'
    </script>
    
    <template>
      <FancyButton>
        <h2>打开</h2> <!-- slot content -->
      </FancyButton>
    </template>
    
  • 效果图

这就是在App组件显示的内容。
<slot> 元素是一个插槽出口 (slot outlet),标示了父元素提供的插槽内容 (slot content) 将在哪里被渲染。

默认插槽

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

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

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

<button type="submit">
  <slot>
    Submit <!-- 默认内容 -->
  </slot>
</button>

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

<SubmitButton />

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

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

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

<SubmitButton>Save</SubmitButton>

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

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

具名插槽

有时在一个组件中包含多个插槽出口是很有用的。举例来说,在一个 <BaseLayout> 组件中,有如下模板:

<div class="container">
  <header>
    <!-- 标题内容放这里 -->
  </header>
  <main>
    <!-- 主要内容放这里 -->
  </main>
  <footer>
    <!-- 底部内容放这里 -->
  </footer>
</div>

对于这种场景,<slot> 元素可以有一个特殊的 attribute name,用来给各个插槽分配唯一的 ID,以确定每一处要渲染的内容:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

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

在父组件中使用 <BaseLayout> 时,我们需要一种方式将多个插槽内容传入到各自目标插槽的出口。此时就需要用到具名插槽了:

要为具名插槽传入内容,我们需要使用一个含 v-slot 指令的 <template> 元素,并将目标插槽的名字传给该指令:

<BaseLayout>
  <template v-slot:header>
    <!-- header 插槽的内容放这里 -->
  </template>
</BaseLayout>

v-slot 有对应的简写 #,因此 <template v-slot:header> 可以简写为 <template #header>。其意思就是“将这部分模板片段传入子组件的 header 插槽中”。

具名插槽图示

下面我们给出完整的、向 <BaseLayout> 传递插槽内容的代码,指令均使用的是缩写形式:

<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> 节点都被隐式地视为默认插槽的内容。所以上面也可以写成:

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

现在 <template> 元素中的所有内容都将被传递到相应的插槽。最终渲染出的 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>

作用域插槽

插槽的内容无法访问到子组件的状态。

然而在某些场景下插槽的内容可能想要同时使用父组件域内和子组件域内的数据。要做到这一点,我们需要一种方法来让子组件在渲染时将一部分数据提供给插槽。

我们也确实有办法这么做!可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes:

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

当需要接收插槽 props 时,默认插槽和具名插槽的使用方式有一些小区别。下面我们将先展示默认插槽如何接受 props,通过子组件标签上的 v-slot 指令,直接接收到了一个插槽 props 对象:

<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

具名作用域插槽

具名作用域插槽的工作方式也是类似的,插槽 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' }

如果你同时使用了具名插槽与默认插槽,则需要为默认插槽使用显式的 <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>

为默认插槽使用显式的 <template> 标签有助于更清晰地指出 message 属性在其他插槽中不可用:

<MyComponent>
  <!-- 使用显式的默认插槽 -->
  <template #default="{ message }">
    <p>{{ message }}</p>
  </template>

  <template #footer>
    <p>Here's some contact info</p>
  </template>
</MyComponent>

标签:slot,插槽,具名,默认,内容,Vue3,组件
From: https://www.cnblogs.com/dragon-925/p/18292134

相关文章

  • Vue2和Vue3区别的理解和学习1-API结构
    API结构Vue2采用选项式API,包括data、methods、mounted等,而Vue3则引入了组合式API,主要使用setup函数。这种变化使得代码组织更加模块化,更易于复用和维护。选项式API(OptionsAPI)包含多个选项的对象来描述组件的逻辑。选项所定义的属性都会暴露在函数内部的this上,......
  • Vue2和Vue3区别的理解和学习4-模板和语法
    Vue2和Vue3区别的理解和学习4-模板和语法组件定义//vue2exportdefault{data(){return{count:0}},methods:{increment(){this.count++}}}vue3---jsimport{ref}from'vue'expo......
  • Vue3 如何接入 i18n 实现国际化多语言
    1.基本方法在Vue.js3中实现网页的国际化多语言,最常用的包是vue-i18n,通常我们会与vue-i18n-routing一起使用。vue-i18n负责根据当前页面的语言渲染文本占位符,例如:<span>{{t('Login')}}</span>当语言设置为中文时,会将Login渲染为“登录”。vue-i18n-routing负责......
  • 2024已过半,还没试过在vue3中使用ioc容器吗?
    Vue3已经非常强大和灵活了,为什么还要引入IOC容器呢?IOC容器离不开Class,那么我们就从Class谈起Class的应用场景一提起Class,大家一定会想到这是Vue官方不再推荐的代码范式。其实,更确切的说,Vue官方是不推荐基于Class来定义Vue组件。如图所示:社区确实有几款基于Clas......
  • vue3 watch使用方式,如何监听reactive子属性 ref数据等
    代码<template><divclass="box">childB</div></template><scriptlang="ts"setup>import{reactive,watch,ref}from"vue";constdata1=reactive({msg:"childB",abc:"sl......
  • vue3 defineEmits 使用
    概论defineEmits用来定义子组件暴漏给父组件的自定义事件测试代码子组件<template><divclass="box">child</div></template><scriptlang="ts"setup>interfaceEmit{(e:"emitfn1",data:Array<number>):void;......
  • vk-data-goods-sku-popup uniapp vue3示例
    效果图组件简介vk-data-goods-sku-popup是一个uniapp上面方便好用的sku组件,使用场景包括但不限于商品详情页、购物车页面、订单结算页、搜索结果页下面就上代码了,完整vue页面的代码如下<scriptsetup>import{ref,defineEmits,defineProps,computed}from'vue'//显示......
  • 前端面试题28(Vue3的Teleport功能在什么场景下特别有用?能给个例子吗?)
    Vue3的Teleport功能在需要将组件的渲染结果放置在DOM树中与当前组件位置无关的任意位置时特别有用。这通常涉及到需要将某些UI元素(如模态框、弹出菜单、通知、工具提示等)从其逻辑上的父级组件中“提取”出来,放置到页面的更高层级或完全不同的位置,以避免样式冲突或层......
  • 前端面试题27(在实际项目中,如何有效地利用Vue3的响应式系统提高性能?)
    在实际项目中,有效利用Vue3的响应式系统提高性能主要涉及以下几个关键点:1.合理使用reactive和refreactive:用于将复杂的数据结构(如对象或数组)转换成响应式版本。确保只将需要实时更新的数据结构声明为响应式,避免不必要的全局响应化,以减少性能开销。ref:用于创建基本类型......
  • tauri + vue3 如何实现在一个页面上局部加载外部网页?
    ......