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

如何封裝一個可用js直接調(diào)用的彈窗組件

 更新時間:2025年05月21日 09:57:11   作者:wyfgoodgoodstudy  
這篇文章主要介紹了如何封裝一個可用js直接調(diào)用的彈窗組件的相關資料,通過Vue.extend動態(tài)創(chuàng)建實例,支持Promise異步關閉,提升復用性與開發(fā)效率,實現(xiàn)類似原生alert的調(diào)用方式,文中給出了詳細的代碼示例,需要的朋友可以參考下

前言

在Vue開發(fā)中,正常的組件通常以模板方式調(diào)用,但對于彈窗這種呈現(xiàn)方式,使用模板的方式開發(fā)過于繁瑣,怎樣才能讓彈窗組件可以像原生alert()一樣通過函數(shù)調(diào)用觸發(fā)彈窗呢?本文將基于Vue2,詳細講解如何封裝一個可通過JavaScript函數(shù)直接調(diào)用的彈窗組件,實現(xiàn)高復用性和開發(fā)效率的提升。

一、開發(fā)思路

1. 先封裝一個正常的彈窗組件

2. 使用Vue.extend動態(tài)構造組件實例,并掛載到新創(chuàng)建的DOM節(jié)點

3. 需要支持Promise的方式捕獲確定和取消操作,同時支持確定按鈕異步關閉。比如點確定后調(diào)個接口,接口返回處理后,再讓彈窗關閉。

二、開發(fā)過程

1.封裝彈窗組件

代碼如下:

<template>
  <div class="my-dialog-container" v-if="visible" :style="{ 'z-index': zIndex }">
    <div class="mask" v-if="showMask" :style="{ 'z-index': zIndex + 1 }"></div>
    <div class="my-dialog-bg" @click="clickMask" :style="{ 'z-index': zIndex + 2 }">
      <div
        class="my-dialog"
        :style="{ width: width ? width : '60%' }"
        @click.stop="clickDialog"
      >
        <!-- 這里添加一個stop的事件,在點擊彈窗區(qū)域時,阻止向上冒泡觸發(fā)clickMask,把彈窗關掉了 -->
        <div class="dialog-header">
          <div class="dialog-title">{{ title }}</div>
          <div class="close-btn" v-if="showClose" @click="doClose">
            <i class="el-icon-close"></i>
          </div>
        </div>
        <div class="dialog-content" v-if="content">
          <div class="dialog-type-icon" v-if="type">
            <i
              class="el-icon-warning"
              style="color: #e6a23c"
              v-if="type == 'warning'"
            ></i>
            <i class="el-icon-error" style="color: #f56c6c" v-if="type == 'danger'"></i>
            <i class="el-icon-info" style="color: #909399" v-if="type == 'info'"></i>
            <i
              class="el-icon-success"
              style="color: #67c23a"
              v-if="type == 'success'"
            ></i>
          </div>
          <div class="dialog-context" v-html="content"></div>
        </div>
        <div class="dialoag-footer" v-if="showCancelButton || showConfirmButton">
          <el-button v-if="showCancelButton" size="small" @click="doCancel">{{
            cancelButtonName
          }}</el-button>
          <el-button
            type="primary"
            v-if="showConfirmButton"
            size="small"
            style="margin-right: 10px"
            @click="doConfirm"
            >{{ confirmButtonName }}</el-button
          >
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import Vue from "vue";
export default {
  created() {
    this.zIndex = Vue.dialogZIndex;
  },
  props: {
    visible: {
      type: Boolean,
      isRequired: true,
    },
    title: {
      type: String,
      default: "提示",
    },
    content: {
      type: String,
    },
    showMask: {
      // 是否顯示遮罩
      type: Boolean,
      default: true,
    },
    clickMaskClose: {
      // 點擊遮罩是否關閉彈窗
      type: Boolean,
      default: true,
    },
    showCancelButton: {
      type: Boolean,
      default: true,
    },
    cancelButtonName: {
      type: String,
      default: "取消",
    },
    showConfirmButton: {
      type: Boolean,
      default: true,
    },
    confirmButtonName: {
      type: String,
      default: "確定",
    },
    showClose: {
      // 是否顯示右上角關閉按鈕
      type: Boolean,
      default: true,
    },
    width: {
      // 彈窗占屏幕寬度,默認60%
      type: String,
      default: "60%",
    },
    type: {
      // 提示類型,文案前的圖標會有所不同 success  warning  info  danger
      type: String,
    },
    beforeClose: {
      type: Function,
      default: (action, instance, done) => {},
    },
  },
  data() {
    return {
      zIndex: 1000,
    };
  },
  methods: {
    clickMask() {
      if (this.clickMaskClose && this.showMask) {
        this.beforeClose("close", this, this.done("close"));
      }
    },
    clickDialog() {},
    doCancel() {
      this.beforeClose("cancel", this, this.done("cancel"));
    },
    doConfirm() {
      this.beforeClose("confirm", this, this.done("confirm"));
    },
    doCloseBtn() {
      this.beforeClose("close", this, this.done("close"));
    },
    doClose() {
      this.visible = false;
    },
    done(action) {
      const fn = () => {
        if (action == "confirm") {
          this.$emit("confirm");
        } else if (action == "cancel") {
          this.$emit("cancel");
        }
        this.doClose();
      };
      return fn;
    },
  },
};
</script>
<style scoped lang="less">
.my-dialog-container {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  .mask {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: #000;
    opacity: 0.5;
  }
  .my-dialog-bg {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    overflow-y: auto;
    .my-dialog {
      margin: 0 auto;
      background: #fff;
      max-height: 50vh;
      overflow-y: auto;
      margin-top: 30vh;
      border-radius: 8px;
      .dialog-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 50px;
        .dialog-title {
          font-size: 18px;
          font-weight: bold;
          padding-left: 15px;
        }
        .close-btn {
          padding-right: 15px;
        }
      }
      .dialog-content {
        display: flex;
        text-align: left;
        padding: 10px 15px;
        font-size: 14px;
        align-items: center;
        .dialog-type-icon {
          font-size: 24px;
          padding-right: 10px;
        }
        .dialog-context {
        }
      }
      .dialoag-footer {
        display: flex;
        justify-content: flex-end;
        align-items: center;
        height: 50px;
      }
    }
  }
}
</style>

