vue使用Vue.extend創建全局toast組件實例

Vue.extend創建全局toast組件

src -> components -> Toast -> toast.vue

<template>
  <transition name="fades">
    <div class="Errormes"  v-if="show">{{txt}}</div>
  </transition>
</template>
 
<script>
export default {
  name: 'Toast',
  data () {
    return {
      txt: '',
      show: false
    }
  }
}
</script>
<style lang="less" scoped>
.fades-enter-active, .fades-leave-active {
  transition: opacity 0.5s;
}
.fades-enter, .fades-leave-active {
  opacity: 0;
}
/* 提示彈框 */
.Errormes {
  position: fixed;
  top: 40%;
  left: 50%;
  -webkit-transform: translate(-50%, -50%);
  transform: translate(-50%, -50%);
  padding: 20px 30px;
  background: rgba(0, 0, 0, 0.8);
  border-radius: 16px;
  color: #fff;
  font-size: 28px;
  z-index: 999999;
  max-width: 80%;
  height: auto;
  line-height: 60px;
  text-align: center;
}
</style>

src -> components -> Toast -> index.js

import Toast from './toast.vue'
 
const toast = {}
toast.install = (vue) => {
  const ToastClass = vue.extend(Toast)
  const instance = new ToastClass()
  instance.$mount(document.createElement('div'))
  document.body.appendChild(instance.$el)
 
  let t = null
  const ToastMain = {
    show (msg, seconds = 2000) {
      if (t) clearTimeout(t)
      instance.txt = msg
      instance.show = true
      t = setTimeout(() => {
        instance.show = false
      }, seconds)
    }
  }
  vue.prototype.$toast = ToastMain
}
 
export default toast

main.js

import Vue from 'vue'
import App from './App.vue'
import toast from '@/components/Toast/index'
 
Vue.use(toast)

使用

$toast.show(message)

關於vue.extend的理解應用

基本概念

Vue.extend( options )

使用基礎 Vue 構造器,創建一個“子類”。參數是一個包含組件選項的對象。

一般,我們會用 Vue.extend 接收一個組件對象來創建一個構造器,再利用創建的構造器 new 一個實例,並將這個實例掛載到一個元素上。

官網基本示例

<div id="mount-point"></div>
// 創建構造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 創建 Profile 實例,並掛載到一個元素上。
new Profile().$mount('#mount-point')

data 選項是特例,需要註意 – 在 Vue.extend() 中它必須是函數

結果如下:

<p>Walter White aka Heisenberg</p>

應用

Vue.extend 屬於 Vue 的全局 API,在實際業務開發中我們很少使用,因為相比常用的 Vue.component 寫法使用 extend 步驟要更加繁瑣一些。

但是在一些獨立組件開發場景中,例如要實現一個類似於 window.alert() 提示組件,要求像調用 JS 函數一樣調用它,這時候 Vue.extend + $mount 這對組合就是我們需要去關註的。

1、vue $mount 和 el的區別說明

在應用之前我們先瞭解一下2個東西 —— $mount 和 el,兩者在使用效果上沒有任何區別,都是為瞭將實例化後的vue掛載到指定的dom元素中。

如果在實例化vue的時候指定el,則該vue將會渲染在此el對應的dom中,反之,若沒有指定el,則vue實例會處於一種“未掛載”的狀態,此時可以通過$mount來手動執行掛載。

註:如果$mount沒有提供參數,模板將被渲染為文檔之外的的元素,並且你必須使用原生DOM API把它插入文檔中。

var MyComponent = Vue.extend({
 template: '<div>Hello!</div>'
})
 
// 創建並掛載到 #app (會替換 #app)
new MyComponent().$mount('#app')
 
// 同上
new MyComponent({ el: '#app' })
 
// 或者,在文檔之外渲染並且隨後掛載
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)

2、Vue.extend實現Loading插件($mount)

<div id="root">
    <button @click="showLoading">顯示Loading</button>
