vue如何便捷的判断vnode的类型?
我有一个组件,使用方式如下:
<TabContainer v-model="activeTab"> <TabHeader tab-id="1"> tab1 </TabHeader>
<TabHeader tab-id="2"> tab2 </TabHeader>
<TabHeader tab-id="3"> tab3 </TabHeader>
<TabContent tab-id="1"> content 1 </TabContent>
<TabContent tab-id="2"> content 2 </TabContent>
<TabContent tab-id="3"> content 3 </TabContent>
</TabContainer>
按照预期工作。
实现如下:
import { h } from 'vue'import './TabContainer.scss'
const TabContainer = {
name: 'TabContainer',
props: {
modelValue: {
type: String,
required: true,
},
},
render() {
const slots = this.$slots.default()
console.log(slots)
// 检查子组件类型
const existInValidSubCom = slots.some(slot => ![TabHeader, TabContent].includes(slot.type))
if (existInValidSubCom) {
const message = 'TabContainer的子组件必须是 TabHeader 和 TabContent'
// throw new Error(message)
return h('div', message)
}
const Tabs = slots
.filter(item => item.type === TabHeader)
.map(Tab =>
h(Tab, {
class: {
tab: true,
active: Tab.props['tab-id'] === this.modelValue,
},
onClick: () => {
this.$emit('update:modelValue', Tab.props['tab-id'])
},
}),
)
const content = slots.find(
slot => slot.type === TabContent && slot.props['tab-id'] === this.modelValue,
)
return [h('div', { class: 'tab-container' }, Tabs), h('div', content)]
},
}
export default TabContainer
export const TabHeader = TabItem({ name: 'TabHeader' })
export const TabContent = TabItem({ name: 'TabContent' })
function TabItem(options) {
return {
...options,
props: {
tabId: {
type: String,
required: true,
},
},
render() {
return h('div', null, this.$slots.default())
},
}
}
当插槽里有注释时:
<TabContainer v-model="activeTab"> <TabHeader tab-id="1"> tab1 </TabHeader>
<TabHeader tab-id="2"> tab2 </TabHeader>
<TabHeader tab-id="3"> tab3 </TabHeader>
<!-- 注释 -->
<TabContent tab-id="1"> content 1 </TabContent>
<TabContent tab-id="2"> content 2 </TabContent>
<TabContent tab-id="3"> content 3 </TabContent>
</TabContainer>
slots 多了一个注释的 vnode:
下面的判断条件结果为 true,组件不能按照预期工作:
// 检查子组件类型const existInValidSubCom = slots.some(slot => ![TabHeader, TabContent].includes(slot.type))
当有很多TabHeader和 TabContent 时,希望使用v-for
:
<TabContainer v-model="activeTab"> <TabHeader :tab-id="item" v-for="(item, index) in ['1', '2', '3']" :key="index">
tab{{ item }}
</TabHeader>
<TabContent tab-id="1"> content 1 </TabContent>
<TabContent tab-id="2"> content 2 </TabContent>
<TabContent tab-id="3"> content 3 </TabContent>
</TabContainer>
slots 里多了一个 Symbol(Fragement)
也导致刚才的判断结果为 true。
为何需要限制子组件的类型?table 内只能使用 thead、tbody、tr、td等有限的标签,希望组件之间也有这样的特性。
vue 版本:^3.2.41
。
这种情况该如何处理比较好?或者说,有什么快捷的函数可判断一个vnode的类型呢?
回答:
没有简便的办法可检查类型,只能这样检查了。
const vnodeList = this.$slots.default()const childList = []
let existNonValidSubCom = false
let i = 0
do {
const vnode = vnodeList[i]
// html tag
if (typeof vnode.type === 'string') {
existNonValidSubCom = true
break
} else if ([TabHeader, TabContent].includes(vnode.type)) {
childList.push(vnode)
}
// Symbol(Fragment)
else if (typeof vnode.type === 'symbol' && Array.isArray(vnode.children)) {
// childList.push(h(vnode.type, null, vnode.children))
vnode.children.forEach(child => {
if ([TabHeader, TabContent].includes(child.type)) {
childList.push(child)
}
})
}
// Symbol(Comment)
else if (typeof vnode.type === 'symbol' && typeof vnode.children === 'string') {
// 跳过
} else {
existNonValidSubCom = true
break
}
} while (++i < vnodeList.length && !existNonValidSubCom)
回答:
这种在生产环境判断的方法有点浪费资源了。可以换个思路,从vue的config入手,去掉所有的注释 看看会不会产生好的效果。
module.exports = { chainWebpack: config => {
config.optimization.minimizer('terser').tap((args) => {
args[0].terserOptions.output = {
...args[0].terserOptions.output,
comments: false // 跳过所有的注释
}
return args
})
}
}
回答:
不是很理解为什么要去判断 slot
的 VNode
类型。直接使用 具名插槽
不就好了???
回答:
有点搞不懂你的做法。
- 你的每个组件都是手写的
- 然后你手动插入一个注释
- 然后你说你检查组件会出错
??
换个逻辑,如果你这里不手写,那判断传入的数据就行了,也不需要管注释。
以上是 vue如何便捷的判断vnode的类型? 的全部内容, 来源链接: utcz.com/p/933390.html