为什么用插槽

组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力。

  组件的复用性常见情形如在有相似功能的模块中,他们具有类似的UI界面,通过使用组件间的通信机制传递数据,从而达到一套代码渲染不同数据的效果。

  然而这种利用组件间通信的机制只能满足在结构上相同,渲染数据不同的情形;假设两个相似的页面,他们只在某一模块有不同的UI效果,以上办法就做不到了。可能你会想,使用 v-if 和 v-else来特殊处理这两个功能模块,不就解决了?很优秀,解决了,但不完美。极端一点,假设我们有一百个这种页面,就需要写一百个v-if、v-else-if、v-else来处理?那组件看起来将不再简小精致,维护起来也不容易。

  而 插槽 “SLOT”就可以完美解决这个问题

什么情况下使用插槽

顾名思义,插槽即往卡槽中插入一段功能块。还是举刚才的例子。如果有一百个基本相似,只有一个模块功能不同的页面,而我们只想写一个组件。可以将不同的那个模块单独处理成一个卡片,在需要使用的时候将对应的卡片插入到组件中即可实现对应的完整的功能页。而不是在组件中把所有的情形用if-else罗列出来

什么是编译作用域

父组件模板的内容在父组件的作用域内编译,子组件模板的内容在子组件的作用域内编译

单个插槽 (匿名插槽)

在没有使用插槽前,组件内部写入的后备内容都会被抛弃,原因很简单,在父组件渲染的时候,会使用子组件里的内容来替换它在父组件的占位。如果不想被丢弃,就需要在子组件中使用单个插槽来接收内容

  单个插槽一般都是匿名的,当然也可以给他命名,默认未命名情况下,Vue2.6+版本默认为v-slot:default或简写#default

// 父组件中定义卡片
<div>
    <h1>父组件</h1>
    <child-component>
        <p>卡片内容1</p>
        <p>卡片内容2</p>
    </child-component>
</div>
// child-component组件中使用slot接收
<div>
    <h2>子组件</h2>
    <slot>
        插槽默认内容
    </slot>
</div>

在案例中除了有卡片内容与插槽内容,我们还看到了在<slot>中定义的一段话,它是插槽标签的默认内容,会在子组件编译作用域内编译,只有当宿主元素为空,且没有相应的插入内容时才显示。上面的案例我们可以得到如下结果:

// 渲染结果:
<div>
    <h1>父组件</h1>
    <div>
        <h2>子组件</h2>
        <p>卡片内容1</p>
        <p>卡片内容2</p>
    </div>
</div>

具名插槽

我们可以给插槽定义名字,使其成为具名插槽。在单个插槽中,会将父组件中所有的卡片(假设都没有命名)按其在父组件中定义的顺序都接收过来;

  而具名插槽则是接收指定的卡片。这样,我们就可以在不同位置定义多个插槽,分别用来接收不同的卡片内容。也可以增加一个匿名插槽,用来接收父组件编译作用域中未被指定名称的卡片内容(剩余内容)。

在父组件中,通过使用v-slot:name或简写#name来给卡片内容命名,如下案例中,我们将内容分成了两个卡片,一个卡片名为header, 另一个为footer。需要注意的是,包含slot的标签元素也会被插入到卡槽中。如案例中的div标签

<div>
  <child-component>
    <template v-slot:header>   // 这里使用插槽语法全称方式
      <div>
        <h2>插槽标题</h2>
      </div>

    <div>没被命名的“剩余”内容一</div>

    <template #footer>  // 这里使用插槽语法简写方式
      <div #footer>
        <p>版权所有,翻版我也没办法</p>
      </div>
    </template>

    <div>没有被命名的“剩余”内容二</div>
  </child-component>
</div>

  强烈建议将“剩余”内容写在一起,并使用<template>包裹起来,规范的话再加入#default。卡片我们设定好了,接下来设定接收的插槽

// child-component 中的内容
<div>
  <slot name="header"></slot>

  <div>
    <p>这里是组件实现页面相似的功能模块的地方</p>
  </div>

  // 定义默认的卡槽用来存放“剩余”内容
  <slot></slot>

  <slot name="footer"></slot>
</div>
Last modification:April 14th, 2020 at 10:58 am
如果觉得我的文章对你有用,请随意赞赏