关于vue3:封装弹窗抽屉使用hook函数形式减少template内部代码

8次阅读

共计 3209 个字符,预计需要花费 9 分钟才能阅读完成。

hook 模式应用弹窗组件

vue3 新增了 composition api 之后,组件性能的拆分更加不便了,上面应用这种形式来编写弹窗组件,抽屉同理。

MyDrawer.vue

首先,自定义一个 dialog 组件。此组件外部裸露管制弹窗显隐的办法、和设置属性的办法,getCurrentInstance 是 vue 提供的获取组件实例的办法,具体代码如下———

<template>
  <el-dialog
    :before-close="()=>{ actionDialog(false) }"
    v-model="visible"
    v-bind="getProps"
  >
    <template #[item]="data" v-for="item in Object.keys($slots,'default')">
      <slot :name="item" v-bind="data"></slot>
    </template>
  </el-dialog>
</template>
<script lang="ts">
import {
  computed,
  defineComponent,
  getCurrentInstance,
  reactive,
  ref,
} from "vue";

export default defineComponent({
  name: "",
  setup(props, { emit}) {const visible = ref(false);
    const propsRef = reactive({
      visible: false,
      title: undefined,
    });
    const getProps = computed(() => {return Object.assign(propsRef, props);
    });

    const dialogInstance = {
      actionDialog,
      setProps,
    };

    const instance = getCurrentInstance();

    if (instance) {emit("register", dialogInstance);
    }

    function actionDialog(isShow: boolean) {visible.value = isShow;}

    function setProps(propsValue: any) {Object.assign(propsRef || {}, propsValue);
    }

    return {
      visible,
      getProps,
      actionDialog,
    };
  },
});
</script>

useDialog.ts

除了自定义组件外部须要做一些解决之外,还须要提供一个裸露一些操作弹窗办法的 useDialog 办法,这就是常说的 hook 函数吧。此处裸露一个 register 办法,在应用时该办法须要绑定在自定义 dialog 组件上。当创立了 dialog 组件后,就会触发 register 办法,将 dialog 实例和外部提供的办法传递进去,而后在父组件中应用。

import {ref, unref} from '@vue/reactivity'
import {isInSetup} from '/@/utils/help/vue'
import {DialogPropsModel, ResultModel, MethodsModel} from "./types";

export function useDialog(props?: DialogPropsModel): ResultModel {
  // 监测是否在 setup 外面调用
  isInSetup()

  const instanceRef = ref()
  const uuidRef = ref()

  function register(dialogInstance: any, uuid: string) {
    instanceRef.value = dialogInstance
    uuidRef.value = uuid

    props && methods.setProps(props)
  }

  const getInstance = () => {const instance = unref(instanceRef);
    if (!instance) {console.error('useModal instance is undefined!');
    }
    return instance;
  };


  const methods: MethodsModel = {actionDialog(open = true) {getInstance()?.actionDialog(open)
    },
    setProps(props: any) {getInstance()?.setProps(props)
    }
  }

  return [register, methods]
}

home.vue

具体应用时,在父组件中调用对应的 TestDialog 组件,而后应用 useDialog 函数暴露出 register 注册函数和 actionDialog 操作显隐的函数,将 register 绑定到 TestDialog 上,这样当组件被创立时,就会触发 emit 裸露办法再通过 useDialog 返回进去,也就是 actionDialog 函数,绑定对应的触发 Dom 上就 OK 了。

<template>
  <div>
    <el-button @click="actionDialog()">open dialog</el-button>
    <TestDialog @register="register" />
  </div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import {userStore} from "/@/store/modules/user";
import TestDialog from "/@/components/TestDialog.vue";
import {useDialog} from "/@/components/dialog/useDialog";

export default defineComponent({components: { MyDrawer},
  setup() {const [register, { actionDialog}] = useDialog({title: "Dialog"});
    return {
      register,
      actionDialog,
    };
  },
});
</script>

TestDialog.vue

TestDialog 组件中只须要调用 MyDialog 并应用 v -bind=”$attrs” 将所有的属性和事件传递给 MyDialog 就能够了。而后就能够在 MyDialog 中编写弹窗内显示的内容。弹窗的属性能够通过 useDialog 传递,也能够间接在 TestDialog 中编写。

<template>
  <MyDialog v-bind="$attrs">
    这是弹窗外部的内容!</MyDialog>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import MyDialog from "/@/components/dialog/MyDialog.vue";

export default defineComponent({
  name: "TestDrawer",
  components: {MyDialog},
  setup() {return {};
  },
});
</script>

弹窗代码的拆解,hook 模式的代码就实现了。实现了设置 dialog 属性和设置显示暗藏的简略性能。这样拆解之后,缩小了 Home 组件外部弹窗的 template 代码,能够随便的将属性在 js 中或者子组件中进行设置。尽管性能不简单,但编写起来难受了很多,否则 Home 组件中调用 element 原生的 dialog 组件的话,须要在 template 传递很多属性。如果间接抽离的话又须要在子组件中监听显隐变量,父组件监听显隐事件,写了很多与数据不相干的代码,代码看起来也不那么请爽。

正文完
 0