✨vue封裝一個全局toast和confirm(Vue.extend)

⚠️ Vue.extend是什麼?javascript

👉 extend建立的是一個組件構造器,而不是一個具體的組件實例,須要經過Vue.components註冊css

🚀先來封裝一個toast組件

toast.vuehtml

<template>
  <transition :name="fadeIn">
    <div class="alertBox" v-show="show">
      <div class="alert-mask" v-show="isShowMask"></div>
      <transition :name="translate">
        <div class="box" :class="position" v-show="show">
          <p>{{text}}</p>
        </div>
      </transition>
    </div>
  </transition>
</template>
 
<script> export default { data() { return { } }, props: { show: { // 是否顯示此toast default: false }, text: { // 提醒文字 default: 'loading' }, position: { // 提醒容器位置 default: 'center' //這裏應該是middle 我沒有改動畫 因此暫時不用 }, isShowMask: { // 是否顯示遮罩層 default: false }, time: { // 顯示時間 default: 1500 }, transition: { // 是否開啓動畫 default: true } }, mounted() { // 時間控制 // setTimeout(() => { // this.show = false // }, this.time) }, computed: { translate() { // 根據props,生成相對應的動畫 if (!this.transition) { return '' } else { if (this.position === 'top') { return 'translate-top' } else if (this.position === 'middle') { return 'translate-middle' } else if (this.position === 'bottom') { return 'translate-bottom' } } }, fadeIn() { // 同上 if (!this.transition) { return '' } else { return 'fadeIn' } }, } } </script>
 
<style lang='scss'> .box { position: fixed; top: 50%; left: 50%; transform: translate(-50%,-50%); min-width: 130px; background: rgba(0, 0, 0, 0.5); text-align: center; color: #fff; z-index: 5000; color: #fff; padding: 20px 30px; border-radius: 10px; word-wrap: normal ; p { display: inline-block; text-align: left; } } .box.top { top: 50px; margin-top: 150px; } .box.center { top: 50%; margin-top: -100px; } .box.bottom { top: auto; bottom: 50px; margin-top: 0; } .alert-mask { position: fixed; left: 0; top: 0; bottom: 0; right: 0; background: rgba(0, 0, 0, 0.5); z-index: 4999; } .fadeIn-enter-active, .fadeIn-leave-active { transition: opacity 0.3s; } .fadeIn-enter, .fadeIn-leave-active { opacity: 0; } .translate-top-enter-active, .translate-top-leave-active { transition: all 0.3s cubic-bezier(0.36, 0.66, 0.04, 1); } .translate-top-enter, .translate-top-leave-active { transform: translateY(-50%); opacity: 0; } .translate-middle-enter-active, .translate-middle-leave-active { transition: all 0.3s cubic-bezier(0.36, 0.66, 0.04, 1); } .translate-middle-enter, .translate-middle-leave-active { transform: translateY(80%); opacity: 0; } .translate-bottom-enter-active, .translate-bottom-leave-active { transition: all 0.3s cubic-bezier(0.36, 0.66, 0.04, 1); } .translate-bottom-enter, .translate-bottom-leave-active { transform: translateY(100%); opacity: 0; } </style>
複製代碼

toast.jsvue

import Alert from './toast.vue';   
var Toast = {} // 定義插件對象
Toast.install = function (Vue, options) { // vue的install方法,用於定義vue插件
 // 若是toast還在,則再也不執行
 if(document.getElementsByClassName('alertBox').length){ 
   return
 }
 let toastTpl = Vue.extend(Alert) // 建立vue構造器
 // el:提供一個在頁面上已存在的DOM元素做爲Vue實例的掛載目標。能夠是css選擇器,也能夠是HTMLElement實例。
 // 在實例掛載以後,能夠經過$vm.$el訪問。
 // 若是這個選項在實例化時有用到,實例將當即進入編譯過程。不然,須要顯示調用vm.$mount()手動開啓編譯(以下)
 // 提供的元素只能做爲掛載點。全部的掛載元素會被vue生成的dom替換。所以不能掛載在頂級元素(html, body)上
 // let $vm = new toastTpl({
 // el: document.createElement('div')
 // })
 let $vm = new toastTpl() // 實例化vue實例
 // 此處使用$mount來手動開啓編譯。用$el來訪問元素,並插入到body中
 let tpl = $vm.$mount().$el
 document.body.appendChild(tpl)
 
 Vue.prototype.$toast = { // 在Vue的原型上添加實例方法,以全局調用
  show(options) { // 控制toast顯示的方法
   if (typeof options === 'string') { // 對參數進行判斷
    $vm.text = options // 傳入props
   }
   else if (typeof options === 'object') {
    Object.assign($vm, options) // 合併參數與實例 
   }
   $vm.show = true // 顯示toast (防止每次彈窗建立一次新的定時器)
    setTimeout(()=>{
       $vm.show = false
     },$vm.time)    //消失時間
  },
  hide() { // 控制toast隱藏的方法
   $vm.show = false
  }
 }
}
export default Toast;// 導出Toast(注意:此處不能用module exports導出,在一個文件中,不能同時使用require方式引入,而用module exports導出,兩種方式不能混用)

複製代碼

🌰使用方法

main.jsjava

import Toast from './components/toast/toast';
Vue.use(Toast);   //封裝的messagebox組件 經過this調用
複製代碼

home.vue 具體使用promise

this.$toast.show({
    text: '複製成功',
    time:'2000', //顯示的時間
})
複製代碼

🚀 再來個confirm彈框

由於框架的風格不知足於項目的風格,因此有時候須要本身定製一個bash

👉app

messageBox.vue框架

<template>
  <div class="dialog_views" v-show="isShowMessageBox" @touchmove.prevent>
    <div class="UImask" @click="cancel"></div>
    <transition name="confirm-fade">
      <div class="UIdialog" v-show="isShowMessageBox">
        <div class="UIdialog_hd">{{title}}</div>
        <div class="UIdialog_bd">
          <slot>{{content}}</slot>
        </div>
        <div :class="[ isShowCancelBtn ? 'UIdialog_ft' : 'UIdialog_ft UIdialog_ft_one']">
          <span v-if="isShowCancelBtn" class="UIdialog_btn" @click="cancel">{{cancelVal}}</span>
          <span v-if="isShowConfimrBtn" class="UIdialog_btn" @click="confirm">{{confirmVal}}</span>
        </div>

      </div>
    </transition>
  </div>

</template>

<script> export default { components: { }, data() { return { isShowMessageBox: false, resolve: '', reject: '', promise: '', // 保存promise對象 }; }, props: { isShowConfimrBtn: { type: Boolean, default: true }, content: { type: String, default: '這是彈框內容' }, isShowCancelBtn: { //是否展現取消按鈕 type: Boolean, default: true }, title: { //標題 type: String, default: '提示', }, confirmVal: { type: String, //確認文字 default: '肯定' }, cancelVal: { //取消文字 type: String, default: '取消' }, maskHide: { type: Boolean, //是否能夠點擊蒙層關閉 default: true } }, methods: { // 肯定,將promise判定爲resolve狀態 confirm() { this.isShowMessageBox = false; this.resolve('confirm'); this.remove(); }, // 取消,將promise判定爲reject狀態 cancel() { this.isShowMessageBox = false; this.reject('cancel'); this.remove(); }, // 彈出messageBox,並建立promise對象 showMsgBox() { this.isShowMessageBox = true; this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); // 返回promise對象 return this.promise; }, remove() { setTimeout(() => { this.destroy(); }, 100); }, destroy() { this.$destroy(); document.body.removeChild(this.$el); }, } }; </script>
<style lang='scss' scoped> .UImask { position: fixed; z-index: 999; top: 0; right: 0; left: 0; bottom: 0; background: rgba(0, 0, 0, 0.6); } .UIdialog { position: fixed; z-index: 999; width: 80%; max-width: 400px; display: table; z-index: 5000; top: 0; right: 0; bottom: 0; left: 0; margin: auto; transition: opacity 0.3s, transform 0.4s; text-align: center; border-radius: 8px; overflow: hidden; background: #fff; padding: 30px 40px; } .UIdialog_hd { font-weight: bold; font-size: 34px; letter-spacing: 1px; } .UIdialog_bd { margin: 40px 0; text-align: center; font-size: 24px; slot, p { display: inline-block; text-align: left; } } .UIdialog_ft { position: relative; font-size: 28px; color: #fff; display: flex; justify-content: center; align-items: center; justify-content: space-between; margin: 0 20px; margin-bottom: -5px; padding-top: 15px; } .UIdialog_btn { display: block; text-decoration: none; position: relative; display: block; background-color: #000; border-radius: 40px; padding: 12px 45px; } .UIdialog_ft_one { text-align: center; justify-content: center; } /* 進入和出去的動畫 */ .confirm-fade-enter-active { animation: bounce-in 0.5s; } .confirm-fade-leave-active { animation: bounce-in 0.5s reverse; } .confirm-fade-enter, .confirm-fade-leave-to { opacity: 0; } @keyframes bounce-in { 0% { transform: scale(0); } 50% { transform: scale(1.2); } 100% { transform: scale(1); } } } </style>

複製代碼

messageBox.jsdom

import msgboxVue from './messageBox.vue';    
// 定義插件對象
const MessageBox = {};
// vue的install方法,用於定義vue插件
MessageBox.install = function (Vue, options) {
  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 = {
    showMsgBox (options) {
      if (!currentMsg) {
        initInstance();
      }
      if (typeof options === 'string') {
        currentMsg.content = options;
      } else if (typeof options === 'object') {
        Object.assign(currentMsg, options);
      }
// Object.assign方法只會拷貝源對象自身的而且可枚舉的屬性到目標對象
      return currentMsg.showMsgBox()
        .then(val => {
          currentMsg = null;
          return Promise.resolve(val);
        })
        .catch(err => {
          currentMsg = null;
          return Promise.reject(err);
        });
    }
  };
};
export default MessageBox;
複製代碼

🌰使用方法

main.js

import MessageBox from './components/messageBox/messageBox';
Vue.use(MessageBox);   //封裝的messagebox組件 經過this調用
複製代碼

home.vue 具體使用

this.$msgBox.showMsgBox({
        title: '提示',
        content: '肯定要刪除嗎',
      }).then(async (val) => {
        // ...        
        console.log('確認')
      }).catch(() => {
        // ...
        console.log('取消')
      });
複製代碼

🙈 這是我寫項目中須要封裝一個彈窗,樣式能夠自行修改

相關文章
相關標籤/搜索