</div>
function Loading(msg) {
        // 創建構造器
        const Loading = Vue.extend({
          template: '<div id="loading-msg">{{ msg }}</div>',
          props: {
            msg: {
              type: String,
              default: '加載中'
            }
          },
          name: 'Loading'
        })
 
        // 創建掛載div
        const div = document.createElement('div')
        div.setAttribute('id', 'loading-div')
        document.body.append(div)
 
        // 創建實例並掛載到一個元素上
        new Loading().$mount('#loading-div')
 
        // 返回一個移除元素的function
        return () => {
          document.body.removeChild(document.getElementById('loading-div'))
        }
}
 
// 掛載到vue實例上
Vue.prototype.$loading = Loading
 
 new Vue({
     el: '#root',
     methods: {
        showLoading() {
            const hide = this.$loading('正在加載,請稍等...')
            setTimeout(() => {
              hide()
            }, 1500)
        }
     }
})

3、Vue.extend實現信息彈窗插件(el)

新建一個popBox.vue

<template>
  <div id="confirm" v-if='flag'>
    <div class="contents" >
      <div class="content-top">{{ text.title }}</div>
      <div class="content-center">{{ text.msg }}</div>
      <div class="content-bottom">
        <button @click='show' class="left">{{ text.btn.ok }}</button>
        <button @click='hide' class="right">{{ text.btn.no }}</button>
      </div>
    </div>
  </div>
</template>
 
<script>
 
export default {
  data () {
    return {
      flag: true,
      text: {
          title:'標題',
          msg: '這是一個信息彈出框組件',
          btn: {
              ok: '確定',
              no: '取消'
          }
      }
    }
  },
 
  methods: {
    show (){
      this.flag = false;
    },
 
    hide() {
      this.flag = false;
    }
  }
}
 
</script>

新建一個popBox.js

import Vue from 'vue'
import PopBox from './popBox.vue'
 
// Vue.extend返回一個實例創建的構造器,但實例構造器需要進行掛載到頁面中
let popBox = Vue.extend(PopBox)   
 
popBox.install = (vue, text) => {
      
        // 在body中動態創建一個div元素,之後此div將會替換成整個vue文件的內容
        // 此時的popBoxDom通俗講就是相當於是整個組件對象,通過對象調用屬性的方法來進行組件中數據的使用
        let popBoxDom = new popBox({
            el: document.createElement('div')
        })
 
        
        // 可以通過$el屬性來訪問創建的組件實例
        document.body.appendChild(popBoxDom.$el)
 
   
        // 將需要傳入的文本內容傳給組件實例
        popBoxDom.text = text;
 
        // 返回一個promise,進行異步操作,成功時返回,失敗時返回
        return new Promise((res, rej) => {     
            popBoxDom.show = () => {   
                res()   //正確時返回的操作
                popBoxDom.flag = false;
            }
 
            popBoxDom.hide = ()=>{
                rej()   //失敗時返回的操作
                popBoxDom.flag = false;
            }
        }
 
        vue.prototype.$popBox = popBox    
    })
}
 
// 將邏輯函數進行導出和暴露
export default popBox

頁面使用

import PopBox from './popBox.js'
 
Vue.use(popBOx);
 
 
this.$popBox({
      title:'標題',
      msg:'內容',
      btn:{ ok:'確定', no:'取消'}
}).then(()=>{
      console.log('ok')
}).catch(()=>{
      console.log('no')
})

其他

import toastCom from "./Toast";
 
const toast = {};
toast.install = vue => {
 const ToastCon = vue.extend(toastCom);
 const ins = new ToastCon();
 ins.$mount(document.createElement("div"));
 document.body.appendChild(ins.$el);
 console.log(ins.toast)
 vue.prototype.$toast = ins.toast;
};
 
 
 
const globalComponent = {
 install: function(Vue) {
   Vue.use(toast);
 }
};
 
export default globalComponent;

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: