共计 4944 个字符,预计需要花费 13 分钟才能阅读完成。
大家好我是林三心,Vue 实现了一套内容散发的 API,将
<slot>
元素作为承载散发内容的进口,这是 Vue 文档上的阐明。具体来说,slot
就是能够让你在组件内增加内容的‘空间’,你真的晓得插槽 Slot 是怎么“插”的吗?我心愿你们能像我一样单纯,老老实实地看这篇文章。
Vue 插槽 slot 的根本应用
单个插槽 | 匿名插槽
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
</div>
</template>
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child>
林三心
</child>
</div>
</template>
咱们晓得,如果间接在父组件中的 <child></child> 中增加内容“林三心”,“林三心”文本是不会在页面上渲染的。那么咱们如何使增加的内容可能显示呢?在子组件内增加 slot 即可。
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot></slot>
</div>
</template>
编译作用域(父组件在子组件 <slot></slot>
处插入 data)
下面咱们理解了,slot 其实就是可能让咱们在父组件中增加内容到子组件的‘空间’。咱们能够增加父组件内任意的 data 值,比方这样:
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child> {{parent}}</child>
</div>
</template>
new Vue({
el:'.app',
data:{parent:'父组件'}
})
应用数据的语法齐全没有变,然而,咱们是否间接应用子组件内的数据呢?显然不行!!
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot></slot>
</div>
</template>
new Vue({
el:'child',
data:{child:'子组件'}
})
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child> {{child}}</child>
</div>
</template>
间接传入子组件内的数据是不能够的。因为:父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
后备内容 (子组件 <slot></slot>
设置默认值)
所谓的后背内容,其实就是 slot 的默认值,有时我没有在父组件内增加内容,那么 slot 就会显示默认值,如:
// 子组件:(假如名为:child)
<template>
<div class='child'>
<slot> 这就是默认值 </slot>
</div>
</template>
具名插槽(子组件多个 <slot></slot>
对应插入内容)
有时候,兴许子组件内的 slot 不止一个,那么咱们如何在父组件中,准确的在想要的地位,插入对应的内容呢?给插槽命一个名即可,即增加 name 属性。
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot name='one'> 这就是默认值 1 </slot>
<slot name='two'> 这就是默认值 2 </slot>
<slot name='three'> 这就是默认值 3 </slot>
</div>
</template>
父组件通过,或
slot="name"(旧语法)
,v-slot:name
或#name(新语法)
的形式增加内容:
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child>
<template v-slot:"one"> 这是插入到 one 插槽的内容 </template>
<template v-slot:"two"> 这是插入到 two 插槽的内容 </template>
<template v-slot:"three"> 这是插入到 three 插槽的内容 </template>
</child>
</div>
</template>
作用域插槽 (父组件在子组件 <slot></slot>
处应用子组件 data)
通过
slot
咱们能够在父组件为子组件增加内容,通过给slot
命名的形式,咱们能够增加不止一个地位的内容。然而咱们增加的数据都是父组件内的。下面咱们说过不能间接应用子组件内的数据,然而咱们是否有其余的办法,让咱们可能应用子组件的数据呢?其实咱们也能够应用slot-scope
的形式:
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot name= 'one' :value1='child1'> 这就是默认值 1 </slot> // 绑定 child1 的数据
<slot :value2='child2'> 这就是默认值 2 </slot> // 绑定 child2 的数据,这里我没有命名 slot
</div>
</template>
new Vue({
el:'child',
data:{
child1:'数据 1',
child2:'数据 2'
}
})
// 父组件:(援用子组件 child)<template>
<div class='app'>
<child>
<template v-slot:one='slotone'>
{{slotone.value1}} // 通过 v -slot 的语法 将子组件的 value1 值赋值给 slotone
</template>
<template v-slot:default='slotde'>
{{slotde.value2}} // 同上,因为子组件没有给 slot 命名,默认值就为 default
</template>
</child>
</div>
</template>
Slot 插槽是怎么“插”的(艰深版)
一般插槽
// 子组件:(假如名为:child)
<template>
<div class='child'>
我在子组件外面
<slot></slot>
<slot name="one"></slot>
</div>
</template>
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child>
这是插入到默认插槽的内容 {{parent}}
<template v-slot:"one"> 这是插入到 one 插槽的内容 {{parent}}</template>
</child>
</div>
</template>
new Vue({
el:'.app',
data:{parent:'父组件的值'}
})
-
父组件先解析,把
child
当做子元素解决,把 插槽当做child
的子元素解决,并且在父组件作用域内得出了 parent 变量的值,生成这样的节点:{ tag: "div", children: [{ tag: "child", children: ['这是插入到默认插槽的内容 父组件的值', '这是插入到 one 插槽的内容 父组件的值'] }] }
-
子组件解析,
slot
作为一个占位符,会被解析成一个函数,大略意思像 解析成上面{ tag: "div", children: [ '我在子组件外面', _t('default'), // 匿名插槽,默认名称为 default _t('one') // 具名插槽,名称为 one ] }
-
_t 函数须要传入插槽名称,默认是
default
,具名插槽则传入name
,这个函数的作用,是把第一步解析失去的插槽节点拿到,而后返回解析后的节点,那么子组件的节点就残缺了,插槽也胜利认了爹——div
标签{ tag: "div", children: ['我在子组件外面', '这是插入到默认插槽的内容 父组件的值', '这是插入到 one 插槽的内容 父组件的值'] }
作用域插槽
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot :value1='child1' :value2='child1'></slot>
<slot name='one' :value1='child2' :value2='child2'></slot>
</div>
</template>
new Vue({
el:'child',
data:{
child1: '子数据 1',
child2: '子数据 2'
}
})
// 父组件:(援用子组件 child)<template>
<div class='app'>
<child>
<template v-slot:default='slotde'>
插入默认 slot 中{{slotde.value1}}{{slotde.value2}}
</template>
<template v-slot:one='slotone'>
插入 one slot 中{{slotone.value1}}{{slotone.value2}}
</template>
</child>
</div>
</template>
-
过程很简单,这里就艰深点讲了,父组件先解析,遇到作用域插槽,会将此插槽封装成一个函数保留到子元素
child
下{ tag: "div", children: [{ tag: "child" scopeSlots:{default (data) { // 记住这个 data 参数 return ['插入 one slot 中插入默认 slot 中' + data.value1 + data.value2] }, one (data) { // 记住这个 data 参数 return ['插入 one slot 中' + data.value1 + data.value2] } } }] }
2. 轮到子组件解析了,这个时候_t 函数又退场了,并且子组件将对应的插槽数据包装成一个对象,传进_t 函数
{
tag: "div",
children: [
'我在子组件外面',
_t('default',{value1: '子数据 1', value2: '子数据 1'}),
_t('one',{value1: '子数据 2', value2: '子数据 2'})
]
}
接下来就是_t 外部执行,包装后的对象被当做 data 参数传入了 scopeSlots 中的对应的各个函数,解析成:
{
tag: "div",
children: [
'我在子组件外面',
'插入默认 slot 中 子数据 1 子数据 1',
'插入 one slot 中 子数据 2 子数据 2'
]
}
$slots
看到这,置信大家曾经分明了大略一个过程(尽管不是很具体),那么又有一个疑难了,这些解析后的
节点 VNode
对象,是存在哪儿呢?你总不能解析进去而后就扔了吧?必定得找个中央存起来而后进行实在 dom
的渲染,这个中央就是$slots
// 子组件:(假如名为:child)
<template>
<div class= 'child'>
<slot></slot>
<slot name='one'></slot>
<slot name='two'></slot>
<slot name='three'></slot>
</div>
</template>
new Vue({
el:'.child',
created () {console.log(this.$slots) // 看看外面有啥
}
})
// 父组件:(援用子组件 child)<template>
<div class= 'app'>
<child>
<template> 这是插入到默认插槽的内容 </template>
<template v-slot:"one"> 这是插入到 one 插槽的内容 </template>
<template v-slot:"two"> 这是插入到 two 插槽的内容 </template>
<template v-slot:"three"> 这是插入到 three 插槽的内容 </template>
</child>
</div>
</template>
console.log 的后果:
看到这里大家都懂了,
$slots
是一个Map
,key
是各个插槽的名称(匿名插槽的key
为default
),key 对应的 value 都是各个插槽上面的 VNode 节点,具体 VNode 对象里都是长什么样,大家能够本人输入看看,外面货色太多,我就不在这展现了。嘿嘿。
结语
我是林三心,一个热心的前端菜鸟程序员。如果你上进,喜爱前端,想学习前端,那咱们能够交朋友,一起摸鱼哈哈,摸鱼群,加我请备注【思否】