vue.js

vue.js 開發實現全域性呼叫的MessageBox元件

79 / 100

vue.js 開發實現全域性呼叫的MessageBox元件(整合 PrimeVUE-Dialog 元件)

 

PrimeVUE 沒有提供全域性的 MessageBox ,在使用上總是要重覆寫 <Dialog....> ...</Dialog>,利用 vue.js 官方文件中的開發 Vue 外掛客制元件 來作一個全域性的 MessageBox。

 

  • 先建立 mseeageBox 元件模板

使用 PrimeVUE-Dialog 可以省掉很多 css 匹配的問題。這個模板是呈現 UI 操作畫面,主要的程式段在 48-56 行的 comfirm() 函數裡的 new Promise((resolve,reject)來針對按鈕: 確認 & 取消 作出相對應的 resolve & reject 。

<template>
  <transition name="msgbox-fade">
    <Dialog :visible.sync="visible" :style="{width: '450px'}" :modal="true">
      <template #header>      
        <h4>{{header}}</h4>
      </template>
      <div class="confirmation-content">
        <i :class="['pi p-mr-1',icon]" style="font-size: 2.5rem" />
        <h5>{{content}}</h5>
      </div>
      <template #footer>
        <Button :label="cancelBtnText" class="p-button-danger p-button-sm" icon="pi pi-times" 
          @click="handleAction('cancel')" v-if="showCancelButton" />
        <Button :label="confirmBtnText" class="p-button-success p-button-sm" icon="pi pi-check" @click="handleAction('confirm')"/>
      </template>
    </Dialog>
  </transition>
</template>

<script>
import i18n from '../../i18n'

let typeMap = {
  alert: 'pi-info-circle',
  info: 'pi-exclamation-triangle',
  confirm: 'pi-question-circle',
};

export default {
  props:{
    visible:{
      type: Boolean,
      default: false
    },
  },
  methods:{
    handleAction(action){
      this.visible = false;
      
      if(action==='confirm') {  // 確認時, 將 promise 設為 resolve 狀態
        this.resolve('confirm');
      }
      if (action==='cancel') { // 取消時, 將 promise 設為 reject 狀態
        this.reject('cancel');
      }
    },
    // 顯示對話框, 對創建 promise 物件    
    confirm(){
      this.visible = true;
      this.promise = new Promise((resolve,reject) => {
          this.resolve = resolve;
          this.reject = reject;
      });
      // 返回 promise 物件
      return this.promise;
    }
  },
  computed:{
    cancelBtnText(){
      return i18n.t("CANCEL")
    },
    confirmBtnText(){
      return i18n.t("CONFIRM")
    },
    icon() {
      const { type, iconClass } = this;      
      return iconClass || (type && typeMap[type] ? `${ typeMap[type] }` : `${ typeMap['confirm'] }`);
    },
    header() {
      const {type, headerText} = this;
      let txt = '';
      if (headerText){
        return headerText;
      }
      switch (type) {
        case 'info':
          txt = i18n.t("MsgBox.INFO");
          break;      
        case 'alert':
          txt = i18n.t("MsgBox.ALERT");
          break;
        case 'confirm':
          txt = i18n.t("MsgBox.CONFIRM");
          break;
        default:
          txt = i18n.t("MsgBox.CONFIRM");
          break;
      }
      return txt ;
    },
    content() {
      const {contentText} = this;
      return contentText || i18n.t("MsgBox.CONTENT");
    }
  },
  data(){
    return {
      resolve: '',
      reject: '',
      promise: '', //保存 promise
      type: '',
      iconClass: '',
      headerText: '',
      contentText: '',
      showCancelButton: true,
    }
  },
}
</script>
<style scoped lang="scss">
.confirmation-content {
 display: flex;
 align-items: center;
 justify-content: center;
}
</style>

 

  • 給元件新增全域性功能

vue.js 官方文件中有開發外掛的介紹。利用 vue 的 install 方法, 將客制的 插件 msgboxVue 加入,展示的程式碼如下:

import msgboxVue from './index.vue';

// 定義插件物件
const MessageBox = {}
// 利用 vue 的 install 方法, 將客制的 vue 插件加入
MessageBox.install = function (Vue) {  
  const MessageBoxInstance = Vue.extend(msgboxVue);
  let currentMsg;
  const initInstance = () => {
    // 實體化 vue 物件    
    currentMsg = new MessageBoxInstance();
    let msgBoxEl = currentMsg.$mount().$el;
    document.body.appendChild(msgBoxEl);
  };
  // 在Vue的原型上加入實例方法,以便全局可以呼叫使用
  Vue.prototype.$msgBox = {
    confirm (options) {      
      if (!currentMsg) {
        initInstance();
      }
      if (typeof options === 'string') {
        currentMsg.content = options;
      } else if (typeof options === 'object') {
        Object.assign(currentMsg, options);
      }
      return currentMsg.confirm()
        .then(val => {
          currentMsg = null;
          return Promise.resolve(val);
        })
        .catch(err => {
          currentMsg = null;
          return Promise.reject(err);
        });
    }
  };
};
export default MessageBox;

 

在 main.js 中註冊 MessageBox 可供全域性使用

/*main.js*/

import Vue from 'vue'
import MessageBox from './components/MessageBox'

Vue.use(MessageBox)

 

在每一個 Vue 的程式頁面方法中,就可以直接呼叫使用了

methods: {
   revertEvent() {
      const { insertRecords, removeRecords, updateRecords } = this.$refs.xTable.getRecordset()
      let count = updateRecords.length + removeRecords.length + insertRecords.length;
      if (count>0) {
        this.$msgBox.confirm({
          contentText:'資料還原時, 編輯中的資料會遺失?!'
        }).then(()=>{            
            this.$refs.xTable.revertData()
            this.showResMsg('success', count + '筆資料已回覆');
        }).catch(()=>{
          this.showResMsg('info', count + '筆資料未回復');            
        })
      } else {
        this.showResMsg('success','資料未有修改');
      }
      
    }
}

vue-messageBox

 

參考:

vue.js開發實現全域性呼叫的MessageBox元件例項程式碼