博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
element 源码学习五 —— Notice 系列组件学习
阅读量:6292 次
发布时间:2019-06-22

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

消息提示行为是开发中非常常见的功能,Element 为我们提供了非常好用和美观的消息提示组件。这里就简单学习下 Notice 组件的 CSS 和代码逻辑。

简介

Notice 包括了五类组件:

  • Alert 用于页面中展示重要的提示信息。
  • Loading 加载数据时显示动效。
  • Message 常用于主动操作后的反馈提示。与 Notification 的区别是后者更多用于系统级通知的被动提醒。
  • MessageBox 模拟系统的消息提示框而实现的一套模态对话框组件,用于消息提示、确认消息和提交内容。
  • Notification 悬浮出现在页面角落,显示全局的通知提醒消息。

本文中不同角度来学习这些组件(这些组件有很多相似性,所以一起学习啦~)。

demo

下面是参照 element ui 写的一个小demo,尝试着了解下其中的 CSS

贴代码:

    
My Notice
成功提示的文案
X

代码的运行结果请看

以上代码实现了

  • Alert 的样式
  • loading 的简单版本
  • message 的无动画版本。

只实现这三个功能的原因是另外两个功能和扩展功能都是基于这个demo扩展的。

Alert 是一个静态的文本内容,只是外部包裹了带样式的容器。可能再多个隐藏按钮和消息图标。
Loading 和 MessageBox 其实的基本逻辑是插入或显示新的内容,并在显示完成后消失。需要注意的就是后面要添加一层遮罩阴影,遮罩如果非全屏使用 position:absolute 而全屏则使用 position:fixed 覆盖。另外就是注意 z-index 属性将组件放到视图最上层。
Message 和 Notification 其实就是文本内容、图标和按钮组合容器的现实和隐藏过程。它们的过渡动画使用的是 vue 的来实现。

通过几个问题来看源码

其实从样式上,上面的 demo 已经实现了大致的样子了。下面来看看组件的一些逻辑。源码内容比较多,所以就以问答的方式有目的的来看源码。

Alert 的界面实现?

Alert 由图标、文本内容、描述内容和关闭按钮组成:

组件很简单,注释上都写了~组件还做了 slot 插槽拓展,可以在 <el-alert> 标签内插入自定义内容。

如何显示纯文本、HTML 和 VNode

显示文本使用 {

{ text }} 指令来显示内容。
显示HTML使用 v-html 指令来渲染显示。

{

{ message }}

使用 vue 的 render 函数生成 VNode 对象传给组件作为组件 slot 插槽的默认显示结果。

if (isVNode(instance.message)) {    instance.$slots.default = [instance.message];    instance.message = null;  }

组件的过渡动画怎么来的

使用 Notice 系列组件时,发现组件的显示和消失都是有过渡动画的。界面看着更加友好和舒服。实现方式就是使用了 vue 的来实现效果。

界面的关闭使用的是什么方式?

对于 loading 和 message-box ,在没有界面时会在 body 最后添加组件内容,显示过后使用 v-show="false" (display:none;) 隐藏,随后就调用显示和隐藏界面。

// 将 message-box 组件加入到 body 中document.body.appendChild(instance.$el);

对于 Alert 由于一开始就显示,只是删除按钮,所以只需修改 v-show 属性隐藏即可。

对于 message 和 notification,这两个组件可以多次弹出,逐个关闭(自动或手动)。所以这两个组件是保存在一个数组中,然后进行渲染的,关闭某个组件就是一个将组件从组件数组中移除的过程。

// id 组件id// useOnClose 自定义关闭函数Message.close = function(id, userOnClose) {  for (let i = 0, len = instances.length; i < len; i++) {    if (id === instances[i].id) {      // 找到组件,执行自定义关闭函数并从数组中移除      if (typeof userOnClose === 'function') {        userOnClose(instances[i]);      }      instances.splice(i, 1);      break;    }  }};

message-box 的回调函数实现

对于 message-box 有两种函数回调:callback 函数和 Promise 函数。

