欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從0到1解鎖Element-Plus組件二次封裝El-Dialog動態(tài)調(diào)用的原理解析

 更新時間:2025年07月07日 09:38:59   作者:hackchen  
作者通過二次封裝Element-Plus的el-dialog組件,實現(xiàn)動態(tài)顯示與數(shù)據(jù)傳遞功能,提升項目靈活性和代碼復(fù)用性,適用于用戶編輯、文件上傳確認(rèn)、權(quán)限管理等多場景需求,本文給大家介紹從0到1解鎖Element-Plus組件二次封裝El-Dialog動態(tài)調(diào)用的原理解析,感興趣的朋友一起看看吧

技術(shù)難題初登場

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

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

實現(xiàn)效果

代碼實現(xiàn)

import { ElButton, ElDialog } from "element-plus";
import { createApp, h } from "vue";
// 創(chuàng)建一個 DialogManager 類來管理對話框
class DialogManager {
  constructor() {
    this.dialogs = [];
  }
  /**
   * 創(chuàng)建并顯示一個動態(tài)對話框
   * @param {Object} options - 對話框配置選項
   * @returns {Object} - 返回對話框?qū)嵗?
   */
  create(options = {}) {
    // 合并默認(rèn)配置
    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 };
    // 創(chuàng)建一個容器元素
    const container = document.createElement("div");
    document.body.appendChild(container);
    // 創(chuàng)建 Dialog 組件實例
    const app = createApp({
      data() {
        return {
          dialogVisible: dialogOptions.visible,
        };
      },
      provide() {
        return {
          manager: this.$options.manager, // 提供manager
        };
      },
      inject: ["manager"], // 注入manager
      render() {
        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 = {
              // 提供關(guān)閉對話框的回調(diào)
              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);
              }
              // 延遲銷毀,讓關(guān)閉動畫完成
              setTimeout(() => {
                this.destroy();
              }, 300);
            },
          },
          {
            // 默認(rèn)插槽用于對話框內(nèi)容
            default: renderContent,
            footer: () =>
              h(
                "div",
                {
                  class: "dialog-footer",
                },
                footerNodes
              ),
          }
        );
      },
      methods: {
        // 關(guān)閉對話框
        close() {
          this.dialogVisible = false;
        },
        // 銷毀對話框?qū)嵗?
        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
    // 掛載應(yīng)用
    const instance = app.mount(container);
    instance.manager = this; // 直接在實例上設(shè)置manager
    return instance;
  }
  /**
   * 關(guān)閉所有對話框
   */
  closeAll() {
    this.dialogs.forEach((dialog) => {
      dialog.close();
    });
  }
}
// 創(chuàng)建單例實例
const dialogManager = new DialogManager();
// 導(dǎo)出創(chuàng)建對話框的函數(shù)
export function createDialog(options) {
  return dialogManager.create(options);
}
// 導(dǎo)出關(guān)閉所有對話框的函數(shù)
export function closeAllDialogs() {
  dialogManager.closeAll();
}

調(diào)用示例

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

原理剖析

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

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

實際應(yīng)用場景

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

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

總結(jié)

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

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

到此這篇關(guān)于從0到1解鎖Element-Plus組件二次封裝El-Dialog動態(tài)調(diào)用的文章就介紹到這了,更多相關(guān)Element-Plus二次封裝El-Dialog內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue+Canvas制作簡易的水印添加器小工具

    Vue+Canvas制作簡易的水印添加器小工具

    隨著搬運工的逐漸增加,原創(chuàng)作者的利益收到了極大的影響。所以給圖片或視頻加上水印顯得極其重要。本文分享一個由canvas和vue.js制作的圖片水印添加器,需要的可參考一下
    2022-06-06
  • Vue實例簡單方法介紹

    Vue實例簡單方法介紹

    這篇文章主要為大家詳細(xì)介紹了Vue實例的一些簡單方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • vue表格(table)計算總計方式

    vue表格(table)計算總計方式

    這篇文章主要介紹了vue表格(table)計算總計方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • vue使用axios實現(xiàn)動態(tài)追加數(shù)據(jù)

    vue使用axios實現(xiàn)動態(tài)追加數(shù)據(jù)

    在vuejs中使用axios時,有時候需要追加數(shù)據(jù),比如,移動端下拉觸底加載,分頁加載,滑動滾動條等,下面小編就來為大家介紹一下如何使用使用axios實現(xiàn)動態(tài)追加數(shù)據(jù)吧
    2023-10-10
  • 使用reactive導(dǎo)致數(shù)據(jù)失去響應(yīng)式的原因和解決方案

    使用reactive導(dǎo)致數(shù)據(jù)失去響應(yīng)式的原因和解決方案

    在 Vue 的響應(yīng)式系統(tǒng)中,reactive 對象是一個深度代理,它會追蹤對象屬性的變更,但如果你將整個對象重新賦值,那么 Vue 無法繼續(xù)追蹤新的對象,本文給大家介紹了使用reactive導(dǎo)致數(shù)據(jù)失去響應(yīng)式的原因和解決方案,需要的朋友可以參考下
    2024-09-09
  • Vue實現(xiàn)各種類型文件的預(yù)覽功能

    Vue實現(xiàn)各種類型文件的預(yù)覽功能

    這篇文章主要介紹了如何在Vue3中使用aceEditor插件和vue-ipynb插件實現(xiàn)不同類型的文件預(yù)覽,包括txt、md、json、pkl、mps、py、ipynb、doc、docx、pdf、xlsx、csv等文件,需要的朋友可以參考下
    2025-03-03
  • 誤引用vuex-persistedstate導(dǎo)致用戶信息無法清除問題及解決

    誤引用vuex-persistedstate導(dǎo)致用戶信息無法清除問題及解決

    這篇文章主要介紹了誤引用vuex-persistedstate導(dǎo)致用戶信息無法清除問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue.js實現(xiàn)雙擊放大預(yù)覽功能

    vue.js實現(xiàn)雙擊放大預(yù)覽功能

    這篇文章主要為大家詳細(xì)介紹了vue.js實現(xiàn)雙擊放大預(yù)覽功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • 使用element-ui的Pagination分頁的注意事項及說明

    使用element-ui的Pagination分頁的注意事項及說明

    這篇文章主要介紹了使用element-ui的Pagination分頁的注意事項及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • Vue.js路由組件vue-router使用方法詳解

    Vue.js路由組件vue-router使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Vue.js路由組件vue-router使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12

最新評論