У меня есть компонент vue TabContiainer, чтобы использовать его таким образом:
<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>
Хорошо работать.

это код TabContainer:
import { h } from 'vue'
// import './TabContainer.scss' //ignore css
const TabContainer = {
name: 'TabContainer',
props: {
modelValue: {
type: String,
required: true,
},
},
render() {
const slots = this.$slots.default()
console.info(slots)
// check slot type
const existInValidSubCom = slots.some(slot => ![TabHeader, TabContent].includes(slot.type))
if (existInValidSubCom) {
const message = "TabContainer's sub commpont muse be TabHeader and 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>
<!-- some comment -->
<TabContent tab-id = "1"> content 1 </TabContent>
<TabContent tab-id = "2"> content 2 </TabContent>
<TabContent tab-id = "3"> content 3 </TabContent>
</TabContainer>
Некоторые комментарии приводят к тому, что следующий код становится верным в TabContainer
// check slot type
const existInValidSubCom = slots.some(slot => ![TabHeader, TabContent].includes(slot.type))
if (existInValidSubCom) {
const message = "TabContainer's sub commpont muse be TabHeader and TabContent"
// throw new Error(message)
return h('div', message)
}
Зачем мне нужно проверять тип подкомпонента? Как и тег таблицы, в таблице разрешено использовать ограниченный тег, только тег ad tbody tr td. Я надеюсь, что есть такое ограничение или аналогичная функция между компонентом vue.
слоты консоли:

существует символ (комментарий).
Он не отображается как кроме. если я использую 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>
слоты имеют символ (фрагмент) vnode.

Я пытаюсь найти хороший способ проверить vnode или тип слота. Но хорошего не получил. Есть ли лучшая реализация в моем случае? Как это исправить?
Проблема в том, что случай комментария и фрагмента vnode не отображается нормально, я знаю, что нужно обрабатывать комментарий и фрагмент. но я не знаю, как лучше.
Для фрагмента разверните детей. Непонятно, в чем проблема с комментарием. Это просто игнорируется, не так ли? "return h('div', message)" - это не общепринято.
Как и в случае с тегом таблицы, мы можем использовать только некоторые теги в таблице, такие как thead tbody и tr td. Поэтому я хочу, чтобы между компонентами vue была такая функция. поэтому мне нужно проверить тип подкомпонента.
Как и в случае с тегом таблицы, мы можем использовать только некоторые теги в таблице, такие как thead tbody и tr td. Поэтому я хочу, чтобы между компонентами vue была такая функция. поэтому мне нужно проверить тип подкомпонента.
Это распространенный случай. Просто отфильтруйте все, что вам нужно, и пропустите остальное, например, комментарии. Вам нужно сгладить фрагмент children в массиве, если вы планируете использовать v-for. Используйте slot.type === Fragment проверку



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


проверьте тип с этим кодом.
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)
}
else if (typeof vnode.type === 'symbol' && Array.isArray(vnode.children)) {
// Symbol(Fragment)
// childList.push(h(vnode.type, null, vnode.children))
vnode.children.forEach(child => {
if ([TabHeader, TabContent].includes(child.type)) {
childList.push(child)
}
})
}
else if (typeof vnode.type === 'symbol' && typeof vnode.children === 'string') {
// Symbol(Comment) skip
} else {
existNonValidSubCom = true
break
}
} while (++i < vnodeList.length && !existNonValidSubCom)
Можете уточнить, в чем проблема? Что не так с комментарием? Если вы ожидаете, что v-for будет использоваться, дополнительно обработайте типы фрагментов.