最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

一、開發(fā)思路

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

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

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

二、開發(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的事件,在點(diǎn)擊彈窗區(qū)域時,阻止向上冒泡觸發(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)會有所不同 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

屬性字段名是否必填默認(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%支持字符串形式的值,會直接賦給width樣式
彈窗類型

type

success/warning/info/danger

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

beforeClose

(action, instance, done) => {}

注意事項(xiàng):

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

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

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

3. 點(diǎn)擊確定、取消、關(guān)閉、遮罩觸發(fā)的關(guān)閉動作,都不直接修改visible屬性,而是調(diào)用了this.beforeClose(),該方法的第三個參數(shù)是this.done的執(zhí)行結(jié)果,可以看出,this.done返回了一個方法。當(dāng)該方法執(zhí)行時,會判斷當(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,
            }
        });
        // 掛載到臨時DOM
        const container = document.createElement('div')
        document.body.appendChild(container)
        instance.$mount(container);
        // 手動打開彈窗
        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) => {
        // 彈窗層級累加,保證先彈的框在下面
        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,維護(hù)彈窗絕對定位的層級高度。然后調(diào)用了createModal方法,該方法會使用Vue.extend動態(tài)構(gòu)造組件實(shí)例,并掛載到新創(chuàng)建的DOM節(jié)點(diǎn),是整個實(shí)現(xiàn)的核心。

const DialogConstructor = Vue.extend(MyDialog);

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

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

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

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

另外,監(jiān)聽visible的值變化,當(dāng)visible為false時,銷毀當(dāng)前彈窗實(shí)例,并從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秒后關(guān)閉");
         setTimeout(() => {
           done();
         }, 2000);
      } else {
         done();
      }
    },
}).then(() => {
   console.log("確認(rèn)完畢");
}).catch(() => {
   console.log("取消完畢");
});

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

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

總結(jié) 

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

相關(guān)文章

  • JavaScript輸出為[object?Object]問題的解決辦法

    JavaScript輸出為[object?Object]問題的解決辦法

    平時我們在接收后端返回的json對象通常是一個字符串類型的object,所以一般我們要對這個object進(jìn)行類型轉(zhuǎn)化后,我們才能使用object里面的數(shù)據(jù),這篇文章主要給大家介紹了關(guān)于JavaScript輸出為[object?Object]問題的解決辦法,需要的朋友可以參考下
    2023-11-11
  • 淺談JavaScript異步編程

    淺談JavaScript異步編程

    本文主要介紹了javascript的異步編程相關(guān)知識。具有一定的參考價值,下面跟著小編一起來看下吧
    2017-01-01
  • js實(shí)現(xiàn)按鈕進(jìn)行某行上移下移

    js實(shí)現(xiàn)按鈕進(jìn)行某行上移下移

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)按鈕進(jìn)行某行上移下移,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • BootStrap智能表單實(shí)戰(zhàn)系列(四)表單布局介紹

    BootStrap智能表單實(shí)戰(zhàn)系列(四)表單布局介紹

    這篇文章主要介紹了BootStrap智能表單實(shí)戰(zhàn)系列(四)表單布局介紹,表單布局分為自動布局和自定義布局兩種,本文通過代碼給大家介紹,介紹的非常詳細(xì),具有參考借鑒價值,感興趣的朋友一起學(xué)習(xí)吧
    2016-06-06
  • JavaScript中Array.map()的使用與技巧分享(附實(shí)際應(yīng)用代碼)

    JavaScript中Array.map()的使用與技巧分享(附實(shí)際應(yīng)用代碼)

    Array.map()適合需要返回新數(shù)組、進(jìn)行鏈?zhǔn)秸{(diào)用或不修改原數(shù)組的場景,它與forEach()的區(qū)別在于有返回值,基本語法中,callback函數(shù)處理每個元素并返回新值,本文介紹了JavaScript中Array.map()的使用與技巧分享(附實(shí)際應(yīng)用代碼),需要的朋友可以參考下
    2025-02-02
  • js二維數(shù)組排序的簡單示例代碼

    js二維數(shù)組排序的簡單示例代碼

    本篇主要是對js二維數(shù)組排序的簡單示例代碼進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01
  • 鼠標(biāo)事件的screenY,pageY,clientY,layerY,offsetY屬性詳解

    鼠標(biāo)事件的screenY,pageY,clientY,layerY,offsetY屬性詳解

    這篇文章主要介紹了鼠標(biāo)事件的screenY,pageY,clientY,layerY,offsetY屬性詳解,需要的朋友可以參考下
    2015-03-03
  • JavaScript函數(shù)柯里化實(shí)現(xiàn)原理及過程

    JavaScript函數(shù)柯里化實(shí)現(xiàn)原理及過程

    這篇文章主要介紹了JavaScript函數(shù)柯里化實(shí)現(xiàn)原理及過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-12-12
  • file模式訪問網(wǎng)頁時iframe高度自適應(yīng)解決方案

    file模式訪問網(wǎng)頁時iframe高度自適應(yīng)解決方案

    最近做到iframe的高度自適應(yīng)這個問題;發(fā)現(xiàn)自己做的網(wǎng)頁是通過file方式訪問的,將網(wǎng)頁代碼放到apache下通過http協(xié)議訪問,在iframe加載的時候調(diào)用如下js方法:果然網(wǎng)頁高度能夠自適應(yīng)(對于其他方案應(yīng)該也有效果,我沒有注意去嘗試)感興趣的朋友可以了解下
    2013-01-01
  • JS+CSS實(shí)現(xiàn)彈出全屏灰黑色透明遮罩效果的方法

    JS+CSS實(shí)現(xiàn)彈出全屏灰黑色透明遮罩效果的方法

    這篇文章主要介紹了JS+CSS實(shí)現(xiàn)彈出全屏灰黑色透明遮罩效果的方法,詳細(xì)分析了彈出遮罩層效果的實(shí)現(xiàn)方法以及完整的實(shí)例代碼,需要的朋友可以參考下
    2014-12-12

最新評論

松阳县| 长沙市| 依安县| 伊春市| 清水河县| 德令哈市| 漳浦县| 于都县| 石林| 米脂县| 滨海县| 冕宁县| 天气| 博湖县| 来宾市| 乌海市| 中江县| 台北市| 农安县| 永川市| 疏附县| 正安县| 城市| 吉林省| 林口县| 潮州市| 东山县| 罗江县| 黄平县| 赤壁市| 武平县| 团风县| 长丰县| 聊城市| 东辽县| 垣曲县| 利辛县| 江城| 八宿县| 红原县| 钦州市|