检查子组件的类型

在一些场景下,需要对组件嵌套组合使用,比如TabsTab的组合。此时会牵涉出一些问题,Tabs组件不应该无条件接受外部传入内容进行渲染,应该判断内部组件的类型以符合所需。

获取slots的方式

setup函数

<script lang="ts">
import { defineComponent } from 'vue';
import Tab from './Tab.vue';

export default defineComponent({
  setup(props, context) {
    const { slots } = context;

    if (slots.default?.()) {
      slots.default().forEach((item, index) => {
        if (item.type !== Tab) {
          throw Error(`[Crystal error]: The element ${index} type is not Tab`)
        }
      })
    } else {
      throw Error("[Crystal error]: Tabs missing content")
    }
  }
})
</script>

默认导出的普通对象中的组合式API setupopen in new window并没有参数类型提示,想要对传递给 setup() 的参数进行类型推断,则必须使用defineComponent,使用普通的export default {}的方式将无法正确得类型判断,ts将会给出警告。

<script setup>

<!-- Tabs.vue -->
<script setup lang="ts">
import { useSlots } from 'vue';
import Tab from './Tab.vue';

const slots = useSlots();

if (slots.default?.()) {
  slots.default().forEach((slot, index) => {
    // 判断是否是 Tab 
    if (slot.type !== Tab) {
      // 使用 console.error 或 throw Error
      throw Error(`[Crystal error]: The element ${index} type is not Tab`)
    }
  })
} else {
  throw Error("[Crystal error]: Tabs missing content")
}
</script>










 








slots.default?.()使用的是可选链操作符open in new window,判断是否传入了内容。

由于useSlots返回值的类型可能包含undefined,又可能因为没有给组件传入内容,因此slots本就不含有default方法,直接使用slots.default()会报错。这样的情况下我们需要对slotsdefault做判断来避免运行时错误和ts的警告。

if(slots && slots.default) {
  // ... 使用 slots.default()
}

// 使用可选链操作符简化写法
if (slots.default?.()) {}

如何判断类型

Tabs传入的每个节点都将会成为default函数返回值(数组)的一部分,数组的每一项都有一个type属性,标记着这个节点的类型。它的值是个对象,如果是自定义组件,那么导入时的对象,就是这个type的内容,因此完全可以用来进行===相等判断!

参考资料:组合式APIopen in new windowdefineComponentopen in new windowuseSlotsopen in new window插槽open in new window可选链操作符open in new window

最近更新:
Contributors: untilthecore