当前位置:   article > 正文

Vue插槽——理解v-slot指令以及其为何要废弃具名插槽和作用域插槽_element template v-slot

element template v-slot


前言

Vue在2.6.0中,更新添加了一个新的指令v-slot,用于取代原先的slot与slot-scope属性的功能。

	注意:此处的slot为属性,不是HTML标签那个<slot></slot>
  • 1


一、Vue的插槽

Vue中的插槽很好用也很实用,在实际开发项目时或多或少几乎都会遇到,很多第三方引入的组件提供的修改内容的方法,也是通过插槽。

但网上关于插槽的教程与介绍都还是 “插槽种类分为三种:单个插槽/具名插槽/作用域插槽” 等等,也包括很多第三方组件仍然使用着slotslot-scope属性。

(例如下图便是element-ui关于el-tree组件的文档中介绍如何去自定义节点内容)element-ui el-tree的文档
如果你对slot以及slot-scope属性还不理解,对插槽还不是很熟悉,推荐看一下这篇博文,博主对于vue中的插槽写的非常详尽易懂

深入理解vue中的slot与slot-scope–云荒杯倾

虽然slot以及slot-scope属性已经被废弃,但在vue 2.x版本中未被移除,依然可以使用,特别是在很多基于Vue的框架中被大量使用,所以学习还是很有必要的!

二、为何引入v-slot

1.作用域插槽的局限和缺点


如果你理解了slot以及slot-scope属性,就会明白slot-scope的用法是写在slot所在组件下\标签中,例:
<!--版本一:-->
<class> 
	<template slot-scope="name"> 
		<div> 
			{{ name }} 
		</div> 
	</template> 
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结果有人提出这个\是否真的有必要,直接将slot-scope写在组件下的元素上不就可以简洁一点。 于是Vue在2.5版本中更新了该功能:
<!--版本二:-->
<class>
	<div slot-scope="name">
		{{ name }}
	</div> 
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

嗯,确实简洁了不少,那能用于HTML标签,自然也应该可以用于组件上,于是:
<!--版本三:-->
<class>
	<people slot-scope="name">
		{{ name }}
	</people>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个用法很常用,几乎现在的插件都是这么写的,然而这样使用,有个大问题:

无法直观表示该slot-scope用于哪个组件的插槽,明明是写在<people>标签上,然而跟people组件没有关系,这个name竟然是class组件中的数据。

如果再套娃几层:

<class>
	<people slot-scope="grade">
		<book slot-scope="number">
			<div slot-scope="name">
				{{ grade }} {{ number }} {{ name }}
			</div>
		</book>
	</people>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

太模糊了,连官方自己都承认:

It’s not immediately clear which component is providing which variable in this template.

有人又提议,那既然这样有问题,那我们回到Vue 2.5之前,强制slot-scope使用在标签下不就行了:

加功能容易,改功能难,删功能更难!

毕竟那么多人已经用上这个语法了

2.应运而生的v-slot

当时学习插槽时,就被各种“单个插槽”、“具名插槽”、“作用域插槽”什么的弄得云里雾里,明明在子组件里都是<slot>框住的部分,功能都是提供给父组件一块可在父组件中定义的HTML块,它可以带子组件的数据也可以不带,可以带名字也可以不带名字使用默认的插槽,没必要特意去分成三种。

不过也是因为各种插槽一开始用法上区别还是蛮大的,最后因为不断更新成现在这种用法类似的样子

既然如此官方自然会希望统一插槽类型,不管他是不是作用域插槽和非作用域插槽,他们全都是插槽就行了。那无论是slot-scope甚至是slot这两个属性,都没有必要了。

v-slot

在子组件中依然是使用<slot></slot>去设定你要在父组件中替换的位置,而在父组件中用v-slot写在对应子组件下标签上,使得标签下的内容插入插槽中。

设定每一个插槽都是作用域插槽,只要为v-slot设定属性值来声明接收到的数据。设定使用伪指令参数来设定插槽名称。

