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

相关推荐
鎈卟誃筅甡10 分钟前
Vuex 的使用和原理详解
前端·javascript
呆呆小雅14 分钟前
二、创建第一个VUE项目
前端·javascript·vue.js
m0_7482393321 分钟前
前端(Ajax)
前端·javascript·ajax
Fighting_p24 分钟前
【记录】列表自动滚动轮播功能实现
前端·javascript·vue.js
前端Hardy26 分钟前
HTML&CSS:超炫丝滑的卡片水波纹效果
前端·javascript·css·3d·html
技术思考者30 分钟前
HTML速查
前端·css·html
缺少动力的火车30 分钟前
Java前端基础—HTML
java·前端·html
Domain-zhuo43 分钟前
Git和SVN有什么区别?
前端·javascript·vue.js·git·svn·webpack·node.js
雪球不会消失了1 小时前
SpringMVC中的拦截器
java·开发语言·前端
李云龙I1 小时前
解锁高效布局:Tab组件最佳实践指南
前端