Vue3 H5 项目尝试(五)

269 阅读1分钟

provider提供通用方法调用组件

背景

由于项目面向pc端和移动端,又因为涉及聊天以及表单提交等内容,组内用的最多的ui库就是pc端是element和vant,所以采用了用element-plus和vant3两个ui库分别开发对应端的业务模板。

业务模板可以区分,但业务逻辑肯定是可以高度重用的,利用Vue3的Composition API能很好的抽象业务代码,但是又有问题引出来了,像类似

  • Message 消息提示
  • MessageBox 弹框
  • Loading 加载

等组件在业务代码里都是要用到的,怎么样做才能根据不同的端用相同的业务代码能展示上述不同端的业务组件?

provider

分别设计pc和mobile的provider将各端组件绑定到window上

Talk is cheap,show me the code

PCProvider.vue

<template></template>
<script lang="ts">
  interface NotifyObj {
    type: string;
    iconName: string;
    background: string;
    color: string;
    message: string;
  }

  export default {
    name: 'PCProvider',
    setup() {
      let message: any = null;
      let loadingInstance: any = null;
      window['$loading'] = {
        service: (text: string, fullscreen = true) => {
          loadingInstance = ElLoading.service({ fullscreen, text });
        },
        finish: () => {
          loadingInstance && loadingInstance.close();
        },
      };
      window['$confirm'] = (msg, config = {}) =>
        ElMessageBox.confirm(msg, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning',
          ...config,
        });
      //挂载在 window 方便与在js中使用
      window['$message'] = {
        ...ElMessage,
        cusShow: async (obj: NotifyObj) => {
          if (message) await message.close();
          message = ElMessage({
            duration: 0,
            type: 'success',
            ...obj,
          });
        },
        cusOff: async (obj?: NotifyObj) => {
          if (message) await message.close();
          if (obj && message) {
            ElMessage({
              duration: 500,
              type: 'success',
              ...obj,
            });
          }
          message = null;
        },
      };
    },
  };
</script>

<style>
  .el-message-box__status {
    position: absolute !important;
  }
</style>

MobileProvider.vue

<template> </template>
<script lang="ts">
  import { Notify, Toast, Dialog } from 'vant';

  interface NotifyObj {
    type: string;
    iconName: string;
    background: string;
    color: string;
    message: string;
  }

  export default {
    name: 'MobileProvider',
    setup() {
      let notify = null;
      //挂载在 window 方便与在js中使用
      window['$toast'] = { ...Toast };
      window['$loading'] = {
        service: (message: string, duration = 0, forbidClick = true) => {
          Toast.loading({ message, duration, forbidClick });
        },
        finish: () => {
          Toast.clear();
        },
      };
      // window['$loading'] = (opt) => Toast.loading(opt);
      window['$message'] = {
        ...Notify,
        success: (msg: string) =>
          Notify({
            type: 'success',
            message: msg,
          }),
        warning: (msg: string) =>
          Notify({
            type: 'warning',
            message: msg,
          }),
        message: (msg: string) =>
          Notify({
            type: 'primary',
            message: msg,
          }),
        error: (msg: string) =>
          Notify({
            type: 'danger',
            message: msg,
          }),
        cusShow: async (obj: NotifyObj) => {
          if (notify) {
            await Notify.clear();
          }
          notify = Notify({
            duration: 0,
            type: 'success',
            ...obj,
          });
        },
        cusOff: async (obj?: NotifyObj) => {
          if (notify) {
            await Notify.clear();
          }
          if (obj && notify) {
            Notify({
              duration: 500,
              type: 'success',
              ...obj,
            });
          }
          notify = null;
        },
      };
      window['$confirm'] = (message, config = {}) =>
        Dialog.confirm({
          title: '提示',
          confirmButtonColor: '#2d8cf0',
          ...config,
          message,
        });
    },
  };
</script>

在各端入口html文件处定义一个

<div id="appProvider" style="display: none"></div>

通过入口处挂载

const appProvider = createApp(MobileProvider);

appProvider.mount('#appProvider', true);

在不同端的入口文件挂载不同的provider,业务代码中可通过window[$component]去调用组件,便会展示对应端的组件。