亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

一、開發(fā)思路

1. 先封裝一個(gè)正常的彈窗組件

2. 使用Vue.extend動(dòng)態(tài)構(gòu)造組件實(shí)例,并掛載到新創(chuàng)建的DOM節(jié)點(diǎn)

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

二、開發(fā)過(guò)程

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"
      >
        <!-- 這里添加一個(gè)stop的事件,在點(diǎn)擊彈窗區(qū)域時(shí),阻止向上冒泡觸發(fā)clickMask,把彈窗關(guān)掉了 -->
        <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: {
      // 點(diǎn)擊遮罩是否關(guān)閉彈窗
      type: Boolean,
      default: true,
    },
    showCancelButton: {
      type: Boolean,
      default: true,
    },
    cancelButtonName: {
      type: String,
      default: "取消",
    },
    showConfirmButton: {
      type: Boolean,
      default: true,
    },
    confirmButtonName: {
      type: String,
      default: "確定",
    },
    showClose: {
      // 是否顯示右上角關(guān)閉按鈕
      type: Boolean,
      default: true,
    },
    width: {
      // 彈窗占屏幕寬度,默認(rèn)60%
      type: String,
      default: "60%",
    },
    type: {
      // 提示類型,文案前的圖標(biāo)會(huì)有所不同 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>

該組件提供了幾個(gè)props

屬性字段名是否必填默認(rèn)值備注

彈窗顯示狀態(tài)

visible

彈窗標(biāo)題

title

"提示"
內(nèi)容

content

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

showMask

true

點(diǎn)擊遮罩是否關(guān)閉彈窗

clickMaskClose

true
是否顯示取消按鈕

showCancelButton

true
取消按鈕名稱

cancelButtonName

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

showConfirmButton

true
確定按鈕名稱

confirmButtonName

“確定”

是否顯示右上角關(guān)閉按鈕

showClose

true
彈窗占屏幕寬度比例

width

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

type

success/warning/info/danger

關(guān)閉前回調(diào)

beforeClose

(action, instance, done) => {}

注意事項(xiàng):

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

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

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

3. 點(diǎn)擊確定、取消、關(guān)閉、遮罩觸發(fā)的關(guān)閉動(dòng)作,都不直接修改visible屬性,而是調(diào)用了this.beforeClose(),該方法的第三個(gè)參數(shù)是this.done的執(zhí)行結(jié)果,可以看出,this.done返回了一個(gè)方法。當(dāng)該方法執(zhí)行時(shí),會(huì)判斷當(dāng)前是何種方式觸發(fā)的關(guān)閉,并做相應(yīng)處理,然后關(guān)閉彈窗。這是實(shí)現(xiàn)異步關(guān)閉彈窗的關(guā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,
            }
        });
        // 掛載到臨時(shí)DOM
        const container = document.createElement('div')
        document.body.appendChild(container)
        instance.$mount(container);
        // 手動(dòng)打開彈窗
        instance.visible = true
        // 監(jiān)聽關(guā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) => {
        // 彈窗層級(jí)累加,保證先彈的框在下面
        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的原型對(duì)象上。

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

const DialogConstructor = Vue.extend(MyDialog);

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

MyDialog是包含組件選項(xiàng)的對(duì)象,Vue.extend實(shí)際構(gòu)建了彈窗組件的子類,該子類繼承了彈窗組件所有的屬性和方法。

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

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

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

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

3.頁(yè)面使用

代碼示例

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

點(diǎn)擊確定后,會(huì)先打印出“2秒后關(guān)閉”,等待兩秒后關(guān)閉,點(diǎn)擊取消或者關(guān)閉按鈕,會(huì)直接關(guān)閉。

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

總結(jié) 

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

相關(guān)文章

最新評(píng)論