弹窗是前端中一个很常见的业务功能,通常弹窗分两个页面现实,这两个页面是父子关系。
实现需要的vue-composition-api:inject, provide, ref, watchEffect
这个hooks一共只有两个方法:控制打开弹窗(openModal)、控制关闭弹窗(closeModal)
openModal
/**
* 控制打开弹窗
* @param modelName 相对应的弹窗组件名(这里是自己定义的一个接口,一是为了编码代码时候友好提示,十是为了防止代码出错)
* @returns openAction 打开弹窗方法
*/
export function openModal(modelName: keyof ModalName) {
const name = ref<boolean>(false)
provide(modelName, name);
/**
* 打开弹窗
* @param value 弹窗名
*/
function openAction() {
name.value = true;
}
return { openAction }
}
/**
* 控制关闭弹窗
* @param modelName 相对应的弹窗组件名
* @returns
*/
export function closeModal(modelName: keyof ModalName) {
// 控制弹窗 flag
const visible = ref<boolean>(false);
const show = inject(modelName, ref<boolean>(false))
watchEffect(() => {
visible.value = show.value
})
/**
* 取消弹窗
*/
function cancel() {
visible.value = false;
show.value = false
}
/**
* 带有回调函数关闭弹窗
* @param callback
*/
function handleOk(callback: Function) {
cancel();
callback && callback()
}
return { visible, cancel, handleOk }
}
ModalName 是我们定义好的接口名,这样做一是了防止出错,二是了有友好提示
在父组件里引入openModal,并在setup里调用openModal方法,传入参数就是我们定义好的,弹窗组件名。
在子组件里引入closeModal,并在setup里调用closeModall方法,传入参数就是我们定义好的,弹窗组件名。
这个时候在父组件里provide弹窗名,在子组件inject弹窗名,这样父子组件就建立了一个通信渠道
当父组件需要弹窗的时候,调用openAction方法,这个时候就会更改provide的value为true(默认是false),子组 件里show(接受inject的值)的value就会变化,而我们通过watchEffect追踪其依赖show的依赖,并更改控制弹窗 的flag—visible,这样就达到了控制打开弹窗。
关闭弹窗很简单,设置控制弹窗 的flag——visible为false,并把show.value重置为默认值false
个人实现示例:github.com/Buzhifanji/…
父组件
<template>
<div class="home">
<div @click="openNotice">消息-弹窗</div>
<Notice />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { openModal } from "@/setup/controlModal/index"; // 控制弹窗逻辑
import Notice from "./notice.vue";
export default defineComponent({
name: "home",
components: {
Notice,
},
setup() {
// 打开弹窗
const { openAction } = openModal("notice");
return { openAction };
}
});
</script>
子组件
<template>
<div class="modal">
<a-modal class="notice"
v-model:visible="visible"
@cancel="cancel"
width="890px"
title="弹窗"
:footer="null"
@ok="handleOk">
我是一个消息弹窗
</a-modal>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { closeModal } from "../setup/controlModal/index";
export default defineComponent({
name: "modal",
components: {},
setup() {
// visible 是否弹窗flag
// cancel 关闭弹窗
// 带有回调函数关闭弹窗(预留需要关闭弹窗进行其他操作)
const { visible, cancel, handleOk } = closeModal("notice");
return { visible, cancel };
}
});
</script>
父组件调用openModal,子组件调用closeModal,封装后代码简洁,优雅