初学vue时,学习过vue的插槽,但是那时对插槽也只是一个很浅的认识,只是知道插槽是往组件里面添加放置代码片段的,并且学习的版本也比较老旧。且对于为什么会用插槽?什么情况下使用插槽?插槽具体怎么实现?都是一知半解的。
这几天在网上搜集了一些插槽的相关资料,官网的资料比较全,但是都是很短的代码片段,再加上文字描述也很少,因此很难让人理解。网上相关插槽的知识点也比较老旧,都是2.6.0之前的版本,基本上都是被废弃过的slot
。因此闲暇之余,通过大量地查找和参考相关资料,总结出以下最新版的slot知识点:
在 2.6.0 中,具名插槽和作用域插槽引入了一个新的统一的语法 (即 v-slot
指令)。它取代了 slot
和 slot-scope
,这两个目前已被废弃但未被移除且仍在文档。
目录
概念
什么是插槽?
在自定义的组件中的留一个或多个的插槽位置,以便根据父组件的需求可以向子组件对应的槽中插入对应的代码片段。
为什么用插槽?
组件的最大特性就是复用性,而用好插槽能大大提高组件的可复用能力。
组件的复用性常见情形如在有相似功能的模块中,他们具有类似的UI界面,通过组件之间的通信机制,达到了使用一套代码渲染不同的数据的效果。
然而这种利用组件之间的通信机制,只能满足结构上相同,渲染数据不同的条件。但如果他们页面及其相似,只有其中某一块有不同的UI效果,以上办法就不能实现了。但这时我们一般的想法是,使用 v-if
和 v-else
来特殊处理这些特殊的功能模块,是的,这样可以解决,但是如果有一百个这种页面呢?显然v-if
和 v-else
这种方法处理起来就显得比较笨拙了,维护起来也不容易。
而插槽slot
就可以很完美解决这个问题
什么情况下使用插槽?
还是举刚才的例子。如果有一百个基本相似,只有一个模 块功能不同的页面,而我们只想写一个组件。这时我们可以给子组件留一个卡槽,在父组件中将不同的那个模块单独处理成一个卡片,在父组件需要使用的时候,将卡片插入对应子组件的卡槽中即可实现对应的完整的功能页。而不是在组件中把所有的情形用if-else
罗列出来。
可能你会想,那我把一个组件分割成一片片的插槽,需要什么拼接什么,岂不是只要一个组件就能完成所有的功能?思路上没错,但是需要明白的是,卡片是在父组件上代替子组件实现的功能,使用插槽无疑是在给父组件页面增加规模,如果全都使用拼装的方式,和不用组件又有什么区别。因此,插槽并不是用的越多越好。
插槽是组件最大化利用的一种手段,而不是替代组件的策略,当然也不能替代组件。如果能在组件中实现的模块,或者只需要使用一次v-else
, 或一次v-else-if
,v-else
就能解决的问题,都建议直接在组件中实现。
如何控制插槽
由于插槽是一块模板,所以,对于任何一个组件,从模板种类的角度来分,其实都可以分为非插槽模板和插槽模板两大类。
非插槽模板指的是html模板,比如‘div、span、ul、table’这些,非插槽模板的显示与隐藏以及怎样显示由组件自身控制;
插槽模板是slot,它是一个空壳子,因为它的显示与隐藏以及最后用什么样的html模板显示由父组件控制。
但是插槽显示的位置却由子组件自身决定,slot写在组件template的什么位置,父组件传过来的模板将来就显示在什么位置。
1.编译作用域
使用插槽前,需要先了解什么是编译作用域
作为一条规则,请记住:
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
案例如下:
//父组件
<template>
<div>
{
{
color}}
<child1 :myData="num">
{
{
msg}}
</child1>
</div>
</template>
<script>
import child1 from "./component/child1";
export default{
data(){
return {
color:'red',
num:12,
msg:'父组件'
}
},
components:{
child1
}
}
</script>
//子组件child1
<template>
<div>
<h1>{
{
msg}}</h1>
{
{
txt}}
<slot></slot>
</div>
</template>
<script>
export default{
data(){
return {
msg:'子组件',
txt:'你好'
}
},
}
</script>
运行结果:
从运行结果中我们可以看到:
父组件作用域参与编译的内容有:(1) 父组件变量中的color:'red'
;(2)父组件传递给子组件的数据myData
; (3) 父组件变量msg:'父组件'
;
子组件作用域参与编译的内容有:(1) 子组件h1标签中的变量msg:'子组件'
; (2) 子组件变量txt:'你好'
;
需要强调的是,父组件编译作用域上的msg部分也就是插槽的后备内容,是存在于父组件作用域内,该部分是不能访问存在于子组件作用域中的data特性的,如果需要访问这部分内容,需要使用到作用域插槽功能
上面提到过一个观点:卡片是在父组件上代替子组件实现的功能,使用插槽无疑是在给父组件页面增加规模。从上面案例中也可以看出,子组件只提供了插槽<slot>
,而具体什么内容它并不管,都交给了父组件作用于中存在于<child1>
包含的那部分内容去分发。这部分内容,就是我们所说的卡片。
2.插槽内容
通俗来讲,slot作用就是替换自定义标签中的内容,官方称(your profile),slot插槽内可以包含任何模板代码,包括文字:
//父组件
<template>
<div>
<child1>
哈哈哈哈
</child1>
</div>
</template>
//子组件child1
<template>
<div>
<slot></slot>
</div>
</template>
当组件渲染的时候,<slot></slot>
将会被替换为“哈哈哈哈”。
插槽内可以包含任何模板代码,包括 HTML:
//父组件
<template>
<div>
<child1>
哈哈哈哈
<h1>你好</h1>
</child1>
</div>
</template>
当组件渲染的时候,<slot></slot>
将会被替换为“哈哈哈哈”和<h1>
标签里的你好。
甚至其它的组件:
//父组件
<template>
<div>
<child1>
哈哈哈哈
<child2></child2>
</child1>
</div>
</template>
当组件渲染的时候,<slot></slot>
将会被替换为“哈哈哈哈”和<child2>
组件。
3.后备内容
slot后备内容:有时为一个插槽设置具体的后备 (也就是默认的) 内容是很有用的,它只会在没有提供内容的时候被渲染
//父组件
<template>
<div class="me">
<h1>这是父组件</h1>
<child1><