自定义组件 - Message 消息提示

目录

  • 组成
  • 实现
    • Icon 组件
    • CSS Modules
    • 得到组件渲染的DOM
    • 最终实现
    • 使用

目标:使用 Vue2 的语法,简单实现一个类似 element-ui - Message 消息提示 的组件。

组成

点击上面的链接,可以看到展示效果,由以下几个部分组成:

  • 消息类型
  • icon 图标
  • 消息内容

另外还有2点

  • 消息提示是水平居中的,至于垂直方向的位置,自由度比较高,看具体情况。
  • 消息提示关闭后,设置可以执行一个传入回调函数。

实现

分为下面几个部分。

Icon 组件

这里只是简单实现,详细的实现可以参考这里TODU。

<template>
  <i class="iconfont" :class="'icon-' + name">i>
template>

<script>
export default {
  props: {
    name: String,
  },
};
script>
<style scoped>
/* 包含了所有的 class */
@import "//at.alicdn.com/t/c/font_4268117_e989xit5r2k.css";
style>

使用

<Icon name="success" />

CSS Modules

可以在 js 中导入 css 来使用。参考这篇文章

用于导入 Message 组件的 css。

得到组件渲染的DOM

用于获取 Icon 组件的 DOM 元素,和消息内容进行拼接。具体参考这篇文档

最终实现

showMessage.js

import Vue from "vue";
import Icon from "@/components/icon";
import styles from "./showMessage.module.less";

/**
 * 弹出消息
 * @param {String} content 内容
 * @param {String} type 主题  info  error  success  warn
 * @param {Number} duration 显示时间, 毫秒
 * @param {HTMLElement} container 容器,消息在该容器内垂直水平居中;不传则显示到页面正中
 */
export default function (options = {}) {
  const content = options.content || "";
  const type = options.type || "info";
  const duration = options.duration || 2000;
  const container = options.container || document.body;
  // 创建消息元素
  const div = document.createElement("div");
  const iconDom = getComponentRootDom(Icon, {
    name: type,
  });
  div.innerHTML = `${styles.icon}">${iconDom.outerHTML}
${content}
`
; // 设置样式 const typeClassName = styles[`message-${type}`]; //类型样式名 div.className = `${styles.message} ${typeClassName}`; // 将div加入到容器中 // 容器的 position 是否改动过 if (options.container && getComputedStyle(container).position === "static") { container.style.position = "relative"; } container.appendChild(div); // 浏览器强行渲染 div.clientHeight; // 导致reflow // 回归到正常位置 div.style.opacity = 1; div.style.transform = `translate(-50%, -50%)`; // 等一段时间,消失 setTimeout(() => { div.style.opacity = 0; div.style.transform = `translate(-50%, -50%) translateY(-25px)`; div.addEventListener( "transitionend", function () { div.remove(); // 运行回调函数 options.callback && options.callback(); }, { once: true } ); }, duration); } // 获取某个组件渲染的Dom根元素 function getComponentRootDom(comp, props) { const vm = new Vue({ render: (h) => h(comp, { props }), }); vm.$mount(); return vm.$el; }

showMessage.module.less

.message {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) translateY(25px);
  z-index: 999;
  border: 1px solid;
  border-radius: 5px;
  padding: 10px 30px;
  line-height: 2;
  display: flex;
  align-items: center;
  transition: 0.4s;
  opacity: 0;
  white-space: nowrap;
  &-info {
    background: #edf2fc;
    color: #909399;
  }
  &-success {
    background-color: #f0f9eb;
    border-color: #e1f3d8;
    color: #67c23a;
  }
  &-warn {
    background-color: #fdf6ec;
    border-color: #faecd8;
    color: #e6a23c;
  }
  &-error {
    background-color: #fef0f0;
    border-color: #fde2e2;
    color: #f56c6c;
  }
}

.icon {
  font-size: 20px;
  margin-right: 8px;
}

使用

可以挂在到 Vue 原型上方便全局使用

import Vue from "vue";
import App from "./App.vue";
import showMessage from "./utils/showMessage";
Vue.prototype.$showMessage = showMessage;

new Vue({
  render: (h) => h(App),
}).$mount("#app");
handleClick() {
  this.$showMessage({
    content: "错误消息",
    type: "error",
    duration: 1500,
  });
}

以上。

你可能感兴趣的:(vue2,前端,javascript,vue)