前言
这是我新开的一个对于前端常识的模块,次要解说日常开发中罕用的前端技巧。此模块解说的常识都是能大幅晋升前端性能的奇技淫巧,供大家日常交换,同时也心愿大家不吝赐教,指出自己的有余。
本文应用的技术栈: vue3 + typescript + pinia + element-plus
背景
modal 模态框又称之为弹出框、对话框,是前端日常开发最为频繁的组件之一。然而在日常开发过程中常常遇到一些性能、或者写法繁琐的问题。上面是我举例的一些常见问题:
1.modal 框塞入以后页面会导致整个组件更新,影响性能
<template>
<div class="about">
<el-button class="todo-list--add-btn" @click="showModal">
增加工作
</el-button>
<ul>
<li
class="todo-list--item-box"
v-for="(item, index) in list"
:key="item.title">
<div>{{item.title}}</div>
<div class="todo-list--add-btn" @click="handleDelToDoList(index)">
删除
</div>
</li>
</ul>
// 此种形式更新会带动组件的更新
<el-dialog :model-value="show" title="增加工作" width="30%">
<el-input v-model="todoListAddInput" placeholder="请输出" />
<template #footer>
<span class="dialog-footer">
<el-button @click="modalStore.hideModal(ModalType.TODO_LIST)">
勾销
</el-button>
<el-button type="primary" @click="handleAddToDolist"> 提交 </el-button>
</span>
</template>
</el-dialog>
</div>
</template>
- 许多后盾利用的 modal 框体量都是十分宏大的,一些流程 modal 框动辄成千盈百行代码很失常,如果在首次加载势必影响首次加载耗时
- vue 应用 teleport,react 应用 createPortal 把 modal 框放到根节点是一些公司的次要优化伎俩,然而没有全局注册调用事件,导致 modal 框管理混乱,前端开发人员开发的 modal 框组件遍布我的项目各个文件夹
上面我就针对以上问题做出解决方案
构造示意图:
全局注册 modal 框
应用 pinia 进行 modal 的全局治理不仅能使各个组件很不便的调用 model 框,还能对立 modal 入口,方便管理。
// 全局 modal 框惟一身份标识
export enum ModalType {TODO_LIST,}
// modal 框所须要的参数注册接口
export interface ModalDataType {[ModalType.TODO_LIST]: {onSubmit: (value: string) => void;
}
;}
// modal 框实例对象接口
interface ModalInstance<T extends ModalType> {
type: T; // modal 框标识
component: any; // modal 框 vue 组件
data?: ModalDataType[T]; // modal 框传值
onEnter?: (data: ModalDataType[T]) => void; // 生命周期钩子,在 modal 框显示之后调用
onExit?: (data: ModalDataType[T]) => void; // 生命周期钩子,在 modal 框显暗藏之后调用
}
type ModalListItem = {[key in ModalType]: ModalInstance<ModalType> };
通过以上代码咱们就设计好了全局 modal 框的所用到的属性。通过对这些属性的使用,咱们能够很不便的建设起一个全局数据中心,这一步解决了 modal 框的治理问题 (具体代码详见文章结尾 GitHub 地址):
useModalStore = {
//modal 注册核心,当有新 modal 被关上时,把 modal 实例注册到此对象
modalInstanceMap: Ref<ModalListItem>
// 以后关上的 modal 的汇合
showModalList: Ref<ModalType>
//modal 框开启函数,如果以后关上的 modal 未被注册,showModal 将注册此组件
showModal: <T extends ModalType>(modalType: T, data?: ModalDataType[T] | undefined) => void
//modal 框暗藏函数
hideModal:(modalType: ModalType) => void
// 注册 modal 框生命周期钩子 onEnter
onEnter:<T extends ModalType>(modalType: T, fn: (data: ModalDataType[T]) => void) => void
// 注册 modal 框生命周期钩子 onExit
onExit:<T extends ModalType>(modalType: T, fn: (data: ModalDataType[T]) => void) => void
}
全局挂载 modal 框
建设起全局数据中心,咱们下一步就是全局注册 modal 框,这一步解决了咱们先前所提到的 modal 框在其余组件外部注册 modal 框,影响性能的问题:
// app.ts
<script>
import {useModalStore} from "@/stores/modal";
const modalStore = useModalStore();
<template>
...
...
<component
v-for="item in modalStore.modalList"
:key="item.type"
:is="item.component"
/>
...
modal 框实例创立
这一步咱们创立所需的对应的模态框,创立步骤为以下流程
- modal 全局数据中心注册 modal 组件(新建一个 ModalType 枚举,定义 modal 组件传参,引入 modal 组件并注册)
2. 编写 modal 组件,注册 modal 组件的显示暗藏函数
// /modal/todolist.vue
import {ModalType, useModalStore, type ModalDataType} from "@/stores/modal";
import {computed, ref} from "vue";
const modalStore = useModalStore();
const todoListAddInput = ref();
// 管制 modal 的显示暗藏
const show = computed(() => modalStore.showModalList.includes(ModalType.TODO_LIST));
- 注册生命周期钩子,此钩子能够拿到传入的参数,并且因为做了泛型解决,data 的属性为对应的 ModalType 的传参类型(具体能够拜访文章前面的 github 地址感受一下)
modalStore.onEnter(ModalType.TODO_LIST, (data) => {props = data});
modalStore.onExit(ModalType.TODO_LIST, () => {todoListAddInput.value = ""});
调用 modal 框
// todolist.vue
<script>
import {useModalStore, ModalType} from "@/stores/modal";
interface TodoList {title: string;}
const modalStore = useModalStore();
function showModal() {
modalStore.showModal(ModalType.TODO_LIST, {onSubmit: // 自定义提交函数})
}
这样咱们就能够很不便的在各个组件调用 modal 框了,
结尾
致力于代码层面的优化,进步本身编程能力。通过上述优化操作,解决了 modal 的大部分痛点,心愿可能帮忙到你。
我的项目地址:https://github.com/charCR2/vue-repo/tree/main/modal-example(记得给 star 哈~,感激)