• 自定义组件 - Message 消息提示


    目标:使用 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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    使用

    <Icon name="success" />
    
    • 1

    CSS Modules

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

    用于导入 Message 组件的 css。

    得到组件渲染的DOM

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

    其他注意点

    1,如何手动触发浏览器强行渲染(reflow重排)

    读取 DOM 元素的尺寸可位置即可。比如 clientHeight

    2,过渡事件

    transtionend 事件会在过渡完成后触发。addEventListener 也可以通过 once 来指定只执行一次。

    最终实现

    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; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    使用

    可以挂在到 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");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    handleClick() {
      this.$showMessage({
        content: "错误消息",
        type: "error",
        duration: 1500,
      });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以上。

  • 相关阅读:
    ROS服务Service通信机制在无人车中的具体应用
    webpack快速入门-基本使用
    学习ASP.NET Core Blazor编程系列十五——查询
    vue15
    native2ascii转换Unicode编码为utf-8
    记录一次解决数据库连接池连接泄露BUG
    创建一个electron桌面备忘录
    vue表格不显示列号123456
    【手写数字识别】GPU训练版本
    第八章 排序 七、堆排序
  • 原文地址:https://blog.csdn.net/qq_40147756/article/details/133282216