Vue在渲染函数createELement和JSX中使用插槽slot
Vue对于插槽有两个专门的API`vm.$slots`和`vm.$scopedSlots`,分别是普通插槽和作用域插槽,使用JSX语法或渲染函数的时候,定义插槽将使用上述两个API。普通插槽和作用域插槽在定义上相差不大,但是在使用方法上略微有点区别。普通插槽,插槽内容以`children子节点`形式,然后在数据对象中指定插槽名
Vue对于插槽有两个专门的APIvm.$slots
和vm.$scopedSlots
,分别是普通插槽和作用域插槽,使用JSX语法或渲染函数的时候,定义插槽将使用上述两个API。
渲染函数createElement
普通插槽和作用域插槽在定义上相差不大,但是在使用方法上略微有点区别,详见渲染函数>数据对象
普通插槽,插槽内容以children子节点
形式,然后在数据对象中指定插槽名
// 定义带插槽的组件,`$slots.default`为匿名插槽,其余的则是具名插槽,匿名插槽的插槽名可以省略
const MySlot = {
render (h) {
return h('div', [
h('header', [this.$slots.header]),
h('main', [this.$slots.header]),
h('footer', [this.$slots.footer])
])
}
}
// 在`children子节点`中指定插槽名以使用具名插槽,未指定插槽名的则放入匿名插槽中
export default {
components: { MySlot },
render (h) {
return h('MySlot', [
h('template', { slot: 'header' }, 'hello world'),
'children node',
h('div', { slot: 'footer' }, 'this is footer')
])
}
}
作用域插槽,与普通插槽不同,作用域插槽的内容直接放入渲染函数的数据对象中的
// 定义作用域插槽
const MySlot = {
data () {
return { user: 'John', content: 'vue', copytight: 'CopyRight' }
},
render (h) {
return h('div', [
h('header', [this.$scopedSlots.header({ user: this.user })]),
h('main', [this.$scopedSlots.default({ content: this.content })]),
h('footer', [this.$scopedSlots.footer({ copytight: this.copytight })])
])
}
}
// 要使用作用域插槽的数据内容,则插槽必须在组件的数据对象`scopedSlots`中使用,如`header`所示
// 作用域插槽也可以当作普通插槽使用,如`default`和`footer`
export default {
components: { MySlot },
render (h) {
return h('MySlot', {
scopedSlots: {
header: props => `hello, ${props.user}`
}
}, [
'children node',
h('div', { slot: 'footer' }, 'this is footer')
])
}
}
关于静态插槽和作用域插槽:
你可以通过
this.$slots
访问静态插槽的内容,每个插槽都是一个 VNode 数组
也可以通过this.$scopedSlots
访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数
this.$slots
返回的是数组,this.$scopedSlots
返回的是函数,这里踩一个坑,使用 this.$scopedSlots
定义的插槽如果未被使用则会报错
例如删除或注释掉具名插槽footer内容后,控制台报错
[Vue warn]: Error in render: "TypeError: this.$scopedSlots.footer is not a function"
如何避免这个问题暂时没有找到解决方案,研究还不够深入
2021年1月25日补充:
使用
this.$scopedSlots
定义的插槽如果未被使用则会报错
原因: 以footer插槽为例,其实不用想的太复杂,作用域插槽this.$scopedSlots.footer()
就是一个函数,MySlot
组件使用了这个函数,但是父组件却没有传入此函数的定义,所以MySlot
再调用这个函数的时候发生报错。
解决办法: 在MySlot
调用this.$scopedSlots.footer()
前进行一次判断此函数是否存在即可。
JSX语法
JSX是createElement
的语法糖,在用法上没有什么区别,对照着上面的内容稍微改一改就好了
静态插槽
const MySlot = {
render (h) {
return (
<div>
<header>{this.$slots.header}</header>
<main>{this.$slots.default}</main>
<footer>{this.$slots.footer}</footer>
</div>
)
}
}
export default {
render (h) {
return (
<MySlot>
<template slot='header'>hello world</template>
children node
<div slot='footer'>this is footer</div>
</MySlot>
)
}
}
作用域插槽
const MySlot = {
data () {
return { user: 'John', content: 'vue', copytight: 'CopyRight' }
},
render (h) {
return (
<div>
<header>{this.$scopedSlots.header({ user: this.user })}</header>
<main>{this.$scopedSlots.default({ content: this.content })}</main>
<footer>{this.$scopedSlots.footer({ copytight: this.copytight })}</footer>
</div>
)
}
}
export default {
render (h) {
return (
<MySlot
scopedSlots={{
header: props => `hello, ${props.user}`
}}
>
children node
<div slot='footer'>this is footer</div>
</MySlot>
)
}
}
更多推荐
所有评论(0)