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传递很多属性。如果间接抽离的话又须要在子组件中监听显隐变量,父组件监听显隐事件,写了很多与数据不相干的代码,代码看起来也不那么请爽。