Vue3 插槽Slot

关于作用域

默认插槽、具名插槽只能访问使用者的作用域,插槽的内容无法访问子组件的数据。Vue模版中表达式只能访问其定义时所处的作用域,这和Javascript的语法作用域规则是一致的。

如果需要访问子组件中的作用域,则使用作用域插槽

默认插槽

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

一个小栗子,使用默认插槽展示父组件中的一个值

javascript 复制代码
<template>
  <div class="box">
    <div>子组件中的展示父组件的插槽如下:</div>
    <slot></slot>
  </div>
</template>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 15px;
  padding: 10px;
  background-color: antiquewhite;
}
</style>
javascript 复制代码
<template>
  <div class="box">
    <A>
      <div style="padding: 10px;">父组件中使用A子组件的默认插槽,显示父组件中的值:{{ defaultVal }}</div>
    </A>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import A from './component/index.vue'

// 默认插槽
const defaultVal = "A use Val";

</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
}
</style>
具名插槽

有时我们在同一个组件中希望使用多个插槽,此时可以使用具名插槽

一个小栗子,同一个子组件中同时使用具名插槽和默认插槽,代码如下

javascript 复制代码
<template>
  <div class="box">
    <slot name="top"></slot>
    <slot></slot>
    <slot name="down"></slot>
  </div>
</template>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
  padding: 10px;
  background-color: slategray;
}
</style>
javascript 复制代码
<template>
  <div class="box">
    <B>
      <top>
        <div>父组件中使用子组件B中的具名插槽top,显示父组件中的值:{{ topVal }}</div>
      </top>
      <div>
import { skeletonItemProps } from 'element-plus';
import { sliderButtonProps } from 'element-plus/es/components/slider/src/button';
        <div>父组件中使用子组件B中的默认插槽,显示父组件中的值:{{ bDefault }}</div>
      </div>
      <down>
        <div>父组件中使用子组件B中的具名插槽down,显示父组件中的值:{{ downVal }}</div>
      </down>
    </B>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import B from './component/b.vue'


// 具名插槽与默认插槽一起使用
const topVal = "B use top";
const bDefault = "B default val";
const downVal = "B use down";

</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
}
</style>
作用域插槽

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

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

一个小栗子,在同一子组件中同时使用具名插槽和作用域插槽

javascript 复制代码
<template>
  <div class="box">
    <slot name="top" :aVal="aVal"></slot>
    <slot :bVal="bVal"></slot>
    <slot name="down" :cVal="cVal" :dVal="dVal"></slot>
  </div>
</template>
<script setup>
const aVal = "a val of c component";
const bVal = "b val of c component";
const cVal = "c val of c component";
const dVal = "d val of c component";
</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
  padding: 10px;
  background-color: cadetblue;
}
</style>
javascript 复制代码
<template>
  <div class="box">
    <C>
      <template #top="{ aVal }">
        <div>
          {{ introVal }}的具名插槽top,并显示子组件中的值:{{ aVal }}
        </div>
      </template>
      <template #default="{ bVal }">
        <div>
          {{ introVal }}的默认插槽,并显示子组件中的值:{{ bVal }}
        </div>
      </template>
      <template #down="{ cVal, dVal }">
        <div>
          {{ introVal }}的具名插槽down,并显示组件中的值:
            cVal = {{ cVal }}, 
            dVal = {{ dVal }}
        </div>
      </template>
    </C>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import C from './component/c.vue'

// 作用域插槽并同时使用具名插槽
const introVal = "父组件中使用子组件C";

</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
}
</style>
无渲染插槽

一些组件可能只包括了逻辑而不需要自己渲染内容,视图输出通过作用域插槽全权交给了消费者组件。我们将这种类型的组件称为无渲染组件。

一个小栗子,在子组件中声明x、y两个点,通过按钮增加它们的值,并在使用者的作用域中展示x、y最新的值。

javascript 复制代码
<template>
  <div class="box">
    <div>
      <div style="margin: 30px; padding: 45px; width: 360px; background-color: aqua;" @click="addX">add x</div>
      <div style="margin: 30px; padding: 45px; width: 360px; background-color: aqua;" @click="addY">add y</div>
    </div>
    <slot name="transVal" :x="x" :y="y"></slot>
  </div>
</template>
<script setup>
import { ref } from 'vue'
const x = ref(23); 
const y = ref(25);
const addX = () => {
  let val = x.value;
  val++;
  x.value = val;
}
const addY = () => {
  let val = y.value;
  val++;
  y.value = val;
}
</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
  padding: 10px;
  background-color: hotpink;
}
</style>
javascript 复制代码
<template>
  <div class="box">
    <E>
      <template #transVal="{ x, y }">
        E component x = {{ x }}, y = {{ y }}
      </template>
    </E>
  </div>
</template>
<script setup>
import E from './component/e.vue'
</script>
<style scoped>
.box {
  display: flex;
  flex-direction: column;
  margin: 20px;
}
</style>

在这个例子中子组件中使用了ref,可以看到子组件中的值发生变化时,在父组件中显示的值也有更新

相关推荐
用户059540174463 小时前
把AI对话记忆存储测试从手工改成Playwright+pytest,覆盖率从20%提到96%,回归时间缩短90%
前端·css
kyriewen3 小时前
别再这样写TypeScript了——Code Review中最常见的8个反模式
前端·javascript·typescript
名字还没想好☜3 小时前
Next.js ‘use client‘ 到底加在哪:Server/Client Components 边界与常见报错
开发语言·前端·javascript·react·next.js
午安~婉4 小时前
GitHub Token/ GitHub Stats统计显示图异常
前端·github·vercel·github token
码云之上4 小时前
AI Agent 工程化总览篇:从 Prompt 到 Harness
前端·人工智能
2501_926978334 小时前
以说明书 DNA 为模板——完整 AGI 的结构图景
前端·人工智能·经验分享·笔记·ai写作
IT_陈寒4 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端
程序员黑豆5 小时前
鸿蒙应用开发:AttributeModifier 使用教程
前端·harmonyos
codeniu5 小时前
TRAE Work 实战 | 从"有个想法"到线上Demo,我全程只靠对话就完成了
前端·trae
妙码生花5 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(五十):增加管理员角色组管理
前端·后端·ai编程