使用纯JavaScript封装一个消息提示条功能示例详解

使用纯JavaScript封装一个消息提示条功能示例详解_第1张图片

介绍

一个类似Element UIAnt-Design UI等 UI 框架的消息提示功能,方便在任何网页环境中直接调用函数使用;区别在不依赖 js 及 css 引用,而是使用纯 js 进行封装实现,代码更精简,同时保持和 UI 框架一样的视觉效果(可自行修改成自己喜欢的样式)

代码仓库

在线预览效果(点击【登录】、【点击复制】按钮时触发提示效果)

思路&布局

  • 先来写单个提示条,并实现想要的过渡效果,最后再用逻辑操作输出节点即可;这里不需要父节点包裹,直接输出到中,保证提示条的代码结构位置永远在最上层。


  
  • 最基础的样式写好之后,来定义进入的过渡动画,这里使用animation作为进入动画,因为节点一输出就会执行了
.msg-box {
  ...省略以上代码
  animation: msg-move .4s;
}
@keyframes msg-move {
  0% {
    opacity: 0;
    transform: translate3d(-50%, -100%, 0);
  }
  100% {
    opacity: 1;
    transform: translate3d(-50%, 0%, 0);
  }
}
  • 最后就是过渡结束动画,这里使用transition的过渡方式,即定义一个.hide,之后通过 js 去控制切换 class 去实现过渡切换
.msg-box {
  ...省略以上代码
  opacity: 1;
  transition: .4s all; // 保持和 animation 的过渡时间一致
}
.msg-box.hide {
  opacity: 0;
  transform: translate3d(-50%, -100%, 0);
}

这里样式布局就全部完成了,剩下的交给 js 去处理对应的操作逻辑。

操作逻辑

  • 因为调用时,消息条是多个,并且为往下叠加的效果,且节点是散布在下,有可能给其他dom操作插入节点。所以在输出节点的时候要将其存放起来,然后通过循环的方式去设置每一个节点的padding-top,这样就能保证视觉排列效果和代码操作的顺序保持一致了,之后所做的删除操作也是通过循环去设置每一个节点的padding-top
/**
 * 消息队列
 * @type {Array}
 */
const messageList = [];
/**
 * 获取指定`item`的定位`top`
 * @param {HTMLElement=} el 
 */
function getItemTop(el) {
  let top = 10; // 起始的边距
  for (let i = 0; i < messageList.length; i++) {
    const item = messageList[i];
    if (el && el === item) {
      break;
    }
    top += item.clientHeight + 20; // 两个消息条的间距为20
  }
  return top;
}
/**
 * 删除指定列表项
 * @param {HTMLElement} el 
 */
function removeItem(el) {
  for (let i = 0; i < messageList.length; i++) {
    const item = messageList[i];
    if (item === el) {
      messageList.splice(i, 1);
      break;
    }
  }
  el.classList.add(".hide");
  messageList.forEach(function (item) {
    item.style.top = `${getItemTop(item)}px`;
  });
}
  • 输出节点,并监听 动画进入过渡持续时间动画退出过渡
  • 进入的过渡使用addEventListener("animationend", fn)
  • 持续时间使用setTimeout(延迟 N 秒之后为节点添加.hide
  • 退出的过渡使用addEventListener("transitionend", fn)
/** 一直累加的定位层级 */
let zIndex = 1000;
/**
 * 显示一条消息
 * @param {string} content 内容
 * @param {number} duration 持续时间,优先级比默认值高
 */
function show(content, duration) {
  const el = document.createElement("div");
  el.style.top = `${getItemTop()}px`;
  el.style.zIndex = zIndex;
  el.innerHTML = content;
  zIndex++;
  messageList.push(el);
  document.body.appendChild(el);
  // 添加动画监听事件
  function animationEnd() {
    el.removeEventListener("animationend", animationEnd);
    setTimeout(removeItem, duration || 3000, el);
  }
  el.addEventListener("animationend", animationEnd);
  function transitionEnd() {
    if (getComputedStyle(el).opacity !== "0") return;
    el.removeEventListener("transitionend", transitionEnd);
    el.remove();
  }
  el.addEventListener("transitionend", transitionEnd);
}

整个消息输出功能就完成了,最后只需要把对应的方法封装起来并暴露需要调用的函数,并把css样式写进方法里就可以在任意地方使用了;css写进js里其实就是把上面写好的样式,通过字符串模板的方式用变量接收并赋值给动态输入的