简介

告诉组件Notification 罕用于全局展现告诉揭示信息。本文将剖析其源码实现,急躁读完,置信会对您有所帮忙。 组件文档 Notification gitee源码

更多组件分析详见 Element 2 源码分析组件总览

Notification vs Message

Notification 在性能配置以及源码实现上与 Message 十分相似,所以局部反复内容本文将不做详尽解释。为了更好了解,请先浏览 Message 组件实现、Message 服务实现。

Message 罕用于被动操作后的反馈提醒,

  • 可提供胜利、正告和谬误等反馈信息。
  • 顶部居中显示并主动隐没,是一种不打断用户操作的轻量级提醒形式。

Notification 罕用于显示全局的告诉揭示音讯。

  • 较为简单的告诉内容。
  • 零碎被动推送。
  • 悬浮呈现在页面角落。

应用形式

Message组件一样,Notification以服务的形式调用。调用办法为 Notification(options),组件为每个 type 定义了各自的办法,如 Notification.success(options),并且能够调用 Notification.closeAll() 手动敞开所有实例。

options 参数配置项,在此不做详尽解释,详见 组件文档 Notification#options。

当组件库残缺引入,间接应用this.$notify(options)

// packages\notification\index.jsimport Notification from './src/main.js';export default Notification;// src/index.jsconst install = function(Vue, opts = {}) {  Vue.prototype.$notify = Notification;};// 残缺引入this.$notify(options);// 独自援用import { Notification } from 'element-ui'; Notification(options);

组件源码

DOM构造

组件 Notification 的 DOM 层次结构跟 Alert十分相似。

<transition name="el-notification-fade">  <!-- 组件根节点 -->  <div class="el-notification">    <!-- icon 图标 -->    <i class="el-notification__icon"></i>    <!-- 文字内容区域 -->    <div class="el-notification__group">      <!-- 题目 -->      <h2 class="el-notification__title" v-text="title"></h2>      <!-- 阐明文字 -->      <div class="el-notification__content" v-show="message">        <slot>          <p v-if="!dangerouslyUseHTMLString">{{ message }}</p>          <p v-else v-html="message"></p>        </slot>      </div>      <!-- 敞开按钮 -->      <div class="el-notification__closeBtn el-icon-close"></div>    </div>  </div></transition>

类名为el-notification<div> 元素根节点 1️,应用 transition 实现过渡成果,蕴含两个子节点:

  1. 2️左侧的图标 。
  2. 3️右侧的文字内容区域 。

    • 4️ 题目
    • 5️ 阐明文字
    • 6️ 敞开按钮(定位应用相对布局)

下图为组件Alert的DOM层次结构,十分类似。具体能够浏览前文 源码分析之Alert 。

组件性能

事件监听器。它能够是 transitionend 或 animationend

notification 性能实现跟 message相似,接下来次要阐明下不同之处,类似代码将省略。

// packages\notification\src\main.vue<template>  <transition name="el-notification-fade">    <div      :class="['el-notification', customClass, horizontalClass]"      v-show="visible"      :style="positionStyle"      @mouseenter="clearTimer()"      @mouseleave="startTimer()"      @click="click"     >      // 省略...    </div>  </transition></template><script type="text/babel">  export default {    data() {      return {        // ...         title: '', // 题目        position: 'top-right' // 自定义弹出地位      };    },    computed: {      // typeClass() 图标类名       // horizontalClass() 依据position 断定程度方向属性       // verticalProperty() 依据position 断定垂直方向属性       // positionStyle()      },    watch: {      // closed()    },    methods: {      // destroyElement()      // click() 点击回调事件       // close()        // clearTimer()        // startTimer()        // keydown     },    mounted() {      // startTimer      // add keydown Listener    },    beforeDestroy() {      // remove keydown Listener     }  };</script> 

生命周期 & 事件

跟message组件一样,当被挂载之后调用办法startTimer启用定时器,实现实例的主动敞开。挂载之后增加keydown事件监听。实例销毁之前,会移除keydown事件监听。

根节点不仅绑定 mouseentermouseleave 事件,也绑定了 click 事件,用于点击实例时调用传入的回调函数。

click() {  if (typeof this.onClick === 'function') {    this.onClick();  }},

组件 transition 没有绑定after-leave钩子函数,而是在侦听器中增加了 transitionend 事件监听,调用办法 destroyElement 用于组件敞开后的销毁工作。

// watch  侦听closed(newVal) {  if (newVal) {    this.visible = false;    this.$el.addEventListener('transitionend', this.destroyElement); // 增加过渡成果事件监听  }}// methodsdestroyElement() {  this.$el.removeEventListener('transitionend', this.destroyElement); //移除过渡成果事件监听  // vm destroy  &&  remove el },

办法 keydown不仅实现按ESC键敞开音讯组件,同时反对按backspace detele键取革除定时器,按其余键复原计时器。

