使用vue3 hook复用 弹窗组件

1,090 阅读2分钟

1.使用原因

公司需要一个数据表格以查看各项数据, 其中蓝色的字体(可点击), 点击之后打开弹窗查看订单列表细节. 编写多个弹窗不现实, 并且有5个页面需要编写类似功能, 于是想到复用弹窗组件, 放弃了props数据流的方法(因为每个页面都需要状态控制).转而 使用更易懂更简洁的 hook的方式.

2.hook内容

弹窗内的表格展示需要什么呢? 首先是控制弹窗的字段, 使用的地方直接设置即可控制弹窗的展示. 其次是弹窗的顶部title ,在最后就是表格的展示需要的列数据和表格数据. 为了规范操作使用统一的方法更新数据

import { reactive } from "vue";

const dialogConfig = reactive({
  title: "default_title",
  showList: [],
  columList: [],
  isShow: false,
  tableType: "",
});

export function useViewDialog() {
  return {
    dialogConfig,
    update(newData = {}) {
      let keys = Reflect.ownKeys(newData);
      keys.map((item) => {
        dialogConfig[item] = newData[item];
      });
    },
    clear() {
      dialogConfig.isShow = false;
      dialogConfig.title = "";
      dialogConfig.showList = [];
    },
  };
}

3.弹窗内容

这部分因为每个项目技术栈不同所以只展示关键部分代码

viewDialog.vue文件使用hook

//引入
import { useViewDialog } from "./useViewDialog.js";
const { dialogConfig, update, clear } = useViewDialog();

//监听表格数据
const tableData = computed(() => dialogConfig.showList ?? []);
const columData = computed(() => dialogConfig.columList ?? []);

//dialogConfig的数据可以直接使用 也可以使用computed
const title = computed(() => dialogConfig.title ?? '--');
const isShow = computed(() => dialogConfig.isShow ?? '--');

//关闭可直接调用hook内容清空数据
const closeModal = () => {
  clear();
};

数据在组件模板中使用

//页面
<template>
  <n-modal
    preset="dialog"
    :showIcon="false"
    :mask-closable="false"
    :style="{ width: '100vw', minHeight: '100vh' ,maxWidth:'100vw'}"
    @update:show="closeModal"
    :close-on-esc="false"
    :auto-focus="false"
    contentClass="tableStyle"
    :show="isShow"
  >
    <template #header>
      <div>
        {{ title }}
      </div>
    </template>
    <div class="">
      <n-data-table
        bordered
        remote
        striped
        :paginate-single-page="true"
        :single-line="false"
        :single-column="false"
        :columns="myColumns"
        :data="tableData"
        :row-key="(row) => row['orderId']"
      ></n-data-table>
    </div>
  </n-modal>
</template>

注意: 也可以单独处理赋值列数据取决于怎么使用

image.png

我这里是根据打开表单名字做的判断

4.弹窗的使用

因为使用的动态传递的缘故, 所以表格能点击的列需要自定义展示内容. 当前项目使用的NaiveUI, 需要使用render返回元素, 所以返回h函数创建的一个可点击的 span标签. stylePrimary为自定义的style. 表格列数据也应该在此传递进去. 因为我在弹窗部分做过处理, 所以没有传(copy的老系统代码, 直接根据title名字判断赋值列的数据).

import { useViewDialog } from "@/views/financial/commission/modal/viewDialog/useViewDialog.js";
const { update, clear } = useViewDialog();
//其中一个表格的一个列数据
   [{
    title: "xxxx",
    key: "monthOrderAmount",
    render: (row) => {
      const click = h(
        "span",
        {
          style: stylePrimary,
          onclick: () => {
            update({
              title: "xxxx",
              isShow: true,
              showList: row[operatorTableKey["monthOrderAmount"]] ?? [],
            });
          },
        },
        row?.monthOrderAmount ?? "--",
      );
      return click;
    },
    needSummary: true,
  },]

需要注意, 也要在表格所在vue文件引入弹窗组件(为此找了一会儿bug原因);

5.结语

以上是首次使用这种方式去复用组件, 以前都是用的父子组件传递数据的方式. 相比之下, 此方法更方便快捷.也减少多个组件使用的复杂度. 翻看其他开猿项目的复用组件也大多是用的此方法.