【Vue3.x】Slot插槽

26 阅读1分钟

1. Simple

Father.vue

<template>
    <FancyButton> Click me! </FancyButton>
</template>

FancyButton.vue

<template>
    <button> 
        <slot></slot>
    </button>
</template>

渲染的时候,<slot></slot>会被替换为Click me!

image.png

2. 默认内容

父组件没传值使用自己的,如果传值了则替换

<template>
    <button> 
        <slot>
            Submit <!-- 默认内容 -->
        </slot>
    </button>
</template>

3. 具名插槽

Father.vue

<template>
    <Son>
        <template v-slot:header> 
            <h1>Here might be a page title</h1>
        </template> 

        //外层的template可写可不写,不写就是默认default
        <template v-slot:default> 
            <p>A paragraph for the main content.</p> 
            <p>And another one.</p>
        </template>

        <template v-slot:footer> 
            <p>Here some contact info</p> 
        </template> 
    </Son>
</template>
<template>
    <Son>
       <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 some contact info</p>
      </template>
   </Son>
</template>

Son.vue

<template>
    <div>
      <header>
        <slot name="header"></slot>
      </header>

      <main>
        <slot></slot>
      </main>

      <footer>
        <slot name="footer"></slot>
      </footer>
    </div>
</template>

image.png

4. 条件插槽

<template>
  <div class="card">
    <div v-if="$slots.header" class="card-header">
      <slot name="header" />
    </div>
    
    <div v-if="$slots.default" class="card-content">
      <slot />
    </div>
    
    <div v-if="$slots.footer" class="card-footer">
      <slot name="footer" />
    </div>
  </div>
</template>

5. 动态插槽

<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>

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

6. 作用域

  • 通常情况下,插槽由父组件传值,也只能获取父组件的响应式数据

6.1 使用子组件作用域

Father.vue

<template>
    <div> 
        <Son v-slot:default="slotProps"> 
            {{slotProps.usertext.firstName}} 
        </Son>
    </div>
</template>    

缩写1:default

<div>
  <!-- 可以把 :default 去掉,仅限于默认插槽 -->
  <Son v-slot="slotProps">
    {{slotProps.usertext.firstName}}
  </Son>
</div>

缩写二:#字號

<Son>
  <template #header="headerProps">
    {{ headerProps }}
  </template>

  <template #default="defaultProps">
    {{ defaultProps }}
  </template>

  <template #footer="footerProps">
    {{ footerProps }}
  </template>
</Son>

Son.vue

<template>
    <div>
        <!-- 设置默认值:{{user.lastName}}获取 Jun -->
        <!-- 如果home.vue中给这个插槽值的话,则不显示 Jun -->
        <!-- 设置一个 usertext 然后把user绑到设置的 usertext 上 -->
        <slot v-bind:usertext="user">{{user.lastName}}</slot>
        <!-- 缩写 -->
        <slot :usertext="user">{{user.lastName}}</slot>
    </div>
</template>
<scripr setup lang='ts'>
    import {ref,reactive} from 'vue'
    const user = reactive({
      firstName:"Fan",
      lastName:"Jun"
    })
</script>

image.png

6.2 多插槽

多插槽必须单独给每一个插槽赋值

<test>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>

  <template v-slot:other="otherSlotProps">
    ...
  </template>
</test>

6.3 解构插槽Prop

常规写法:父组件

<div>
  <test v-slot="slotProps">
    {{slotProps.usertext.firstName}}
  </test>
</div>

缩写:

<div>
  <test v-slot={usertext}>
    {{usertext.firstName}}
  </test>
</div>

不知道行不行

<div>
  <test #default={usertext}>
    {{usertext.firstName}}
  </test>
</div>

将usertext 重命名为 person

<div>
  <test v-slot={usertext:person}>
    {{person.firstName}}
  </test>
</div>

定义默认内容,用于插槽没有值时的情形

<div>
  <test v-slot="{usertext={firstName:'Yang'}}">
    {{usertext.firstName}}
  </test>
</div>