Vue 100问(27-29)说一下你对 vue 插槽的理解

753 阅读2分钟

「这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战」。


插槽,初学者的噩梦,也是我曾经的噩梦,但业务开发中写多了,回过头总结的时候,发现也不过如此。

问题

27.说一下你对 vue 插槽的理解

一个再复杂的 Vue 组件,都是由三部分组成的:prop、event、slot。

插槽(slot)就是构成 Vue 组件的一部分而已。

插槽通俗的理解就是“占坑”,在组件模板中占好了位置,当使用该组件标签时候,组件标签里面的内容就会自动填坑(替换组件模板中 slot 位置)。

当初还看到过一种理解,让我豁然开朗,把 slot 和 prop 类比:

js -> prop

html -> slot

prop 和 slot 都可以理解成外部传入参数,prop 传的是 js 代码, slot 传的是 html 代码,最终的目的都是父组件去控制子组件做一些事情,只不过 prop 控制的是 js 逻辑, slot 控制的是 html 结构和样式。

插槽基本使用

<base-content> qwer </base-content>

如果直接在一个自定义组件内部写 html,将不会生效。

这时就需要使用插槽,才能把 html 插入到组件中的 slot 标签中。

子组件内:

<div>
  <slot></slot>
</div>

具名插槽

一个组件可以有多个插槽,通过 slot 标签的 name 属性来区分。

父组件通过,slot="name"(旧语法)v-slot:name#name(新语法) 的方式添加内容:

子组件内:
<div class="base-content">
  <slot name="header"></slot>
  <slot name="main"></slot>
  <slot name="footer"></slot>
</div>
父组件内:
<base-content>
  <div slot="header">我是header</div>
  <template #main>我是main</template>
  <template v-slot:footer>我是footer</template>
</base-content>

28.父组件能否通过插槽的形式使用子组件的数据?

直接使用不能,使用作用域插槽能 直接使用

子组件内:

<div class="base-content">
  <slot></slot>
</div>

data() {
  return {
    innerContent: 'qwer'
  }
}
父组件:
<base-content> {{ innerContent }} </base-content>

就报错了:

image.png

原因是:

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。 -- vue 文档

作用域插槽

子组件内:
<div class="base-content">
  <slot name="header" :innerContent="innerContent"></slot>
</div>

data() {
  return {
    innerContent: '我是innerContent'
  }
}
父组件内:
<base-content>
  <template v-slot:header="headerData">{{ headerData.innerContent }}</template>
</base-content>

这样的写法就和使用 props 传参非常像了,不过是从子组件的 slot 标签上向父组件传递,在父组件内通过 v-slot 接收。

注意,作用域插槽以前的写法是 slot-scope,已经在 2.6.0 版本被废弃了,写插槽最好都用 v-slot。

29. $slots$scopedSlots 是干嘛用的?

它们都是 vue 实例上的属性:

image.png

$slots用来访问被 插槽分发 的内容。

$scopedSlots用来访问作用域插槽

在子组件内部判断父组件插槽使用情况的时候,这两个属性很有用,

比如下面这两段代码,取自于 element-ui 的 alert 组件和 tree 组件。

image.png

image.png