单例模式应用,实现一个message弹窗

const Message = (function() {

  class Mes {

    constructor() {

      this.ele = document.createElement('div')

      this.ele.className = 'mes-box'

      document.body.appendChild(this.ele)

    }

    setContent(opts) {

      this.ele.classList.add('fadeIn')

      const type = opts.type || 'default'

      let iconClassList = ''

      switch (type) {

        case 'default':

          iconClassList = 'iconfont icon-loading rotate default inBlock'

          break

        case 'success':

          iconClassList = 'iconfont icon-success success'

          break

        case 'warning':

          iconClassList = 'iconfont icon-warning warning'

          break

        case 'error':

          iconClassList = 'iconfont icon-error error'

          break

        default:

          iconClassList = 'iconfont icon-loading inBlock ratate'

      }



      this.ele.innerHTML = `

            <div class="mes-icon-box ${type}">

                <i class="${iconClassList}"></i>

            </div>

            <div class="mes-cont">${opts.text || '加载中,请稍后...'}</div>

           `

      if (opts.duration) {

        setTimeout(() => {

          this.ele.classList.remove('fadeIn')

        }, opts.duration)

      }

    }

    close() {

      this.ele.classList.remove('fadeIn')

    }

  }

  let instance = null

  return function(options = { duration: '', icon: '', text: '', type: 'default' }) {

    if (!instance) instance = new Mes()

    instance.setContent(options)

    return instance

  }

})()

export default Message

我们实现一个message弹窗,将在axios封装中替换第三方组件库提供的message

-----------------------

message.js

当然message的样式我们需要在全局的css中去做相关设置,我们新建css样式在main.js中引入

.mes-box {

  display: flex;

  position: fixed;

  top: 50%;

  left: 50%;

  padding: 16px;

  min-width: 220px;

  transform: translate(-50%, -50%);

  box-shadow: 0 0 10px 4px #ccc;

  transition: all 0.2s ease-out;

  font-size: 14px;

  z-index: 3000;

  opacity: 0;

  background: #fff;

}

.inBlock {

  display: inline-block;

}

.fadeIn {

  opacity: 1;

}

.mes-icon-box {

  width: 60px;

  text-align: center;

}

.mes-cont {

  flex: 1

}

.rotate {

  animation: ani 1s ease-in infinite;

}

@keyframes ani {

  0% {

    -webkit-transform: rotate(0deg);

  }

  100% {

    -webkit-transform: rotate(360deg);

  }

}

.slide-enter-active,

.slide-leave-active {

  transition: all 0.2s;

  top: 100px;

  opacity: 1;

}

.slide-enter,

.slide-leave-active {

  opacity: 0;

  top: -100px;

}

.default {

  color: #409EFF

}

.error {

  color: #f00

}

.warning {

  color: #ff7a33

}

.success {

  color: #63deaa

}

第三步,我们将在axios的封装中用到它

import axios from 'axios'

import router from '@/router'

import qs from 'qs'

import Message from '@/plugins/message'

let loadingInstance = null

console.log('process.env:', process.env)

const config = {

  timeout: 5000,

  baseURL: process.env.VUE_APP_BASE_API

  // baseURL: ''

}

const Http = axios.create(config)

// 添加请求拦截器

Http.interceptors.request.use((config) => {

  const Token = localStorage.getItem("token")

  if (Token) {

    config.headers.token = Token

  }

  if (config.method === 'post' || config.method === 'put') {

    if (config.data.loading) {

      console.log('loadingInstance:', loadingInstance)

      loadingInstance = new Message()

    }

  } else {

    if (config.params.loading) {

      loadingInstance = new Message()

    }

  }

  return config

})

// 添加响应拦截器

Http.interceptors.response.use(

  (response) => {

    if (response.data.code === 0) {

      if (loadingInstance) {

        loadingInstance.close()

      }

    } else {

      loadingInstance = new Message({

        type: 'error', duration: 3000,

        text: '程序异常,请联系管理员'

      })

    }

    return response.data

  },

  (error) => {

    console.log('error:', error)

    if (

      error.code === 'ECONNABORTED' ||

      error.message === 'Network Error' ||

      error.message.includes('timeout')

    ) {

      new Message({ type: 'error', text: '当前网络错误', duration: 3000 })

    }

    // 错误处理

    const code = error.response.status

    if (code === 200) {

    } else if (code === 403) {

      // 处理token过期问题

      loadingInstance = new Message({

        type: 'error', duration: 3000,

        text: '登录已过期,请重新登录'

      })

      localStorage.clear()

      router.replace('/')

    } else {

      loadingInstance = new Message({

        type: 'error', duration: 3000,

        text: error.response.data

      })

    }

    return Promise.reject(error)

  }

)

// loading:  true:请求接口时出现加载提示,false反之

function request(url, method = 'GET', params = {}, loading = false, headerConfig = {}) {

  const Method = method.toLowerCase()

  if (Method === 'get' || Method === 'delete') {

    params = { ...params, loading }

    return Http[Method](url, { params })

  } else if (Method === 'post' || Method === 'put') {

    let data = {}

    if (Object.keys(headerConfig).length > 0) {

      data = qs.stringify({ ...params, loading })

    } else {

      data = Object.assign(params, { loading }, headerConfig)

    }

    return Http[Method](url, data, headerConfig)

  }

}

export default request

效果图如下:

为什么需要单例模式,因为我们在axios拦截中请求成功,需要关闭这个message,所以所有的打开与关闭,针对的都是同一个实例对象。这样就可以防止页面中多个message出现干扰

----------------------------------------------------------------------------

更新:

最近在使用的时候发现有一个问题。因为我们的dom中一直都会存在这个mes-box,而且我们对它的隐藏实际是是通过opactity:0来实现的,但是它的z-index很大,导致虽然在视图上看不见它,但是它会干扰到我们正常的点击。也就是如果有一个按钮的位置刚好和messagebox重合,但是由于层级关系,messagebox会遮挡住页面内容导致无法点击。其实解决办法也很简单:我们给messagebox默认设置一个很低的层级比如z-index:-400,在fadeIn的时候给它把层级提上去。

在fadeIn的css里做如下设置:

.fadeIn{

opacity:1;

z-index:3000

}

即可解决这个问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值