從0到1解鎖Element-Plus組件二次封裝El-Dialog動態調用

技術難題初登場

家人們,最近在開發一個超復雜的后臺管理系統項目,里面有各種數據展示、表單提交、權限控制等功能,在這個過程中,我頻繁地使用到了element-plus組件庫中的el-dialog組件 。它就像一個小彈窗,可以用來顯示各種提示信息、編輯表單之類的。比如說在用戶點擊 “編輯” 按鈕時,就彈出一個el-dialog,里面放著編輯表單,讓用戶修改數據。

但隨著功能的不斷完善,我發現原生的el-dialog組件在某些場景下真的不夠靈活。比如說,我想在不同的組件中根據不同的業務邏輯動態地控制對話框的顯示和隱藏,還要傳遞不同的數據給對話框,原生組件用起來就很麻煩,每次都要寫很多重復的代碼,這可太影響開發效率了。所以,我就決定對el-dialog進行二次封裝,實現動態調用,讓它更好地滿足我的項目需求。接下來,就把我的經驗分享給大家,一起看看怎么解決這個問題。

實現效果

在這里插入圖片描述

代碼實現

import { ElButton, ElDialog } from "element-plus";
import { createApp, h } from "vue";// 創建一個 DialogManager 類來管理對話框
class DialogManager {constructor() {this.dialogs = [];}/*** 創建并顯示一個動態對話框* @param {Object} options - 對話框配置選項* @returns {Object} - 返回對話框實例*/create(options = {}) {// 合并默認配置const defaultOptions = {title: "提示",visible: true,fullscreen: false,top: "15vh",modal: true,lockScroll: true,closeOnClickModal: true,closeOnPressEscape: true,beforeClose: null,footerBtns: [{label: "取消",type: "default",handler: (instance) => {instance.close();},},{label: "確定",type: "primary",handler: (instance) => {instance.close();},},],};const dialogOptions = { ...defaultOptions, ...options };// 創建一個容器元素const container = document.createElement("div");document.body.appendChild(container);// 創建 Dialog 組件實例const app = createApp({data() {return {dialogVisible: dialogOptions.visible,};},provide() {return {manager: this.$options.manager, // 提供manager};},inject: ["manager"], // 注入managerrender() {const footerNodes = dialogOptions.footerBtns.map((btn, index) => {return h(ElButton,{key: index,type: btn.type || "default",size: "small",onClick: () => {if (btn.handler) {btn.handler(this);}},},() => btn.label);});// 改進 content 渲染方式const renderContent = () => {if (typeof dialogOptions.content === "string") {return h("div", { class: "dialog-content" }, dialogOptions.content);} else if (dialogOptions.content) {// 只傳遞必要的屬性和方法const props = {// 提供關閉對話框的回調closeDialog: () => {this.close();},// 可以添加其他必要的屬性};// 如果有額外的 props,合并它們if (dialogOptions.contentProps) {Object.assign(props, dialogOptions.contentProps);}return h(dialogOptions.content, props);} else {return h("div", { class: "dialog-content" }, "No content provided");}};return h(ElDialog,{title: dialogOptions.title,modelValue: this.dialogVisible,"onUpdate:modelValue": (val) => {this.dialogVisible = val;},fullscreen: dialogOptions.fullscreen,top: dialogOptions.top,modal: dialogOptions.modal,lockScroll: dialogOptions.lockScroll,closeOnClickModal: dialogOptions.closeOnClickModal,closeOnPressEscape: dialogOptions.closeOnPressEscape,beforeClose: dialogOptions.beforeClose,onClose: () => {this.dialogVisible = false;if (dialogOptions.onClose) {dialogOptions.onClose(this);}// 延遲銷毀,讓關閉動畫完成setTimeout(() => {this.destroy();}, 300);},},{// 默認插槽用于對話框內容default: renderContent,footer: () =>h("div",{class: "dialog-footer",},footerNodes),});},methods: {// 關閉對話框close() {this.dialogVisible = false;},// 銷毀對話框實例destroy() {app.unmount();if (container.parentNode) {container.parentNode.removeChild(container);}// 從管理列表中移除if (this.manager) {const index = this.manager.dialogs.indexOf(this);if (index !== -1) {this.manager.dialogs.splice(index, 1);}}},},mounted() {// 添加到管理列表if (this.manager) {this.manager.dialogs.push(this);} else {console.error("Manager is not initialized");}},}).provide("manager", this); // 全局提供manager// 掛載應用const instance = app.mount(container);instance.manager = this; // 直接在實例上設置managerreturn instance;}/*** 關閉所有對話框*/closeAll() {this.dialogs.forEach((dialog) => {dialog.close();});}
}// 創建單例實例
const dialogManager = new DialogManager();// 導出創建對話框的函數
export function createDialog(options) {return dialogManager.create(options);
}// 導出關閉所有對話框的函數
export function closeAllDialogs() {dialogManager.closeAll();
}

調用示例

-------------------------------- 基本文本對話框 -------------------------------------
import { createDialog } from '@/utils/dialog-manager';export default {methods: {showSimpleDialog() {createDialog({title: '確認操作',content: '你確定要執行這個操作嗎?',onClose: () => {console.log('對話框已關閉');},footerBtns: [{label: '取消',handler: (instance) => {console.log('點擊了取消');instance.close();},},{label: '確認',type: 'primary',handler: (instance) => {console.log('執行確認操作');instance.close();},},],});},},
};-------------------------- 包含組件的對話框 --------------------------------
import { createDialog } from '@/utils/dialog-manager';
import MyComponent from '@/components/MyComponent.vue';export default {methods: {showComponentDialog() {createDialog({title: '自定義組件對話框',content: MyComponent,contentProps: {     // 這里可以傳入組件的propsmessage: '這是來自父組件的消息',src: 'xxx',},width: '600px',footerBtns: [{label: '關閉',handler: (instance) => {instance.close();},},],});},},
};-------------------------- 異步操作對話框 --------------------------------import { createDialog } from '@/utils/dialog-manager';export default {methods: {async showAsyncDialog() {const dialog = createDialog({title: '正在加載...',content: '數據加載中,請稍候...',showClose: false, // 隱藏關閉按鈕footerBtns: [],   // 不顯示底部按鈕});try {// 模擬異步操作const result = await this.fetchData();dialog.close();// 顯示成功消息createDialog({title: '操作成功',content: '數據加載完成',footerBtns: [{label: '確定',type: 'primary',handler: (instance) => instance.close(),},],});} catch (error) {dialog.close();// 顯示錯誤消息createDialog({title: '操作失敗',content: `錯誤: ${error.message}`,footerBtns: [{label: '關閉',handler: (instance) => instance.close(),},],});}},},
};

原理剖析

這里面的原理其實也不難理解,主要是利用了Vue的響應式原理 。我們都知道,在Vue中,數據發生變化時,視圖會自動更新。我們封裝的組件就是基于這個特性,通過一個響應式的變量來控制el-dialog的顯示與隱藏。比如說,我們定義一個isDialogVisible變量,當它為true時,el-dialog就顯示,為false時就隱藏 。

而動態傳遞參數呢,則是通過props來實現的。我們在封裝的組件中定義好props,然后在調用組件的時候,就可以把需要的數據通過props傳遞進去,這樣對話框就能根據不同的數據展示不同的內容啦 。比如說,我們要在對話框里顯示不同的提示信息,就可以把提示信息作為props傳遞給對話框組件 。再結合provideinject,它們就像是一座橋梁,能夠讓不同層級的組件之間方便地進行通信,讓數據的傳遞更加靈活 。

實際應用場景

經過二次封裝實現動態調用的el-dialog在實際項目中的應用場景可太廣泛了 。比如說在用戶信息編輯場景,當用戶點擊 “編輯” 按鈕,就可以動態彈出我們封裝好的對話框,里面填充好用戶當前的信息,用戶修改完成后點擊確認,就能提交新的信息,整個過程非常流暢自然 。

在文件上傳確認場景,當用戶選擇好文件準備上傳時,彈出對話框讓用戶確認文件信息,比如文件名、文件大小等 。如果沒問題再點擊上傳,這樣可以避免用戶誤操作上傳錯誤的文件 。還有在權限管理中,當管理員要給某個用戶分配新的權限時,通過動態調用對話框,展示所有權限選項,管理員勾選后提交,就能完成權限分配,操作簡單又高效 。

總結

經過二次封裝實現動態調用的el-dialog組件,不僅大大提高了代碼的復用性,讓我們在不同的業務場景中能夠輕松應對對話框的各種需求,還增強了項目的靈活性和可維護性。以前寫一堆重復代碼的日子一去不復返啦!

強烈建議各位小伙伴在自己的項目中也嘗試應用這種二次封裝的方法 ,相信你們會發現它的強大之處。要是在實踐過程中有什么經驗,或者遇到了問題,都歡迎在評論區留言分享。咱們一起交流,共同進步 !

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/87720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/87720.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/87720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據結構實驗習題

codeblock F2是出控制臺 1.1 /* by 1705 WYY */ #include <stdio.h> #include <stdlib.h> #define TRUE 1 #define FALSE 0 #define YES 1 #define NO 0 #define OK 1 #define ERROR 0 #define SUCCESS 1 #define UNSUCCESS 0 #define OVERFLOW -2 #define UNDERF…

PyTorch 2.7深度技術解析:新一代深度學習框架的革命性演進

引言:站在AI基礎設施變革的歷史節點 在2025年這個充滿變革的年份,PyTorch團隊于4月23日正式發布了2.7.0版本,隨后在6月4日推出了2.7.1補丁版本,標志著這個深度學習領域最具影響力的框架再次迎來了重大突破。這不僅僅是一次常規的版本更新,而是一次面向未來計算架構和AI應…

LTspice仿真10——電容

電路1中電容下標m5&#xff0c;表示5個該電阻并聯電路2中ic1.5v&#xff0c;表示電容初始自帶電量&#xff0c;電壓為1.5v

C#事件驅動編程:標準事件模式完全指南

事件驅動是GUI編程的核心邏輯。當程序被按鈕點擊、按鍵或定時器中斷時&#xff0c;如何規范處理事件&#xff1f;.NET框架通過EventHandler委托給出了標準答案。 &#x1f50d; 一、EventHandler委托&#xff1a;事件處理的基石 public delegate void EventHandler(object se…

全面的 Spring Boot 整合 RabbitMQ 的 `application.yml` 配置示例

spring:rabbitmq:# 基礎連接配置 host: localhost # RabbitMQ 服務器地址port: 5672 # 默認端口username: guest # 默認用戶名password: guest # 默認密碼virtual-host: / # 虛擬主機&#xff08;默認/&…

Win32 API實現串口輔助類

近期需要使用C++進行串口通訊,將Win32 API串口接口進行了下封裝,可實現同步通訊,異步回調通訊 1、SerialportMy.h #pragma once #include <Windows.h> #include <thread> #include <atomic> #include <functional> #include <queue> #inclu…

Python-執行系統命令-subprocess

1 需求 2 接口 3 示例 4 參考資料 Python subprocess 模塊 | 菜鳥教程

Web攻防-XMLXXE上傳解析文件預覽接口服務白盒審計應用功能SRC報告

知識點&#xff1a; 1、WEB攻防-XML&XXE-黑盒功能點挖掘 2、WEB攻防-XML&XXE-白盒函數點挖掘 3、WEB攻防-XML&XXE-SRC報告 一、演示案例-WEB攻防-XML&XXE-黑盒功能點挖掘 1、不安全的圖像讀取-SVG <?xml version"1.0" standalone"yes&qu…

瀏覽器工作原理37 [#] 瀏覽上下文組:如何計算Chrome中渲染進程的個數?

一、前言 在默認情況下&#xff0c;如果打開一個標簽頁&#xff0c;那么瀏覽器會默認為其創建一個渲染進程。 如果從一個標簽頁中打開了另一個新標簽頁&#xff0c;當新標簽頁和當前標簽頁屬于同一站點&#xff08;相同協議、相同根域名&#xff09;的話&#xff0c;那么新標…

位置編碼和RoPE

前言 關于位置編碼和RoPE 應用廣泛&#xff0c;是很多大模型使用的一種位置編碼方式&#xff0c;包括且不限于LLaMA、baichuan、ChatGLM等等 第一部分 transformer原始論文中的標準位置編碼 RNN的結構包含了序列的時序信息&#xff0c;而Transformer卻完全把時序信息給丟掉了…

手動使用 Docker 啟動 MinIO 分布式集群(推薦生產環境)

在生產環境中&#xff0c;MinIO 集群通常部署在多個物理機或虛擬機上&#xff0c;每個節點運行一個 MinIO 容器&#xff0c;并通過 Docker 暴露 API 和 Console 端口。 1. 準備工作 假設有 4 臺服務器&#xff08;也可以是同一臺服務器的不同端口模擬&#xff0c;但不推薦生產…

如何在IntelliJ IDEA中設置數據庫連接全局共享

在現代軟件開發中&#xff0c;數據庫連接管理是開發過程中不可或缺的一部分。為了提高開發效率&#xff0c;減少配置錯誤&#xff0c;并方便管理&#xff0c;IntelliJ IDEA 提供了一個非常有用的功能&#xff1a;數據庫連接全局共享。通過這個功能&#xff0c;你可以在多個項目…

【Python】文件應用: 查找讀取的文件內容

查找讀取的文件內容 from pathlib import Pathpath Path(pi_million_digits.txt) contents path.read_text()lines contents.splitlines() pi_string for line in lines:pi_string line.lstrip()birthday input("Enter your birthday, in the form mmddyy: "…

交互式剖腹產手術模擬系統開發方案

以下是為您設計的《交互式剖腹產手術模擬系統》開發方案框架,包含技術實現路徑與詳細內容結構建議。由于篇幅限制,這里呈現核心框架與關鍵模塊說明: 交互式剖腹產手術模擬系統開發方案 一、項目背景與意義 1.1 傳統醫學教學痛點分析 尸體標本成本高昂(約$2000/例)活體訓…

AWS WebRTC: 判斷viewer端拉流是否穩定的算法

在使用sdk-c viewer端進行拉流的過程中&#xff0c;viewer端拉取的是視頻幀和音頻幀&#xff0c;不會在播放器中播放&#xff0c;所以要根據收到的流來判斷拉流過程是否穩定流暢。 我這邊采用的算法是&#xff1a;依據相鄰幀之間的時間間隔是否落在期望值的 20% 范圍內。 音頻…

【Python】文件讀取:逐行讀取應用實例——從一個JSONL文件中逐行讀取文件

從一個JSONL文件中逐行讀取文件&#xff0c;并將這些問題保存到一個新的JSONL文件中 import json import argparse import os # 導入os模塊用于檢查文件是否存在def read_questions_from_jsonl(file_path, limit):"""從JSONL文件中讀取指定數量的question部分…

百寶箱生成智能體

點擊新建應用 工作流如下&#xff1a; 點擊發布 點擊Web服務&#xff0c;上架

嵌入式 數據結構學習(五) 棧與隊列的實現與應用

一、棧(Stack)詳解 1. 棧的基本概念 棧的定義與特性 后進先出(LIFO)&#xff1a;最后入棧的元素最先出棧 操作限制&#xff1a;只能在棧頂進行插入(push)和刪除(pop)操作 存儲位置&#xff1a;我們實現的鏈棧位于堆區(malloc分配)&#xff0c;系統棧區存儲函數調用信息 棧…

匯編與接口技術:8259中斷實驗

一、實驗目的 該實驗使學生掌握8259向量中斷方式的硬件連接和軟件編程的方法&#xff0c;同時使同學掌握中斷和其它接口芯片配合來完成某一特定任務的方法。 二、實驗內容 1、手動產生單脈沖作為中斷請求信號連接到MIRQ3上和SIRT10上。每按一次開關產生一次中斷&#xff0c;…

Ajax的初步學習

一、什么是 Ajax&#xff1f; Ajax (Asynchronous JavaScript and XML) 是一種無需重新加載整個網頁的情況下&#xff0c;能夠更新部分網頁的技術。通過在后臺與服務器進行少量數據交換&#xff0c;Ajax 可以使網頁實現異步更新。 主要特性&#xff1a; 異步性 (Asynchronous…