博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从零实现Vue的组件库(七)- Message-Box 实现
阅读量:6378 次
发布时间:2019-06-23

本文共 4438 字,大约阅读时间需要 14 分钟。

模拟系统的消息提示框而实现的一套模态对话框组件,用于消息提示、确认消息和提交内容。

概述:该组件的结构、原理与类似,所以这篇文章会减少组件开发的介绍,而增加一些Vue.extendVue生命周期相关源码的解读。

主要有以下几点:
  • Message-Box的基本功能实现;
  • Vue.extend$mount原理以及相应的优化点。

1. 实例

代码

this.$confirm({ title: "自定义提示", content: `

自定义HTML

`, onConfirm: () => this.$message({ content: "确定" }), onCancel: () => this.$message({ type: "warn", content: "取消" })});this.$alert({ title: "标题名称", content: "这是一段内容", onConfirm: () => this.$message({ content: "确定" })});复制代码

实例地址:

代码地址:

2. 原理

将Message-Box分为两部分:

  • Message-Box组件,用于在页面中显示模态框,包含确认、取消、关闭三个操作;
  • Vue插件的封装,利用this.$alert({...})this.$confirm({...})在页面中挂载 Message-Box 组件。

首先开发Message-Box组件,其基本template如下

{
{ title }}
复制代码

基本结构非常简单,清晰的三段:

  • 最上层的visible状态用于控制整个模态框的显示、消失,header部分,包含title,以及关闭按键;
  • 中间content部分,包含传入的content,为了支持HTML,所以采用v-html
  • 最底层footer部分,包含两个按钮,如果当前模态框的类型是alert则只有confirm,如果为confirm,则需要添加cancel

所涉及的datamethods如下

export default {    data() {        return {            // 控制模态框的显示            visible: true        }    },    watch: {        visible(newValue) {            if (!newValue) {                // 过渡结束后注销组件                this.$el.addEventListener('transitionend', this.destroyElement)            }        }    },    mounted() {        document.body.appendChild(this.$el)    },    destroyed() {        this.$el.parentNode.removeChild(this.$el)    },    methods: {        destroyElement() {            this.$destroy()        },        close() {            // 关闭模态框            this.visible = false        },        handleClick(type) {            // 处理对应的点击事件            this.$emit(type);            this.close();        }    }}复制代码

可以看到在该组件的mounteddestroyed两个生命周期中完成组件在页面中的挂载与注销

mounted() {    document.body.appendChild(this.$el)},destroyed() {    this.$el.parentNode.removeChild(this.$el)}复制代码

其中注销的顺序是:

  • 首先使组件的visible状态为false,使它在页面中消失,然后触发模态框transition的过度动画;
  • 之后监听addEventListener('transitionend', this.destroyElement),如果过渡结束,就触发对应的destroyElement触发组件的生命周期destroyed,在组件中注销this.$el.parentNode.removeChild(this.$el)

相对于注销,挂载则要复杂的一些,由于这部分涉及到了封装,所以一起梳理。

// 引入上述Message-Box组件import messageBox from './messagebox.vue'// 生成Message-Box对应的构造器const Constructor = Vue.extend(messageBox)function generateInstance(options, type = 'alert') {    let instance = new Constructor({        propsData: Object.assign(options, {            type        }),    }).$mount(document.createElement('div'))    ...    return instance}复制代码

首先import模态框组件,然后利用创建一个Message-Box组件的构造器。

当调用this.$alert以及this.$confirm时利用new Constructor创建一个Message-Box组件,这时显式调用vm.$mount()手动开启编译,此时会触发组件的mounted生命周期

mounted() {    document.body.appendChild(this.$el)}复制代码

完成在页面中的挂载。

最后一步,利用完成封装,在Vue.prototype上添加$alert以及$confirm方法。

export default {    install(Vue) {        Vue.prototype.$alert = (options = {}) => generateInstance(options)        Vue.prototype.$confirm = (options = {}) => generateInstance(options, 'confirm')    }}复制代码

3. 源码

阐述下 Vue.extend 的源码,在 src/core/global-api/extend.js 中,比较关键的点在于:

  • 如何通过已有组件 object 生成对应构造器 constructor
  • 对于同一个组件的 constructor ,是否存在什么优化。
Vue.extend = function (extendOptions: Object): Function {    extendOptions = extendOptions || {}    const Super = this    const SuperId = Super.cid    const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})    if (cachedCtors[SuperId]) {        return cachedCtors[SuperId]    }    ...        const Sub = function VueComponent (options) {        this._init(options)    }    Sub.prototype = Object.create(Super.prototype)    Sub.prototype.constructor = Sub    ...    // cache constructor    cachedCtors[SuperId] = Sub    return Sub}复制代码

从源码中可以看出,Vue.extend 是一个变式的原型式继承

function object(o) {    function F() {}    F.prototype = o    return new F()}复制代码

临时的构造函数 function Ffunction VueComponent,函数中 this._init 指向的是初始化Vue时候的 _init function

在将 F.prototype 指向 Object.create(Super.prototype) ,这样可以继承 Vue 本身原型上的一些方法,最后 return constructor

之后 Vue 还做了缓存处理,所以多次利用 Vue.extend 创建Message-Box、Toast、Message时,并不会影响效率/

if (cachedCtors[SuperId]) {    return cachedCtors[SuperId]}// cache constructorcachedCtors[SuperId] = Sub复制代码
  1. 总结

深究了一下 Vue.extend 背后的原理,以及如何用它来是实现组件。

参考文章:

往期文章:

原创声明: 该文章为原创文章,转载请注明出处。

你可能感兴趣的文章
CentOS 6.4下Squid代理服务器的安装与配置
查看>>
java三大特性之封装
查看>>
爱创课堂每日一题第五十八天-javascript对象的几种创建方式
查看>>
keepalived设置master故障恢复后不重新抢回VIP配置
查看>>
2018-06-25笔记(LAMP环境搭建)
查看>>
msyql主从畚份
查看>>
[学习笔记]上下界网络流
查看>>
小知识点随手记
查看>>
如何实现一个搜索引擎
查看>>
vue写出放大镜的效果
查看>>
JVM(五)回收机制
查看>>
reactjs弹幕视频播放
查看>>
linux dns
查看>>
线段上格点的个数
查看>>
上线前网页性能及体验的检查
查看>>
LoadRunner脚本编写(转)
查看>>
java泛型
查看>>
“用户、组或角色'XXX'在当前数据库中已存在”问题
查看>>
Volatile关键字的解读
查看>>
LeetCode【169. Majority Element】
查看>>