Vue - 实现消息通知组件及插件

效果图

在这里插入图片描述

功能分解

  • 动画
  • 计算高度

组件源码

<template>
    <div class="ys-message-wrapper animated fadeInDown">
      <div class="ys-message-toast">
        <img :src="currentType" alt="">
        <p>{{text}}</p>
      </div>
    </div>
</template>

<script>
export default {
  name: 'Message',
  props: {
    text: {
      type: String,
      default: '提示信息'
    },
    type: {
      type: String,
      default: 'info'
    }
  },
  data () {
    return {
      src: [require('../../assets/icon/info.svg'), require('../../assets/icon/warn.svg'), require('../../assets/icon/error.svg'), require('../../assets/icon/success.svg')]
    }
  },
  computed: {
    currentType () {
      let i
      switch (this.type) {
        case 'info':
          i = 0
          break
        case 'warn':
          i = 1
          break
        case 'error':
          i = 2
          break
        case 'success':
          i = 3
          break
        default:
          i = 0
      }
      return this.src[i]
    }
  }
}
</script>

<style lang="less" scoped>
  .ys-message-wrapper{
    width: 80%;
    min-height: 30px;

    position: absolute;
    left: 50%;

    animation-duration: 0.5s;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 0.5s;

    .ys-message-toast{
      max-width: 100%;
      pointer-events: none;
      padding: 8px 12px;
      border-radius: 4px;
      box-shadow: 0 1px 6px rgba(0,0,0,.2);
      background: #fff;
      display: flex;
      justify-content: center;
      align-items: center;

      img{
        width: 15px;
        height: 15px;
        object-fit: contain;
        margin: 0 8px 0 0;
      }
      p{
        max-width: 100%;
        font-size: 14px;
        word-break: keep-all;
        word-wrap: break-word;
      }
    }
  }

  .fadeInDown{
    animation-name: fadeInDown
  }
  @keyframes fadeInDown {
    from {
      opacity: 0;
      transform: translate3d(-50%, -100%, 0);
    }

    to {
      opacity: 1;
      transform: translate3d(-50%, 0, 0);
    }
  }

</style>

重头戏在这呢

实现的基本原理主要是两个:

  1. 使用point-event点透,防止遮罩层挡住页面
  2. 使用一个全局数组(栈)记录当前在dom中的message组件

插件源码

import MessageVue from '../../components/Message/Message'

const MessageBox = {}

MessageBox.install = (Vue, options) => {
  const MessageBoxInstance = Vue.extend(MessageVue)
  let currentMsg
  let msgBoxElList = []
  const initInstance = () => {
    if (document.querySelector('#message-container')) {
    } else {
      let template = '<div id="message-container" style="position: fixed;top: 15px;z-index:100;pointer-events:none;width: 100%;height: 100%;">' +
        '<div id="message-wrapper" style="position: relative;width: 100%;height: 100%;"></div>' +
        '</div>'
      let T = Vue.extend({template: template})
      let container = new T().$mount().$el
      document.body.appendChild(container)
    }
    currentMsg = new MessageBoxInstance()
  }
  const mount = () => {
    let msgBoxEl = currentMsg.$mount().$el
    let list = document.querySelectorAll('.ys-message-wrapper')
    if (list.length) {
      msgBoxEl.style.top = parseInt(list[list.length - 1].style.top) + list[list.length - 1].clientHeight + 15 + 'px'
    } else {
      msgBoxEl.style.top = 15 + 'px'
    }
    document.querySelector('#message-wrapper').appendChild(msgBoxEl)
    msgBoxElList.unshift(msgBoxEl)
  }

  Vue.prototype.$message = opt => {
    initInstance()
    if (typeof opt === 'string') {
      currentMsg.text = opt
    } else if (typeof opt === 'object') {
      Object.assign(currentMsg, opt)
    }
    mount()

    setTimeout(() => {
      let el = msgBoxElList.pop()
      el.style.top = 0
      setTimeout(() => {
        document.querySelector('#message-wrapper').removeChild(el)
      }, 500) // transition时间是0.5s
      // 当message都自动销毁以后,不需要销毁container了...缓存在这里
    }, 1500)
  }
}
export default MessageBox

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值