今天花几分钟给大家讲解一下"插槽"这个概念。目前前端主流的运行时框架里,插槽是绕不开的一个概念。究其原因是因为组件的渲染默认是结构式渲染。那啥又是结构式渲染?
上图就是一个很好的例子,渲染前是什么结构,渲染后就是什么结构。
那这个时候就会出现2类问题,如下:
- 性价比。
- 灵活度。
首先是性价比,有的时候,我们当前组件渲染在其他地方的性价比要比直接渲染在父节点里要高,比如Modal、Message这种全局提示类的组件。你说这种全局提示类的组件,能不能将dom放到父级节点里去实现?答案肯定是可以的,只不过这种做法会让你的Modal提示类组件在实现上受父级dom的限制,比如:
- 如果你的Modal是绝对定位做的,那么你就一定要考虑父级以上dom它们的定位了。因为我们知道绝对定位相对的是第一个有定位的父元素。
- 如果你的Modal是固定定位做的,那么父级dom隐藏的时候,你的子元素Modal组件是不是也没了呀。
其次我们再来说说灵活度的问题。有时候,我们想不到开发者具体想渲染什么元素,为了能够让开发者自己决定去渲染什么,我们需要这种机制,我们来提供多个渲染位置,用户想在什么位置渲染就在那个位置渲染。
所以插槽的概念出来了,它就是一种能够让用户在父节点外去渲染特定元素的一种机制
。
当前主流框架里,插槽是如何被使用的呢?
一、React
React.createPortal
是官方提供的插槽机制,个人感觉,比Vue里的slot要方便很多。用法如下:
javascript
React.createPortal(
要插入的元素或者组件,
要插入的位置
)
具体如何使用这个API去实现一个Modal提示类组件,更详细的请参考这篇文章。
二、Vue
Vue也是一个出色的框架,但是我认为心智负担比React要重。在Vue里,插槽的使用分为两点,分别是插槽的位置
、插槽能够提供的数据
。
2.1、插槽的位置
一个组件可以暴露出多个插槽,那么此时用户该如何去指定某个具体的渲染位置呢?在官方文档里这叫做具名插槽
。
还是以下图为例:
<Child1>、<Child2>组件都是<Parent>组件的插槽元素,如果想要指定插槽元素在父元素里的渲染位置,父元素应该给<slot>标签指定name属性,用于给渲染位置进行名字标记,如下:
javascript
// Parent组件如下:
<div class="parent">
<slot name="position1"></slot>
<slot name="position2"></slot>
</div>
同时子元素应该使用v-slot
来指定渲染位置(注意,v-slot指令只能跟template标签配套使用哦),如下:
javascript
<Parent>
<template v-slot:position2>
<Child1/>
</template>
<template v-slot:position1>
<Child2/>
</template>
</Parent>
这样,Child2组件的渲染位置就比Child1组件靠前。
2.2、插槽能够提供的数据
在官网里这叫插槽作用域
。a.vue文件的代码如下:
javascript
<Parent>
<template v-slot:position2>
<Child1/>
</template>
<template v-slot:position1>
<Child2/>
</template>
</Parent>
在a.vue单文件里,默认Child1、Child2组件能够绑定的属性都是a.vue文件里的data或者props。那如果我想绑定Parent组件里的属性呢?
这种情况也是很常见的,比如Table组件里的自定义列。你需要把当前行数据返回,这样用户才能自行决定如何渲染。
想要解决这个问题,操作如下:
1、在Parent组件里,给slot标签添加属性(动态或者静态的属性都可以,这两种属性的区别就是属性前面是否跟着v-bind指令)。
javascript
// Parent组件如下:
<div class="parent">
<slot :row1 = "data1" name="position1"></slot>
<slot :row2 = "data2" name="position2"></slot>
</div>
<script>
export default {
data(){
return {
data1: {},
data2: {}
}
}
}
</script>
2、在a.vue文件里,给v-slot指令绑定value。
javascript
<Parent>
<template v-slot:position2="slot1">
<Child1 :fatherData="slot1.data2"/>
</template>
<template v-slot:position1="slot2">
<Child2 :fatherData="slot2.data1"/>
</template>
</Parent>
这样,Child自组件就可以访问到父组件里的属性了。
三、最后
好啦,以上就是本篇文章的全部内容啦,如果你喜欢,欢迎3连支持;如果上述有表述不对的地方,欢迎指正,我们下期再见啦~~