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,可以看到子组件中的值发生变化时,在父组件中显示的值也有更新

相关推荐
好多吃的啊25 分钟前
css 控制虚线刻度尺寸
前端·css
Pluto & Ethereal36 分钟前
uni-app生命周期
前端·uni-app
QGC二次开发1 小时前
Vue3:mitt实现组件通信
前端·javascript·vue.js·vue
Fightting882 小时前
Openpyxl 插入数据添加数据
前端·windows·python
only-lucky2 小时前
QT之QML从入门到精通(第三章)
前端·javascript·qt
葱不爱姜2 小时前
JavaScript的作用域(四)块作用域
开发语言·javascript
anyup_前端梦工厂2 小时前
探秘 Web Bluetooth API:连接蓝牙设备的新利器
前端·javascript·html
anyup_前端梦工厂3 小时前
深入理解 JavaScript 三大作用域:全局作用域、函数作用域、块级作用域
前端·javascript·html
customer083 小时前
【开源免费】基于SpringBoot+Vue.JS服装商城系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
等你许久_孟然3 小时前
【webpack4系列】设计可维护的webpack4.x+vue构建配置(终极篇)
前端·javascript·vue.js