异步组件之动态弹窗

简介

在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。
弹窗几乎是项目中比不可少的一部分,它就是经典的异步组件需求。
同时,它也是动态的,需要的时候通过方法来调用执行。

调用示例:

import importAsyncComponent from '@/util.component'
const DialogComp = importAsyncComponent('./components/DialogComp.vue')

// 选项
const options = {
  props: {}
  events: {}
}
this.$dialog(DialogComp, options).then(() => {
  // todo something
})

准备

Vue 官方也提供了相关的方法来实现此功能:

// Vue2
const AsyncComp = () => import('./components/MyComponent.vue')


// Vue3
import { defineAsyncComponent } from 'vue'

const AsyncComp = defineAsyncComponent(() =>
  import('./components/MyComponent.vue')
)

[import] 方法会返回一个Promise, 因此可以在事件钩子里进行拦截,增加loading效果以及出错提示。

安装nprogress

npm install --save nprogress

封装引用方法

importAsyncComponent函数统一对引入组件进行处理
以ant-design-vue组件库来做示例

// util.component.js
import { notification } from 'element-plus';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';

NProgress.configure({     
  easing: 'ease',  // 动画方式    
  speed: 500,  // 递增进度条的速度    
  showSpinner: false, // 是否显示加载ico    
  trickleSpeed: 200, // 自动递增间隔    
  minimum: 0.3 // 初始化时的最小百分比
})

function importAsyncComponent(path) {
  NProgress.start()
  return import(path).then(res => {
    return res
  })
  .catch(err => {
    notification.open({
      message: '提示',
      description: '加载失败,请检查你的网络...'
    })
  })
  .finally(() => {
    NProgress.done()
  })
}

export default importAsyncComponent

封装弹窗函数

上一步已经有了加载组件的函数,现在就差实现$dialog函数了

// util.dialog.js
import Vue from 'vue'

/**
 * 创建弹窗
 * @params {Object|Promise} component 弹窗组件
 * @params {Object} options 选项
 */
function createDialogComp(component, options) {
  const { props = {}, events = {} } = options || {}
  const comp = Vue.extend(component, {
    propsData: props,
    watch: {
      // 预设弹出显隐属性
      visible(nv) {
        if(!nv) {
          // 监听关闭时销毁
          this.destroy()
        }
      }
    },
    methods: {
      destroy() {
        this.$destroy()
        document.body.removeChild(this.$el)
      }
    }
  })

  const vm = new Vue(comp).$mount()
  
  // 注册事件
  Object.entries(events).forEach(([name, event]) => {
    vm.$on(name, event) 
  })

  // 挂载
  document.body.appendChild(vm.$el)

  // 打开
  vm.$nextTick(() => {
    vm.open() // 通过调用弹窗组件预设的open方法开弹出
  })

  return vm
}

export default {
  install(Vue) {
    Vue.prototype.$dialog = function dialog(component, options) {
      if(component instanceof Promise) {
        return component.then(res => {
          return createDialogComp(res, options)
        })
      }
      return createDialogComp(component, options)
    }
  }
}

绑定全局

弹窗开发完成,如何绑定全局使用?

// main.js
import Vue from 'vue'
import dialog from '@/util.dialog.js'

Vue.use(dialog)

编写弹窗

至此,弹窗支撑逻辑已经全部完成,下面需要编写一个弹窗组件。
以element UI组件库为例:

<template>
  <div>
    <el-modal :visible="visible" title="My Dialog">
      <p>Some contents...</p>
      <p>Some contents...</p>
      <p>Some contents...</p>
    </el-modal>
  </div>
</template>
<script>


export default {
  data() {
    return {
      visible: false // 该属性控制弹窗弹出
    }
  },
  methods: {
    open() {
      this.visible = true
    },
    close() {
      this.visible = false
    }
  }
}
</script>

调用

最后,在父级组件里动态的加载上一步的弹窗组件。

<template>
  <div>
    <el-button type="primary" @click="openDialog">Open Dialog</el-button>
  </div>
</template>
<script>
import importAsyncComponent from '@/utils/util.component'
const MyDialog = importAsyncComponent('./components/MyDialog.vue')

export default {
  data() {
    return {
    }
  },
  methods: {
    openDialog() {
      // 选项
      const options = {
        props: {}
        events: {}
      }
      this.$dialog(MyDialog, options).then(() => {
        // todo something
      })
    }
  }
}
</script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值