下面举个例子:

<class>
	<template v-slot:slotName="grade">
		<div>
			{{ grade }}
		</div>
	</template
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其中,:slotName表示使用名称为‘slotName’的插槽(即之前slot属性的作用),=“grade”声明接受到的子组件的数据(即之前slot-scope属性的作用)

若对于只有单个默认插槽的组件来说,父组件使用其插槽时可以简洁使用,例:

<foo v-slot="data">
	{{ data }}
</foo>
  • 1
  • 2
  • 3

可以看到相比之前slot-scope的简洁用法,v-slot这个用法使作用域与提供它的组件之间的联系更加清晰,v-slot在什么组件上就是指明什么组件的作用域。

让我们回头看我们的套娃例子使用v-slot有什么变化:

<class v-slot="grade">
	<people v-slot="number">
		<book v-slot="name">
			<div>
				{{ grade }} {{ number }} {{ name }}
			</div>
		</book>
	</people>
</class>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

现在就很清晰了,grade就是class组件的grade,number就是people组件的number,name就是book组件的name。

	注意:只有单个默认插槽的组件可以使用这样的简洁语法
  • 1

更多例子

这里贴几个官方的新旧对比例子,方便大家理解:

1)默认插槽(填充文字)

<!-- 旧 -->
<foo>
  <template slot-scope="{ msg }">
    {{ msg }}
  </template>
</foo>

<!-- 新 -->
<foo v-slot="{ msg }">
  {{ msg }}
</foo>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2)默认插槽(填充元素)

<!-- 旧 -->
<foo>
  <div slot-scope="{ msg }">
    {{ msg }}
  </div>
</foo>

<!-- 新 -->
<foo v-slot="{ msg }">
  <div>
    {{ msg }}
  </div>
</foo>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3)嵌套的默认插槽

<!-- 旧 -->
<foo>
  <bar slot-scope="foo">
    <baz slot-scope="bar">
      <template slot-scope="baz">
        {{ foo }} {{ bar }} {{ baz }}
      </template>
    </baz>
  </bar>
</foo>

<!-- 新 -->
<foo v-slot="foo">
  <bar v-slot="bar">
    <baz v-slot="baz">
      {{ foo }} {{ bar }} {{ baz }}
    </baz>
  </bar>
</foo>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

4)具名插槽

<!-- 旧 -->
<foo>
  <template slot="one" slot-scope="{ msg }">
    text slot: {{ msg }}
  </template>

  <div slot="two" slot-scope="{ msg }">
    element slot: {{ msg }}
  </div>
</foo>

<!-- 新 -->
<foo>
  <template v-slot:one="{ msg }">
    text slot: {{ msg }}
  </template>

  <template v-slot:two="{ msg }">
    <div>
      element slot: {{ msg }}
    </div>
  </template>
</foo>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

5)混合使用

<!-- 旧 -->
<foo>
  <bar slot="one" slot-scope="one">
    <div slot-scope="bar">
      {{ one }} {{ bar }}
    </div>
  </bar>

  <bar slot="two" slot-scope="two">
    <div slot-scope="bar">
      {{ two }} {{ bar }}
    </div>
  </bar>
</foo>

<!-- 新 -->
<foo>
  <template v-slot:one="one">
    <bar v-slot="bar">
      <div>{{ one }} {{ bar }}</div>
    </bar>
  </template>

  <template v-slot:two="two">
    <bar v-slot="bar">
      <div>{{ two }} {{ bar }}</div>
    </bar>
  </template>
</foo>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

总结

如果你使用的是Vue 2.x的版本,那么你仍然可以继续使用slot属性定义具名插槽,使用slot-scope属性定义作用域插槽,也可以使用新的v-slot(2.6版本之后)

然而如果你使用Vue 3.x的版本,那么你只能使用v-slot指令

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/259271
推荐阅读