• 自定义组件 - 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

    以上。

  • 相关阅读:
    kali 脚本应用(二)
    WebRTC系列--track的set_enabled详解
    Leetcode LCR182:动态口令
    中视频伙伴计划开通收益功能的方法和使用介绍
    短视频剪辑矩阵系统开发源码----源头搭建
    力扣解法汇总592-分数加减运算
    基于springboot+vue的餐饮管理系统实现与设计(源码+数据库+文档)
    基于Delft3D模型水体流动、污染物对流扩散、质点运移、溢油漂移及地表水环境报告编制教程
    NNDL实验 优化算法3D轨迹 pytorch版
    山形三元组
  • 原文地址:https://blog.csdn.net/qq_40147756/article/details/133282216