if (typeof Promise !== 'undefined') {    return new Promise((resolve, reject) => {      msgQueue.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();  }

当然,到这一步只是将组件配置和回调函数组成对象,并没有执行。执行实在 showNextMsg 方法中。showNextMsg 方法用于组合当前组件 options 并写入到 DOM 中,然后显示组件。其中有这么一段关于回调的:

// 如果 currentMsg.options.callback 为 undefined      if (options.callback === undefined) {        instance.callback = defaultCallback;      }

所以再看看 defaultCallback 函数对象:

const defaultCallback = action => {  if (currentMsg) {    let callback = currentMsg.callback;    if (typeof callback === 'function') {      if (instance.showInput) {        callback(instance.inputValue, action);      } else {        callback(action);      }    }    if (currentMsg.resolve) {      if (action === 'confirm') {        if (instance.showInput) {          currentMsg.resolve({ value: instance.inputValue, action });        } else {          currentMsg.resolve(action);        }      } else if (action === 'cancel' && currentMsg.reject) {        currentMsg.reject(action);      }    }  }};

这里就可以看到回调函数和 Promise 的调用和传参过程。当组件“关闭”的时候执行 callback 方法回调:

doClose() {        ……        setTimeout(() => {          if (this.action) this.callback(this.action, this);        });      },

至此实现了回调及其传参。

如何实现显示多个 Notification 向下偏移插入?

偏移量计算在 Notification 的构造方法中计算获得当前组件 verticalOffset

const Notification = function(options) {  // 服务器渲染  if (Vue.prototype.$isServer) return;  options = options || {};  const userOnClose = options.onClose; // 自定义关闭  const id = 'notification_' + seed++; // 组件 id  const position = options.position || 'top-right'; // 位置  // 关闭事件  options.onClose = function() {    Notification.close(id, userOnClose);  };  // 组件实例  instance = new NotificationConstructor({    data: options  });  // vnode  if (isVNode(options.message)) {    instance.$slots.default = [options.message];    options.message = 'REPLACED_BY_VNODE';  }  instance.id = id;  instance.vm = instance.$mount();  // 添加实例  document.body.appendChild(instance.vm.$el);  instance.vm.visible = true;  instance.dom = instance.vm.$el;  instance.dom.style.zIndex = PopupManager.nextZIndex();  // 偏移量计算  let verticalOffset = options.offset || 0;  instances.filter(item => item.position === position).forEach(item => {    verticalOffset += item.$el.offsetHeight + 16;  });  verticalOffset += 16;  instance.verticalOffset = verticalOffset;  // 传入数组  instances.push(instance);  return instance.vm;};

偏移量 verticalOffset 在组件 package\notification/src/main.vue 中使用。

computed: {      // 正则匹配 position 是 top 还是 bottom      verticalProperty() {        return /^top-/.test(this.position) ? 'top' : 'bottom';      },      // 最后返回的内联样式      positionStyle() {        return {          [this.verticalProperty]: `${ this.verticalOffset }px`        };      }    }

如果 positionbottom-left 偏移量 verticalOffset 为 20,那么返回的内联样式就是:

{  bottom: 20px;}

至此实现了偏移的功能。

最后

这里简单学习了一下 Notice 系列组件的样式和逻辑。从中学到了:

  • 用 CSS 设计样式和动态修改样式属性。
  • 用了许多 DOM 的操作
  • 使用已有轮子 —— 用到了 Vue 的 directive、 transition 和 render。
  • 组件设计方面,学到了使用数组管理多个同类组件;使用 <slot> 标签给开发者预留拓展空间,使用构造函数的方法来拓展组件逻辑并定义一些快捷方法。

个人感觉学习一些成熟组件的源码能够学到不少东西,收获不少。

转载地址:http://tlcta.baihongyu.com/

你可能感兴趣的文章
embedded linux学习中几个需要明确的概念
查看>>
mysql常用语法
查看>>
Morris ajax
查看>>
【Docker学习笔记(四)】通过Nginx镜像快速搭建静态网站
查看>>
ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
查看>>
<转>云主机配置OpenStack使用spice的方法
查看>>
java jvm GC 各个区内存参数设置
查看>>
[使用帮助] PHPCMS V9内容模块PC标签调用说明
查看>>
关于FreeBSD的CVSROOT的配置
查看>>
基于RBAC权限管理
查看>>
数学公式的英语读法
查看>>
留德十年
查看>>
迷人的卡耐基说话术
查看>>
PHP导出table为xls出现乱码解决方法
查看>>
PHP问题 —— 丢失SESSION
查看>>
Java中Object类的equals()和hashCode()方法深入解析
查看>>
数据库
查看>>
Vue------第二天(计算属性、侦听器、绑定Class、绑定Style)
查看>>
dojo.mixin(混合进)、dojo.extend、dojo.declare
查看>>
Python 数据类型
查看>>