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)
使用
关于vue.extend的理解应用
基本概念
使用基础 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;
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持w3xue。