Vue插槽是一种高级技术,它允许在父组件中定义子组件应该渲染的内容。它类似于 HTML 的slot(占位符)标签,但它可以更好地控制子组件的渲染内容。插槽允许你在父组件中定义一个空白区域,在子组件中填充对应内容,并在父组件中对子组件进行渲染。

Vue插槽提供了一种灵活的方式来扩展组件的内容。它可以让你对组件的结构进行更细粒度的控制,同时保持组件的可重用性。

在Vue中,插槽是通过标签来实现的,它可以在子组件中定义多个插槽,父组件可以根据需要选择具体的插槽。插槽还支持具名插槽和作用域插槽,使得组件更加灵活和可维护。它允许你在父组件中对子组件的渲染内容进行更细粒度的控制,从而提高了组件的可重用性和灵活性。


具名插槽(named slots)是Vue.js中的一种插槽,用于在子组件中定义具有特定名称的插槽,并在父组件中将内容插入到这些具名插槽中。

使用具名插槽需要在子组件中使用<slot>标签,并指定name属性来定义插槽名称,例如:

<template>
  <div>
    <h2><slot name="title"></slot></h2>
    <p><slot name="content"></slot></p>
  </div>
</template>

在父组件中,可以通过在<template>标签中使用<slot>标签和name属性来将内容插入到具名插槽中,例如:

<template>
  <my-component>
    <template v-slot:title>
      <h3>这是一个标题</h3>
    </template>
    <template v-slot:content>
      <p>这是内容</p>
    </template>
  </my-component>
</template>

在上面的例子中,<template>标签中的v-slot指令用于指定要插入的具名插槽的名称。在插槽中可以放置任意的HTML代码,包括其他组件、指令等。

使用具名插槽可以使组件更加灵活,可以轻松地在不同的上下文中复用组件,并将不同的内容插入到不同的具名插槽中。


匿名插槽(anonymous slots)是Vue.js中的一种插槽,与具名插槽不同,匿名插槽没有名称,只需要在子组件中使用单个`< slot>`标签即可,例如:

<template>
  <div>
    <h2><slot></slot></h2>
    <p><slot></slot></p>
  </div>
</template>

在父组件中,可以直接使用<template>标签中的任意内容作为匿名插槽的内容,例如:

<template>
  <my-component>
    <h3>这是一个标题</h3>
    <p>这是内容</p>
  </my-component>
</template>

在上面的例子中,组件<my-component>中的匿名插槽将会被父组件中的<h3><p>标签所填充。

使用匿名插槽可以使组件更加通用,可以将任意的内容插入到插槽中,而不需要指定特定的插槽名称。当组件的内容比较简单或者需要在不同的上下文中使用时,匿名插槽是一种很方便的选择。


什么是作用域插槽?

作用域插槽是指能够让组件接收和传递数据到插槽内容的一种插槽。通常,当我们使用插槽时,只能将数据从父组件传递到子组件,但是有时候我们想要在子组件中使用父组件的数据,这时候就可以使用作用域插槽。

作用域插槽是通过在插槽中使用``标签的属性来传递数据。具体来说,我们可以通过在父组件中使用``标签来定义一个作用域插槽,然后在插槽内容中使用一个包裹在``标签中的属性来访问这个插槽。在子组件中,我们可以通过在``标签中使用一个名字为`slot-scope`的属性来定义一个可以访问父组件数据的作用域。

例如,考虑一个父组件中定义的作用域插槽:

<template>
  <div>
    <slot v-bind:user="user">
      {{ user.name }}
    </slot>
  </div>
</template>

在这个例子中,我们在<slot>标签中使用了一个名为user的属性来向插槽内容传递数据。然后,在子组件中,我们可以定义一个可以访问这个user属性的作用域:

<template>
  <div>
    <slot v-bind:user="user">
      <b>{{ user.name }}</b>
      <p>{{ user.age }}</p>
    </slot>
  </div>
</template>

在这个例子中,我们在<slot>标签中使用了一个名为slot-scope的属性来定义一个可以访问父组件数据的作用域。然后,在插槽内容中,我们可以通过访问user.nameuser.age来使用父组件传递的数据。

使用作用域插槽可以大大增加组件的灵活性和可复用性,因为它允许组件在不同的上下文中使用不同的数据,并且不依赖于父组件的结构。


Vue插槽(slot)的高级用法:

  1. 动态插槽名

通常情况下,插槽名是通过属性传递给子组件的,例如:

<my-component>
  <template v-slot:header>
    <h1>这是头部</h1>
  </template>
  <template v-slot:body>
    <p>这是正文</p>
  </template>
</my-component>

但是,一个组件可能需要在渲染过程中动态决定插槽名。这种情况下,可以使用方括号:

<my-component>
  <template v-slot:[headerSlotName]>
    <h1>这是头部</h1>
  </template>
  <template v-slot:[bodySlotName]>
    <p>这是正文</p>
  </template>
</my-component>

然后在组件中,可以使用计算属性来决定插槽名:

<template>
  <div>
    <slot :name="headerSlotName"></slot>
    <slot :name="bodySlotName"></slot>
  </div>
</template>
<script>
export default {
  props: {
    headerSlotName: {
      type: String,
      default: 'header'
    },
    bodySlotName: {
      type: String,
      default: 'body'
    }
  }
}
</script>

这样,父组件就可以传递动态的插槽名。

  1. 作用域插槽

作用域插槽让父组件可以将数据传递给子组件的插槽内容。例如:

<my-component>
  <template v-slot:default="slotProps">
    <p>{{ slotProps.text }}</p>
  </template>
</my-component>

在这个例子中,父组件向子组件传递一个名为text的数据,子组件使用它来渲染插槽内容。子组件定义插槽时,需要使用slotProps特殊变量来声明作用域:

<template>
  <div>
    <slot v-bind:text="message"></slot>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: '这是从父组件传递来的数据'
    }
  }
}
</script>

这样,在子组件中,插槽内容的模板就可以使用slotProps特殊变量来访问这个数据。

  1. 插槽的函数式编程

在Vue 2.6中,可以使用函数式编程编写插槽内容,这种方式可以提高渲染性能。在函数式编程中,插槽内容被当做函数来处理,它会接收一个props对象作为参数,并返回一个节点。例如:

<my-component>
  <template v-slot:default="props">
    {{ props.text.toUpperCase() }}
  </template>
</my-component>

在这个例子中,插槽内容被写成了一个表达式,它会将插槽的text属性转换为大写。如果要使用函数式编程,需要在插槽的模板中使用v-slot的语法:

<template v-slot:default="props">
  {{ props.text.toUpperCase() }}
</template>

这样,插槽内容就是一个函数,可以在组件中使用scopedSlots属性来访问它:

<template>
  <div>
    <slot :text="message" v-bind="scopedSlots.default({ text: message })"></slot>
  </div>
</template>
<script>
export default {
  data() {
    return {
      message: '这是从父组件传递来的数据'
    }
  },
  computed: {
    scopedSlots() {
      return {
        default: props => {
          return this.$createElement('span', props)
        }
      }
    }
  }
}
</script>

这里,使用了$createElement API来创建一个<span>节点,同时将props对象传递给它。然后,返回的这个节点就会被作为插槽内容来渲染。