因最近业务需求需要实现类似于Element中的MessageBox组件的效果,所以尝试封装了一个类似的小组件,本文不介绍封装,因为受到MessageBox的启发,所以通过源码注释的方式详细剖析一下Element的MessageBox实现思想。

基础知识

Vue.extend(options)

  • 参数:{Object} options
  • 用法:使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。需要注意的是:data 选项是特例,需要注意 - 在 Vue.extend() 中它必须是函数
<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')

结果:

<p>Walter White aka Heisenberg</p>

为什么要介绍Vue.extend(options),因为Element中MessageBox的使用方式为函数式调用 (this.$confirm())的形式,以这种形式调用组件就不能按照常规的组件引入注册的形式去调用,可以通过Vue.extend(options)创建一个vue子类再通过函数暴露出去的方式实现函数式调用。

Element MessageBox 源码

// main.js 仅介绍主要部分代码
...import Vue from 'vue';
// 引入模板文件
import msgboxVue from './main.vue';
// element合并对象的工具函数,代码比较简单可以自行查阅
import merge from 'element-ui/src/utils/merge';
import { isVNode } from 'element-ui/src/utils/vdom';// 创建一个新的vue构造器,构造器可以手动挂载到一个新的Dom上
const MessageBoxConstructor = Vue.extend(msgboxVue);let currentMsg, instance;
let msgQueue = [];// 创建一个新的vue子实例
const initInstance = () => {instance = new MessageBoxConstructor({el: document.createElement('div')});// 给实例添加callback对象,后面会分析到instance.callback = defaultCallback;
};// defaultCallback处理了两种形式的回调方式
// 1.可以手动传入一个callback函数
// 2.使用默认的promise方式
const defaultCallback = action => {if (currentMsg) {let callback = currentMsg.callback;// 处理传入回调函数情况if (typeof callback === 'function') {// showInput区分是否为输入框MessageBoxif (instance.showInput) {callback(instance.inputValue, action);} else {callback(action, instance);}}// 处理promise情况if (currentMsg.resolve) {if (action === 'confirm') {if (instance.showInput) {currentMsg.resolve({ value: instance.inputValue, action });} else {currentMsg.resolve(action);}} else if (currentMsg.reject && (action === 'cancel' || action === 'close')) {currentMsg.reject(action);}}}
};const showNextMsg = () => {if (!instance) {initInstance();}instance.action = '';if (!instance.visible || instance.closeTimer) {if (msgQueue.length > 0) {// 顺序执行msgQueue中的currentMsgcurrentMsg = msgQueue.shift();// currentMsg内容如下:// {//   options: merge({}, defaults, MessageBox.defaults, options),//   callback: callback,//   resolve: resolve,//   reject: reject// }let options = currentMsg.options;// 将参数挂载到新创建的实例data上for (let prop in options) {if (options.hasOwnProperty(prop)) {// 实例参数修改instance[prop] = options[prop];}}// 如果options没传入callback将默认的callback赋值给实例的callbackif (options.callback === undefined) {// 当options里面有callback传入,正常输出。// 当options里面没有callback,instance.callback使用defaultCallbackinstance.callback = defaultCallback;}// 再次封装callbacklet oldCb = instance.callback;instance.callback = (action, instance) => {oldCb(action, instance);showNextMsg();};// 判断message是否传入的是Html片段,如果是Html片段添加到slotif (isVNode(instance.message)) {instance.$slots.default = [instance.message];instance.message = null;} else {delete instance.$slots.default;}// 将某些特定的参数设定初始值['modal', 'showClose', 'closeOnClickModal', 'closeOnPressEscape', 'closeOnHashChange'].forEach(prop => {if (instance[prop] === undefined) {instance[prop] = true;}});// 注意message是挂载到body上document.body.appendChild(instance.$el);// 控制弹窗出现Vue.nextTick(() => {instance.visible = true;});}}
};const MessageBox = function(options, callback) {if (Vue.prototype.$isServer) return;if (typeof options === 'string' || isVNode(options)) {// 当options参数为字符串 this.$msgbox('xxx')情况下默认设置message字段options = {message: options};// 若有两个及以上参数判断第二个参数是否为字符串赋值给titleif (typeof arguments[1] === 'string') {options.title = arguments[1];}} else if (options.callback && !callback) {// 参数为对象且对象有callback字段时 将callback赋值给callbackcallback = options.callback;}// 兼容不支持Promise情况if (typeof Promise !== 'undefined') {return new Promise((resolve, reject) => { // eslint-disable-linemsgQueue.push({options: merge({}, defaults, MessageBox.defaults, options),callback: callback,resolve: resolve,reject: reject});showNextMsg();});} else {msgQueue.push({options: merge({}, defaults, MessageBox.defaults, options),callback: callback});showNextMsg();}
};// 使用方式1:// this.$msgbox({title:'测试',message:'测试',callback:(action,instance)=>{//   console.log(action) //confirm//   console.log(instance) //vue实例// }})// 使用方式2:// this.$msgbox({title:'测试',message:'测试'},(action,instance)=>{//   console.log(action) //confirm//   console.log(instance) //undefined// })...// 暴露MessageBox方法export default MessageBox;
export { MessageBox };

可以看出Message组件主要的两个方法一个是MessageBox,一个是showNextMsg,这两个方法的主要功能一个是添加新的message对象一个是设置实例参数,除了callback的理解有些复杂外其他的代码理解应该不难。至于main.vue文件就是普通的vue文件不再赘述。

简单实现

MessageBox组件
源码

Element组件MessageBox剖析相关推荐

  1. ElementUI弹框组件 messageBox 如何换行 ?

    ElementUI弹框组件 messageBox 如何换行 ? 参考博客:element this.$confirm确定框内容换行显示 效果图 · 截图示下: demo代码如下: const conf ...

  2. Element组件引发的Vue中mixins使用,写出高复用组件

    我们都知道 Vue 采用的是一种组件化开发模式,组件在 Vue 中一个非常重要的核心概念.每个组件都是一个完整的实例,组件的创建,组件间的通讯,组件如何更好的复用,以及整个的生命周期的钩子.所以你会发 ...

  3. 为什么react选择了函数式组件(剖析原理)

    不好意思,这是知乎上我写的文章,就不再csdn发布了.如果需要阅读,请点击: 为什么react选择了函数式组件(剖析原理) 最近,发现知乎的连接出问题了,所以,暂时把内容放在此处.如果知乎上好了的话, ...

  4. element组件el-date-picker禁用当前时分秒之前的日期时间选择(代码最少)

    element组件el-date-picker禁用当前时分秒之前的日期时间选择(包有用) <el-date-pickerv-model="expireDate"type=&q ...

  5. Vue:Vue的element组件中的el-row的属性gutter什么意思?

    Vue:Vue的element组件中的el-row的属性gutter什么意思? 资源 gutter elementui中gutter和offset的区别

  6. 前端基于element组件的语音文件上传

    前端基于element组件的语音文件上传 原理 项目采用的是element组件的UI库,基于标签,实现基本的文件上传功能,并基于标签内置的触发事件,实现了对语音文件大小,格式,上传前确认,上传后显示已 ...

  7. Web核心技术之Element组件库学习及综合案例

    2,Element Element:是饿了么公司前端开发团队提供的一套基于 Vue 的网站组件库,用于快速构建网页. Element 提供了很多组件(组成网页的部件)供我们使用.例如 超链接.按钮.图 ...

  8. JavaWeb前端框架VUE和Element组件详解

    文章目录 前言 一.前端框架--VUE 1.1 概述 1.2 快速入门 1.3 Vue 指令 1.3.1 v-bind & v-model 指令 1.3.2 v-on 指令 1.3.3 条件判 ...

  9. Element 组件之 右键鼠标 自定义菜单

    参考链接: Element 组件之 右键鼠标 自定义菜单 Vue+ElementUI实现给Tab页添加鼠标右键菜单栏 Element tree组件之 自定义菜单 基于element tree组件.效果 ...

最新文章

  1. 【PL/SQL】--导出oracle单表数据--drp204
  2. c#大圣之路笔记——c# SqlDataReader和SqlDataAdapter区别
  3. 为什么写博客?如何在博客中更好的分享?
  4. 生理周期,POJ(1006)
  5. .NET 实现并行的几种方式(三)
  6. AE插件Aura Rowbyte Aura for Mac(AE几何粒子渲染效果插件)
  7. ES8新特性_async和await结合发送ajax请求---JavaScript_ECMAScript_ES6-ES11新特性工作笔记051
  8. 有关windows firewall边缘遍历(Edge traversal)的一点信息
  9. 【转】数字图像处理课件-艾海舟
  10. 新浪微博说说html,说说新浪微博
  11. 数据库语句删除数据库
  12. 基于Springboot+Vue开发建筑工地用料管理系统
  13. lpush rpush 区别_Redis系列(六):数据结构List双向链表LPUSH、LPOP、RPUSH、RPOP、LLEN命令...
  14. Nginx报错failed (13: Permission denied)
  15. 整理 Go 语言中 20 个占位符!
  16. js月份的计算公式_JS获取指定月份的天数几种方法
  17. 2021年,学UI设计还吃香吗?
  18. 刘东明应邀赴台湾担任金手指网络奖终审评委
  19. Golang源码探索----GC的实现原理(6)
  20. C++.继承——虚继承

热门文章

  1. 怎么让宽带和iptv同时走一根网线而且还不影响宽带网速?
  2. java propertygrid_PropertyGrid控件由浅入深(一):文章大纲
  3. matlab滑块sliderstep,slider滑块组件
  4. 这世上,从来没有一无所获的付出
  5. CentOS下unzip出现错误的解决办法
  6. 13.3、linux kernel介绍
  7. Jetson 系列——基于yolov5对火源或者烟雾的检测,使用tensorrt、c++和int8加速
  8. 二、如何使用 Flux 和 Mono 构建响应式数据流?
  9. Android Glide加载图片时转换为圆形、圆角、毛玻璃等图片效果
  10. 深入了解Linux网络设置