vue使用Vue.extend创建全局toast组件实例

2023-03-04 15:06:12

目录Vue.extend创建全局toast组件关于vue.extend的理解应用基本概念官网基本示例应用总结Vue.extend创建全局toast组件src-components-Toast...

目录
vue.extend创建全局toast组件
关于vue.extend的理解应用
基本概念
官网基本示例
应用
总结

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;

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。