該組件提供了幾個props

屬性字段名是否必填默認值備注

彈窗顯示狀態(tài)

visible

彈窗標題

title

"提示"
內(nèi)容

content

支持html和文本
是否顯示遮罩

showMask

true

點擊遮罩是否關閉彈窗

clickMaskClose

true
是否顯示取消按鈕

showCancelButton

true
取消按鈕名稱

cancelButtonName

“取消”
是否顯示確定按鈕

showConfirmButton

true
確定按鈕名稱

confirmButtonName

“確定”

是否顯示右上角關閉按鈕

showClose

true
彈窗占屏幕寬度比例

width

60%支持字符串形式的值,會直接賦給width樣式
彈窗類型

type

success/warning/info/danger

關閉前回調(diào)

beforeClose

(action, instance, done) => {}

注意事項:

1. 彈窗、遮罩都是以fixed絕對定位,為了讓新彈窗遮蓋就彈窗,不顯示到一個平面,所以z-index不能寫死。

設置Vue的全局變量Vue.prototype.dialogZIndex,默認是1000,當創(chuàng)建新彈窗時,dialogZIndex + 3,新彈窗created生命周期函數(shù)中獲取最新的dialogZIndex,使用動態(tài)樣式的方式,設置給遮罩、彈窗體。

2. 由于有點擊遮罩關閉彈窗的功能,為了避免點擊彈窗事件冒泡到外層的遮罩,觸發(fā)關閉彈窗的動作,給彈窗dom綁定一個點擊事件,@click.stop="clickDialog",clickDialog是空方法,不處理。

3. 點擊確定、取消、關閉、遮罩觸發(fā)的關閉動作,都不直接修改visible屬性,而是調(diào)用了this.beforeClose(),該方法的第三個參數(shù)是this.done的執(zhí)行結果,可以看出,this.done返回了一個方法。當該方法執(zhí)行時,會判斷當前是何種方式觸發(fā)的關閉,并做相應處理,然后關閉彈窗。這是實現(xiàn)異步關閉彈窗的關鍵

2.封裝js調(diào)用

代碼如下:

// registerDialog.js
import Vue from "vue";
import MyDialog from "@/components/my-dialog.vue";

const DialogConstructor = Vue.extend(MyDialog);
const createModal = (options) => {
    return new Promise((resolve, reject) => {
        const instance = new DialogConstructor({
            propsData: {
                beforeClose: (action, ins, done) => {
                    done();
                },
                ...options,
            }
        });
        // 掛載到臨時DOM
        const container = document.createElement('div')
        document.body.appendChild(container)
        instance.$mount(container);
        // 手動打開彈窗
        instance.visible = true
        // 監(jiān)聽關閉事件
        instance.$on('update:visible', (val) => {
            if (!val) {
                setTimeout(() => {
                    instance.$destroy();
                    document.body.removeChild(container)
                }, 300)
            }
        });
        instance.$on('confirm', resolve)
        instance.$on('cancel', reject)
    });
}

const registerDialog = () => {
    Vue.prototype.$myConfirm = (options) => {
        // 彈窗層級累加,保證先彈的框在下面
        if (!Vue.dialogZIndex) {
            Vue.dialogZIndex = 1000;
        } else {
            Vue.dialogZIndex = Vue.dialogZIndex + 3;
        }
        return createModal(options);
    }
}

export default registerDialog;
// main.js 添加這兩句
import registerDialog from "@/components/registerDialog.js";
registerDialog();

在main.js中調(diào)用registerDialog方法,將js調(diào)用彈窗的方法$myConfirm,掛到Vue的原型對象上。

$myConfirm方法接受一個options對象,里面就是彈窗組件要求的props。調(diào)用該方法,首先修改Vue原型對象上的全局變量dialogZIndex,維護彈窗絕對定位的層級高度。然后調(diào)用了createModal方法,該方法會使用Vue.extend動態(tài)構造組件實例,并掛載到新創(chuàng)建的DOM節(jié)點,是整個實現(xiàn)的核心。

const DialogConstructor = Vue.extend(MyDialog);

registerDialog.js文件被main.js引用的時候,這句代碼被執(zhí)行了。

MyDialog是包含組件選項的對象,Vue.extend實際構建了彈窗組件的子類,該子類繼承了彈窗組件所有的屬性和方法。

createModal返回一個Promise,這是為了方便使用then和catch捕獲到確定和取消的事件。

在該方法中,實例化了上面用Vue.extend創(chuàng)建的彈窗子類,存在變量instance中,通過propsData將用戶參數(shù)傳給組件,并提供beforeClose方法的默認值,不做異步處理,直接調(diào)用done方法往下。創(chuàng)建一個div,插入到body中,然后是用instance.$mount()方法將彈窗組件掛載到這個div中。并手動設置彈窗顯示狀態(tài)為true,此時彈窗已經(jīng)打開。

另外,監(jiān)聽visible的值變化,當visible為false時,銷毀當前彈窗實例,并從body中移除創(chuàng)建的div。

使用事件訂閱監(jiān)聽到confirm和cancel事件,分別觸發(fā)Promise的resolve和reject。

3.頁面使用

代碼示例

this.$myConfirm({
   title: "梁家輝",
   content: "<div>我話講完,<strong style='color: red;'>誰贊成,誰反對?</strong></div>",
   type: "success",
   beforeClose: (action, instance, done) => {
      if (action == "confirm") {
         console.log("2秒后關閉");
         setTimeout(() => {
           done();
         }, 2000);
      } else {
         done();
      }
    },
}).then(() => {
   console.log("確認完畢");
}).catch(() => {
   console.log("取消完畢");
});

點擊確定后,會先打印出“2秒后關閉”,等待兩秒后關閉,點擊取消或者關閉按鈕,會直接關閉。

需要注意的是,如果要先異步處理,再關閉彈窗,要寫在beforeClose中。如果是關閉彈窗后執(zhí)行的邏輯,可以寫在then或者catch中。

總結 

到此這篇關于如何封裝一個可用js直接調(diào)用的彈窗組件的文章就介紹到這了,更多相關js直接調(diào)用彈窗組件封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論