天天看点

vue3 基础-具名插槽 & 作用域插槽

具名插槽 和 作用域插槽

上篇对 slot 的基本概念和使用有一个初步的认识, 即通过 slot 的这种设计, 父组件可以在调用子组件的时候, 给组件之间传递一波 dom, 子组件通过 slot 标签来进行接收.

slot 默认值

即当父组件调用子组件, 传递 dom 通过 slot 方式时, 如果指定名称, 则在子组件的 slot 中可用一个默认值来表示

// 子组件
      template: `
      <div>
        <slot>我是默认值啦</slot>
      </div>
      `      

具名插槽 slot

即将原本一个大的内容拆分为几个小的片段, 并通过在占位符 template 中 用 v-slot=xxx 进行命名, 然后子组件会根据命名来灵活使用这些片段.

<!DOCTYPE html>
<html lang="en">

<head>
  <title>具名插槽</title>
  <script src="https://unpkg.com/vue@3"></script>
</head>

<body>
  <div id="root"></div>
  <script>
    const app = Vue.createApp({
      template: `
      <layout>
        <template v-slot:header>
          <div >header</div>
        </template>
        <template v-slot:footer>
          <div >footer</div>
        </template>
      </layout>
    
      `
    })

    app.component('layout', {
      template: `
      <div>
        <slot name="header"></slot>
        <div>content</div>
        <slot name="footer"></slot>
      </div>
      `

    })
    
    const vm = app.mount('#root')

  </script>
</body>

</html>      

在每一个父组件的 template 占位符中, 都是一个命为 v-slot=xxx 的具名插槽, 子组件在使用的时候, 在 slot 标签中记得通过 name="xxx" 的方式即可.

父组件中 template 标签里面的 v-slot:xxx 这个其实可以这样简写:

template: `
<layout>
    <template #header>
        <div >header</div>
    </template>
    <template #footer>
        <div >footer</div>
    </template>
</layout>

`      

这个 slot 的应用场景更多就是 父组件向子组件传递 dom, 如果没有它则通过咱之前的 props 则会非常麻烦.

作用域插槽 slot

即子组件要用到子组件的数据, 但由于 slot 的特性又需要将其传递给父组件, 再传到子组件, 理解还好, 就是有点绕, 来个栗子说明一下.

<!DOCTYPE html>
<html lang="en">

<head>
  <title>作用域插槽</title>
  <script src="https://unpkg.com/vue@3"></script>
</head>

<body>
  <div id="root"></div>
  <script>
    const app = Vue.createApp({
      template: `
      <list v-slot="{ cj }">
        <span>{{cj}}</span>
      </list>
      `
    })

    app.component('list', {
      data () {
        return { list: [1, 2, 3, 4, 5] }
      },
      template: `
      <div>
        <slot v-for="item in list" :cj="item">{{item}}</slot>
      </div>
      `

    })
    
    const vm = app.mount('#root')

  </script>
</body>

</html>      

还是来仔细分析一波, 首先是子组件的 slot.

// 子组件
template: `
<div>
    <slot v-for="item in list" :cj="item">{{item}}</slot>
</div>
`      

这里就是由子组件的数据渲染多个 slot, 并将其数据绑定到名为 cj 的属性中.

然后是父组件在调用 子组件的时候, 通过 v-slot 来接收子组件的 slot 向父组件传递的 cj 属性数据.

// 父组件
 template: `
      <list v-slot="{ cj }">
        <span>{{cj}}</span>
      </list>
      `      

注意这里的 "{ cj }" 是一个 es6 的赋值结构语法而已啦, 核心还是父组件接收子组件 slot 通过 cj 传过来的数据, 然后将这个数据在父组件中通过 span 标签的方式, 一并再传递给子组件 slot . 这样最终渲染就是以 span 来对数据进行渲染啦.

可以看出, 作用域插槽的应用场景为: 当子组件渲染的内容要有父组件来决定时, 则就会用到作用域插槽, 因为其可以接收到子组件传递给父组件的数据. 而之前我们对 slot 的特性认识是: 父模板调用的数据属性, 用的是父模板数据属性; 子模板调用的数据属性, 用的是子模板数据属性.

继续阅读