keydown(e) {  // 8 backspace 46 detele 革除定时器  if (e.keyCode === 46 || e.keyCode === 8) {    this.clearTimer();   } else if (e.keyCode === 27) { // esc敞开音讯    if (!this.closed) {      this.close();    }  } else {    this.startTimer(); // 复原计时器  }}

地位偏移

属性position定义实例的弹出地位,反对四个选项:top-righttop-leftbottom-rightbottom-left,默认为top-right

组件应用相对定位,依据属性position值断定高低、左右边界偏移属性。

计算属性verticalProperty 用于断定高低偏移属性应用top或bottom;计算属性positionStyle基于 verticalProperty 值生成内联款式 top/bottom:20px

verticalProperty() {  return /^top-/.test(this.position) ? 'top' : 'bottom';}, positionStyle() {  return {    [this.verticalProperty]: `${ this.verticalOffset }px`  };}

左右偏移应用计算属性horizontalClass 生成类名rightleft

horizontalClass() {  return this.position.indexOf('right') > -1 ? 'right' : 'left';},

相干款式定义:

.el-notification.right {    right: 16px} .el-notification.left {    left: 16px}

服务实现

Notification 在源码实现上与 Message 十分相似,具体的性能流程解说请浏览前文Message 服务实现,此处不在过多赘述。

源码精简后构造如下,代码创立了function类型的对象Notification,同时给对象增加属性办法 closecloseAllwarninginfoerror,导出对象 Notification

// packages\notification\src\main.jsconst NotificationConstructor = Vue.extend(Main); // 组件结构器  let instance; // 组件实例 let instances = []; // 存储所有组件实例数组let seed = 1; // 用于递增计数 const Notification = function(options) {  // 逻辑 ...};['success', 'warning', 'info', 'error'].forEach(type => {  // 逻辑 ...});Notification.close = function(id, userOnClose) {  // 逻辑 ...};Notification.closeAll = function() {  // 逻辑 ...};export default Notification; 

Notification反对自定义弹出地位,能够从屏幕四角中的任意一角弹出,然而所有实例都在保留在同一数组中,在款式计算的过程中,新增了逻辑辨别地位雷同的元素。

函数Notification中,依据属性position过滤元素个数,进行偏移量计算。即便未设置offset值,组件默认偏移量为 16

const Notification = function(options) {  // ...  const position = options.position || 'top-right';    // ...  let verticalOffset = options.offset || 0;  instances.filter(item => item.position === position).forEach(item => {    verticalOffset += item.$el.offsetHeight + 16;  });  verticalOffset += 16;   instance.verticalOffset = verticalOffset;  // ...};

函数close中,当删除实例后,从新计算只须要调整索引值大于以后实例index的偏移量,依据属性position过滤元素,同时依据计算属性verticalProperty更新DOM元素款式。

Notification.close = function(id, userOnClose) {  // ...    // 数据更新后 偏移量计算  const position = instance.position;  const removedHeight = instance.dom.offsetHeight;  for (let i = index; i < len - 1; i++) {    if (instances[i].position === position) {      instances[i].dom.style[instance.verticalProperty] =        parseInt(instances[i].dom.style[instance.verticalProperty], 10) - removedHeight - 16 + 'px';    }  }};// 计算属性verticalProperty() {  return /^top-/.test(this.position) ? 'top' : 'bottom';},

款式实现

组件款式源码 packages\theme-chalk\src\notification.scss 应用混合指令 bwhenme 嵌套生成组件款式。

// 生成 .el-notification@include b(notification) {  // ...    // 生成 .el-notification.right  &.right {    // ...  }  // 生成 .el-notification.left  &.left {    // ...  }  // 生成 .el-notification__group  @include e(group) {    // ...  }  // 生成 .el-notification__title  @include e(title) {    // ...  }  // 生成 .el-notification__content  @include e(content) {    // ...        // 生成 .el-notification__content p    p {      // ...    }  }  // 生成 .el-notification__icon  @include e(icon) {    // ...  }  // 生成 .el-notification__closeBtn  @include e(closeBtn) {    // ...        // 生成 .el-notification__closeBtn:hover    &:hover {      // ...    }  }  // 生成 .el-notification .el-icon-success/error/info/warning  .el-icon-success {    // color ...  }  // error/info/warning}.el-notification-fade-enter {  // 生成 .el-notification-fade-enter.right  &.right {    // ...  }  // 生成 .el-notification-fade-enter.left  &.left {    // ...  }}// 生成 .el-notification-fade-leave-active .el-notification-fade-leave-active {  // ...}

关注专栏

如果本文对您有所帮忙请关注➕、 点赞、 珍藏⭐!您的认可就是对我的最大反对!

此文章已收录到专栏中 ,能够间接关注。