写一个函数调用就能唤起的弹窗

210 阅读2分钟

起源

闲着无聊该干嘛, 当然是造轮子玩. 写代码的时候, 要时常归纳总结, 什么是合适的解决方式, 什么是通用的逻辑很重要. 在 Vue 里,弹窗这个功能一般由第三方的组件库实现, 通常来说, 要使用一个弹窗, 我们需要写出如下代码

<template>
    <!-- antdv -->
    <a-modal>
        <div class="content"></div>
    </a-modal>
</template>

基本上, 都需要在模板内定义好弹窗的内容, 用起来总是觉得不顺手,所以想着自己实现一个不需要在 template 定义的弹窗插件

需求

先讲需求,从使用者的角度思考,自己想要的到底是怎样的调用方式

import Content from './Content.vue';

export default {
    mounted() {
        this.popup({
            component: Content,
            props: {},
            onclose: () => {},
        })
    }
}

导入弹窗的内容, 通过函数调用, 传入被弹出的内容组件, 组件的props参数, 以及关闭弹窗时的回调函数, 大致上这些功能可以满足大部分使用场景的需求 有了需求和调用形式, 就如同有了解题的突破口, 有些新手觉得前端难学, 其实就是难在边界情况, 新人很难掌摸清技术的边界, 不能确定哪些功能能做, 哪些功能不能做, 这也是一个熟能生巧的过程, 在经历大量代码编写后, 自然就不会再有这样的问题

切入点

  • 调用时使用的是 this 调用,显然需要挂载到 Vue的原型下
  • 为了渲染组件, 需要用到 Vue 来构造一个组件, 并挂载到指定的 dom
  • 为了不丢失上下文, 可将 this 作为 parent 传入子组件
  • 自定义一些 css 样式, 让弹窗看上去确实像弹窗
const state = {
   Vue: null,
   store: null,
   router: null
}
const plugin = {
   popup(options) {
      const { component } = options;
      const div = document.createElement('div');
      div.innerHTML = `<div class="popup-bg"></div><div class="popup-content"></div>`
      div.className = 'popup';
      const basicStyle = {
         position: 'absolute',
         width: '100%',
         height: '100%',
            left: 0,
            top: 0
      }
      Object.assign(div.style, basicStyle, {
         display: 'flex',
         justifyContent: 'center',
         alignItems: 'center'
      });
      const bg = div.querySelector('.popup-bg')
      Object.assign(bg.style, basicStyle, {
         backgroundColor: 'rgba(0,0,0,0.2)'
      });
      document.body.appendChild(div);
      if (options.props) {
         options.props.parent = this;
      } else {
         options.props = {
            parent: this
         }
      }
      const content = div.querySelector('.popup-content')
      new state.Vue({
         store: state.store,
         router: state.router,
         render(h) {
            return h(component, {
               props: options.props,
            })
         }
      }).$mount(content)
   },
   install (Vue, options = {}) {
      state.Vue = Vue;
      state.store = options.store;
      state.router = options.router;
      Vue.prototype.$popup = this.popup;
   }
}
export default plugin

小结

上述示例代码只是一个极其基础的弹窗功能, 简陋到无法正常使用, 选择的vue版本也是已经过时了的Vue2, 但是一法通则万法通, 并且已经初具雏形, 可以根据自己的需求进行增删, 似乎又是一个没什么用的玩具