对应 https://blog.bitsrc.io/new-re...

抽逻辑到一个 composition API:

/** 
 * 将逻辑统一抽到一个文件当中, 方便逻辑的复用
 * 没有确认清楚是否可能带来性能方面的问题, 以及对调试工具不如组件友好
 */

import { computed, ref } from 'vue';
import { NDialog, NLink } from '<ui-package>';

/** 用法, 作为 Hooks API 使用
 * const p = warnDeletePublishment()
 */
export const warnDeletePublishment = () => {
  const visible = ref(false);

  const showDialog = () => {
    visible.value = true;
  };

  const dom = computed(() => {
    return (
      <NDialog
        modelValue={visible.value}
        onUpdate:modelValue={(v) => {
          visible.value = v;
        }}
        v-slots={{
          footer: () => {
            return (
              <div class="flex flex-row justify-between">
                <span />
                <NLink onClick={() => (visible.value = false)}>关闭</NLink>
              </div>
            );
          },
        }}
      >
        <div>
          warning content
        </div>
      </NDialog>
    );
  });

  return {
    /** 用法
     * p.show() */
    show: showDialog,
    /** 用法
     * <DynamicDom dom={p.dom} />
     */
    dom,
  };
};

用法非常简短, 状态和 UI 都封装了:

<template>
  <DynamicDom :dom="warnDeletePlugin.dom"></DynamicDom>
</template>

<script setup lang="ts">
  const warnDeletePlugin = warnDeletePublishment();

  function handleRemove(publishment: PackagePublishment) {
    warnDeletePlugin.show();
  }
</script>

渲染动态的 UI, 需要一个组件包装:

/**
 * 这种写法可能带来了额外的性能问题?
 *
 * 配合 plugin 写法使用, 用于渲染 `ComputedRef<VNode>` 到 template 写法的页面当中
 */

import { ComputedRef, defineComponent, PropType, VNode } from 'vue';
import { onMounted, ref, watch } from 'vue';

const DynamicDom = defineComponent({
  props: {
    dom: {
      required: true,
      type: Object as PropType<ComputedRef<VNode>>,
    },
  },

  setup(props) {
    return () => props.dom.value;
  },
});

export default DynamicDom;

使用 expose

Vue 也支持直接从外部操作 Component 方法, 借助 expose:

https://www.vuemastery.com/bl...

https://vuejs.org/api/composi...


题叶
17.3k 声望2.6k 粉丝

Calcit 语言作者