Как проверить тип слота или vnode в функции рендеринга vue3?

У меня есть компонент 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>

Хорошо работать.

Как проверить тип слота или vnode в функции рендеринга vue3?

это код 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.

слоты консоли:

Как проверить тип слота или vnode в функции рендеринга vue3?

существует символ (комментарий).

Он не отображается как кроме. если я использую 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 в функции рендеринга vue3?

Я пытаюсь найти хороший способ проверить vnode или тип слота. Но хорошего не получил. Есть ли лучшая реализация в моем случае? Как это исправить?

Можете уточнить, в чем проблема? Что не так с комментарием? Если вы ожидаете, что v-for будет использоваться, дополнительно обработайте типы фрагментов.

Estus Flask 11.11.2022 18:24

Проблема в том, что случай комментария и фрагмента vnode не отображается нормально, я знаю, что нужно обрабатывать комментарий и фрагмент. но я не знаю, как лучше.

JackChouMine 11.11.2022 18:29

Для фрагмента разверните детей. Непонятно, в чем проблема с комментарием. Это просто игнорируется, не так ли? "return h('div', message)" - это не общепринято.

Estus Flask 11.11.2022 18:43

Как и в случае с тегом таблицы, мы можем использовать только некоторые теги в таблице, такие как thead tbody и tr td. Поэтому я хочу, чтобы между компонентами vue была такая функция. поэтому мне нужно проверить тип подкомпонента.

JackChouMine 13.11.2022 09:36

Как и в случае с тегом таблицы, мы можем использовать только некоторые теги в таблице, такие как thead tbody и tr td. Поэтому я хочу, чтобы между компонентами vue была такая функция. поэтому мне нужно проверить тип подкомпонента.

JackChouMine 13.11.2022 09:36

Это распространенный случай. Просто отфильтруйте все, что вам нужно, и пропустите остальное, например, комментарии. Вам нужно сгладить фрагмент children в массиве, если вы планируете использовать v-for. Используйте slot.type === Fragment проверку

Estus Flask 13.11.2022 09:46
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
6
167
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

проверьте тип с этим кодом.

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)

Другие вопросы по теме