vue3组件 slot插槽渲染作用域

244 阅读2分钟

官方文档链接:cn.vuejs.org/guide/compo…

1.0 插槽内容与出口

含义:通过使用插槽,子组件仅负责渲染外层的,而其内部的内容由父组件提供。

我的理解:子组件提供的插槽出口,父组件填写的对应内容为插槽内容

示图:

image.png

1.1 默认内容

//子组件中
<slot> 
    Submit <!-- 默认内容 --> 
</slot>
//父组件写入内容时,会替换`整个插槽slot`

1.2 具名插槽

  • slot 添加 name="nameID" 属性

为什么要用?

子组件有多个插槽, 就需要用到

父组件怎么指定插槽出口呢? 用v-slot:nameID#nameID

// 子组件BaseLayout
<div class="container">
    <slot></slot>
    <slot name="header"><!-- 具名 --></slot>
    <slot name="footer"><!-- 具名 --></slot>
</div>

// 父组件 
<BaseLayout> 
    <template v-slot:header> <!-- header 插槽的内容放这里 --> </template> 
    <template #footer> <!-- footer 插槽的内容放这里 --> </template> 
</BaseLayout>

1.3 默认插槽

其中1.1 就是默认插槽

  • 父组件怎么用呢? 1.1也告诉我们了, 直接填写, 隐式的默认插槽
  • 或者使用 <template #default>

1.4 条件插槽

结合使用 $slots 属性与 v-if 来实现

// 子组件中
<div v-if="$slots.header" class="card-header"> 
    <slot name="header" /> 
</div>

1.5 动态插槽名

  • [dynamicSlotName]
// 父组件中
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

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

子组件格式: <slot name='插槽名称name' :属性名1="方法/对象" :属性名2="方法/对象">
注:属性可以传多个

<!-- 子组件:ChildComponent.vue -->
<template>
  <div>
    <slot :myMethod="childMethod"></slot>
  </div>
</template>

<script>
export default {
  methods: {
    childMethod() {
      console.log('Child method executed');
    }
  }
}
</script>

2.0 作用域插槽

是什么?

普通情况,插槽出口内容无法访问到子组件的状态, 子组件在渲染时将数据提供给插槽出口

2.1 默认插槽和具名插槽的区别

2.1.1 默认插槽

// 默认插槽
<!-- 子组件 <MyComponent> 的模板 -->
<div>
  <slot :text="greetingMessage" :count="1"></slot>
</div>

//父组件中
<MyComponent v-slot="slotProps">
  {{ slotProps.text }} {{ slotProps.count }}
</MyComponent>

需要解释下:

image.png

解释:

// 解释上图
function MyComponent(slots) {
  const greetingMessage = 'hello'
  return `<div>${
    // 在插槽函数调用时传入 props
    slots.default({ text: greetingMessage, count: 1 })
  }</div>`
}

MyComponent({
  // 类比默认插槽,将其想成一个函数
  default: (slotProps) => {
    return `${slotProps.text} ${slotProps.count}`
  }
})

v-slot="slotProps" 可以类比这里的函数签名,和函数的参数类似,我们也可以在 v-slot 中使用解构:

// 父组件中
<MyComponent v-slot="{ text, count }">
  {{ text }} {{ count }}
</MyComponent>

2.1.2 具名插槽

v-slot:name="slotProps"

#name="slotProps"

向具名插槽中传入 props:

<slot name="header" message="hello"></slot>
  • 注意 默认插槽和具名插槽都支持 静态绑定和动态绑定
message="hello" // 静态绑定
:text="greetingMessage"  // 动态绑定

3. 示例:

没有设置插槽名 默认#default

父组件中: <template #插槽名="{ 属性1, 属性2, ... }"></template>

属性可以接受多个,属性也可以是方法,函数对象,

只取一个可以不用{}接受

属性1是函数对象时,父组件可以这样使用 @click='属性1'

<!-- 父组件 -->
<template>
  <div>
    <child-component>
      <!-- 使用作用域插槽传递函数对象 -->
      <template #default="{ myMethod }">
        <button @click="myMethod">Click me</button>
      </template>
    </child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    parentMethod() {
      console.log('Parent method executed');
    }
  }
}
</script>

总结

插槽slot:父组件向子组件传递元素:父组件发送,子组件接受 插槽作用域:子组件向插槽出口传递数据或方法,如果是方法,父组件又可以通过方法对象操作子组件