Skip to content

在 Composable 中返回 Vue 组件的几种方式

方式 1: 返回组件定义

typescript
import { h, ref, defineComponent, type Component } from "vue";
import type { Viewer } from "cesium";
import MeasureDistanceTool from "@/components/CesiumView/MeasureDistanceTool.vue";

export function useMeasureDistance(viewer: Viewer) {
  const isActive = ref(false);
  const distance = ref(0);

  // 使用 defineComponent 创建响应式包装组件(最可靠的方式)
  // 这样当 ref 变化时,组件会自动重新渲染,保持响应式
  const MeasureDistanceComponent: Component = defineComponent({
    setup() {
      return () =>
        h(MeasureDistanceTool, {
          isActive: isActive, // 传递 ref 对象,Vue 会自动解包为 isActive.value

          // Vue 3 中,v-model
          "onUpdate:isActive": (value: boolean) => {
            isActive.value = value;
          },

          // 如果需要传递其他事件处理函数
          // onStart: startMeasure,
          // onStop: stopMeasure,
        });
    },
  });

  function startMeasure() {
    isActive.value = true;
  }

  function stopMeasure() {
    isActive.value = false;
  }

  return {
    MeasureDistanceComponent, // 返回已绑定 props 的组件,使用时无需再传 props
    startMeasure,
    stopMeasure,
  };
}

方式 2: 动态导入组件(按需加载)

typescript
export function useMeasureDistance() {
  const state = reactive({
    isActive: false,
  });

  // 动态导入组件(懒加载)
  const MeasureDistanceComponent: Component = () => {
    return import("@/components/measure/MeasureDistanceTool.vue").then(
      (module) => module.default
    );
  };

  return {
    state,
    MeasureDistanceComponent,
  };
}

方式 3: 返回渲染函数(使用 h 函数)

typescript
import { h, reactive } from "vue";

export function useMeasureDistance() {
  const state = reactive({
    distance: 0,
  });

  // 返回渲染函数
  const MeasureDistanceRender = () => {
    return h("div", { class: "measure-tool" }, [
      h("p", `距离: ${state.distance}m`),
      h("button", { onClick: () => (state.distance = 0) }, "重置"),
    ]);
  };

  return {
    state,
    MeasureDistanceRender,
  };
}
vue
<template>
  <component :is="MeasureDistanceRender" />
</template>

方式 4: 返回组件引用(适用于需要传递 props 的情况)

typescript
import { reactive, type Component } from "vue";
import MeasureDistanceTool from "@/components/measure/MeasureDistanceTool.vue";

export function useMeasureDistance(viewer: Ref<Viewer | null>) {
  const state = reactive({
    isActive: false,
  });

  // 返回组件引用,可以在模板中传递 props
  const MeasureDistanceComponent: Component = MeasureDistanceTool;

  return {
    state,
    MeasureDistanceComponent,
  };
}
vue
<template>
  <component
    :is="MeasureDistanceComponent"
    :viewer="viewer"
    v-if="state.isActive"
  />
</template>

注意事项

  • 组件必须正确导入或动态导入
  • 使用 component :is 时,组件会被正确渲染
  • 返回的组件可以接收 props 和 emit 事件
  • 组件的生命周期会正常执行