从0开始手写一个Vue消息弹窗组件

前言

近期闲来无事,就想折腾一点东西,无奈技术水平太低,做不了什么高深复杂的项目,所以还是先从简单的做起吧。平时我们做项目的时候或多或少都会用到一些组件库,比如element、muse之类的,所以这次我想自己手动写一个组件,封装成一个包,可以暴露到外部去调用。

效果预览

废话不多说,这次写的是一个Vue的消息弹窗组建,借鉴了element的message组件,大家可以去看一看element的源码,里面一些组件的实现方式很巧妙,非常值得去学习。话不多说,先来看看最终的实现效果:

不同主题

关闭按钮
不同位置

代码

第一步应该是写一个模板:


可以看到,html内容是很简单的,主要是几个标签和一些props,还有几个事件,然后我们再来看js:


可以看到组件的代码逻辑也是非常简单的,props的处理我就不多细说了,可能每一个人的需求都一样。重点要讲一讲的是组件的创建和销毁过程。在组件挂载后,组件会调用startTimer方法生成一个定时器,按照duration指定的时间后调用close方法,close方法会设定data的closed为true,visible监听到closed变为true后就变为false,所以根据v-show这个指令,组件的display样式属性就会变成none。最后Vue官方内置的过渡组件transition会调用一系列钩子函数,我们直接在afterLeave这个钩子上销毁组件和清除dom。看到这里,可能有同学会有疑问了?为啥要这样销毁组件啊,直接用一个prop控制组件显示不就可以了吗?其实对于一般的组件我们是没必要弄成这样,但是我们得思考一下消息弹窗的使用场景啊。一般情况下,消息弹窗都是在完成了某种操作后,弹出来告诉用户操作成功与否,所以我们通常用js控制消息弹窗显示。因此,我们的消息弹窗组件不仅仅是声明式的,更应该是命令式的,直接用js控制显示与否。

很多同学应该都使用过element,element在全局引入的时候会向vue上挂载一个message的方法,一般我们都是this.$message这样来操作的,我的目标也是做成这样子。

import Vue from 'vue'
import Message from './Message.vue'

const messageConstructor = Vue.extend(Message)
let count = 1

const notify = (options = {}) => {
  // 如果Vue运行在服务端,放弃调用
  if (Vue.prototype.$isServer) {
    return
  }
  
  if (typeof options === 'string') {
    options = {
      message: options
    }
  }

  // 创造实例
  const instance = new messageConstructor({
    propsData: options
  })

  // 渲染并挂载到body上
  const vm = instance.$mount()
  document.body.appendChild(vm.$el)
  vm.$el.style.zIndex = count

  // 返回一个主动关闭的方法
  const close = () => {
    vm.closed = true
  }
  return close
}

export default notify

这里我们用了Vue的一个方法,vue.extend,这个方法接受一些配置参数,返回一个可以生产vue实例的构造函数,其实我们平时使用的组件一般都是这些构造函数实例化的对象。代码的逻辑很简单,当notify方法被调用的时候会创造一个message组件的实例对象,同时传入props,最后渲染成dom并挂载到document.body上。最后我们提供一个install方法将notify和message组件全局安装到Vue中:

class Plugin {
  static install (Vue) {
    Vue.prototype.notify = notify
    Vue.mixin({
      components: {
        'oce-message': Message
      }
    })
  }
}
export default Plugin


// 全局注册
import oce-message from 'oce-message'
import Vue from 'vue'

Vue.use(oce-message)

// 使用

this.notify(...)

好了,一个简单的消息弹窗组件就完成了,具体的代码和使用方法在这里oce-message可以找到,欢迎star和提issue。

后续

这个组件有点简陋,其实有一些可以优化的地方:

  1. 样式
  2. 过渡动画
  3. 性能(实例是否可以做成一个单例?)


我是naecoo,前端打杂工程师,偶尔写写灌水文章...
Github
博客

你可能感兴趣的:(从0开始手写一个Vue消息弹窗组件)