欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用Vue.extend()来做一个全局提示组件

程序员文章站 2024-03-04 16:58:05
...

相信很多人用vuejs构建单页应用时都会用到一些全局方法,比如发ajax请求时喜欢用axios挂载到vue原型上,如下:

// 1 引入vue和axios
import Vue from 'vue'
import axios from 'axios'
// 2 对axios的一些封装
// code ...

// 3 然后挂载到原型上
Vue.prototype.$axios = axios

用的时候就直接上this.$axios

// 用axios.get()方法可以这样用
this.$axios.get()

这样确实方便,不用每个用到axios的组件都去引入

类似如此,当我们要用到一些操作dom的方法时要怎么做呢,上面的例子纯属js的封装,没有涉及到dom;下面我用一个全局提示组件为例,为大家演示一遍如何封装一个包含操作dom的的全局组件的,步骤主要有3步:
1, 在componenets 目录下新建一个Message.vue组件

<template>
  <div class="messMessage" :id="messId" v-if="isMessage" >
    <div ref="messMessage" :class="['messageBox', type,isMesSHow?'messageBoxShow':'messageBoxHide']"
      :style="{'textAlign':align,width:width,padding:padding,borderRadius:borderRadius,background,background,color:color}">
      <!--提示的ICON-->
      <mgn-icon class="pc" :style="[iconData,{marginTop:-(iconStyle.fontSize.split('px')[0]/2)+0.5+'px'}]" :iconClass="iconStyle.name"></mgn-icon>
      <!--message内容-->
      <p v-html="message" :style="contStyles"></p>
      <!--关闭安钮-->
      <span class="messageClose pc"
      :style="{marginTop:-(closeIconStyle.fontSize.split('px')[0]/2)+'px'}"
      @click="messClose" v-if="isCloseIcon">
        <mgn-icon :style="closeIcon" :iconClass="closeIconStyle.name"></mgn-icon>
      </span>
    </div>
  </div>
</template>
<script type="text/ecmascript-6">
import mgnIcon from '@/components/pcComponents/icon'
export default {
  data () {
    return {
      // 组件内参数
      messId: (Math.random() + '').substring(3),
      isTrue: true,
      isMessage: false,
      // 以下为传入
      // icon图标样式
      iconStyle: {
        color: '',
        fontSize: '',
        name: ''
      },
      // icon组件
      iconData: {},
      // 关闭icon
      closeIcon: {},
      // 内容对齐方式
      align: 'left',
      // 弹框宽度
      width: '240px',
      // 弹框内边距
      padding: '14px, 26px, 14px, 14px',
      // 弹框圆角
      borderRadius: '4px',
      // 弹框背景颜色
      background: '',
      // 弹框字体颜色
      color: '',
      // 关闭icon
      isCloseIcon: true,
      // 关闭icon样式
      closeIconStyle: {
        color: '',
        fontSize: '',
        name: 'iconclose-line'
      },
      // 是否开自动关闭
      isAutoClose: true,
      // 信息类型 默认样式 info 成功 success 警告 warning 错误 error
      type: 'define',
      // 提示的消息内容
      message: '-',
      // 提示内容文字样式
      contStyles: {
        color: '',
        fontSize: '14px'
      },
      // 自动关闭的时间(毫秒)
      duration: 2000,
      // 显示组件
      isMesSHow: true
    }
  },
  methods: {
    // 调用事件
    messOpen (options) {
      this.isMessage = true
      this.$nextTick(() => {
        // 参数处理
        if (!this.iconStyle.name) {
          switch (this.type) {
            case 'success':
              this.iconStyle.name = 'iconcheck-fill'
              break
            case 'warning':
              this.iconStyle.name = 'icongantan'
              break
            case 'error':
              this.iconStyle.name = 'iconclose-fill'
              break
            case 'info':
              this.iconStyle.name = 'iconsigh-fill'
              break
          }
        }
        for (const key in this.inputDefault) {
          if (key.indexOf('Of') !== -1) {
            let arr = key.split('Of')
            this[arr[0]][this.titleCase(arr[1])] = this.inputDefault[key]
          }
        }
        this.iconData = {
          fontSize: this.iconStyle.fontSize,
          color: this.iconStyle.color
        }
        this.closeIcon = {
          fontSize: this.closeIconStyle.fontSize,
          color: this.closeIconStyle.color
        }
        this.iconStyle.fontSize = this.iconStyle.fontSize || '18px'
        this.closeIconStyle.fontSize = this.closeIconStyle.fontSize || '16px'
        this.contStyles.fontSize = this.contStyles.fontSize || '14px'
        this.contStyles.marginLeft = this.iconStyle.name ? '26px' : 0
        this.contStyles.marginRight = '26px'
        this.isMesSHow = true
        let _this = this
        this.$nextTick(() => {
          if (_this.isAutoClose) {
            setTimeout(function () {
              _this.isMesSHow = false
              // 清除dom结构
              _this.clearDom()
            }, _this.duration)
          }
        })
      })
    },
    // 转换首字母大写
    titleCase (name) {
      return name.charAt(0).toLowerCase() + name.slice(1)
    },
    // 关闭事件
    messClose () {
      this.isMesSHow = false
      this.clearDom()
    },
    // 清除dom结构
    clearDom () {
      let _this = this
      setTimeout(function () {
        var self = document.getElementById(_this.messId)
        if (self)document.body.removeChild(self)
      }, 280)
    }
  },
  components: {
    mgnIcon
  }
}
</script>
<style scoped lang="less" rel="stylesheet/less">
@import "../../common/less/base";
.messMessage {
  .pr();
  .l(1);
  @keyframes showAni {
    0% {
      opacity: 0;
      top: 0px;
    }
    100% {
      opacity: 1;
      top: 30px;
    }
  }
  @keyframes showAni2 {
    0% {
      opacity: 1;
      top: 30px;
    }
    100% {
      opacity: 0;
      top: 0px;
    }
  }
  .pc{
    .pa();
    .pos-t(50%);
  }
  .messageBoxShow{
    animation: showAni 0.3s ease;
  }
  .messageBoxHide{
    animation: showAni2 0.3s ease;
  }
  .messageBox {
    .ml(-119px);
    .w(240px);
    .p(14px, 26px, 14px, 14px);
    .radius(4px);
    .border-box();
    .pf();
    .zindex(9999999) !important;
    .pos-t(30px);
    .pos-l(50%);
    p {
      .f(14px);
      .i-block();
      .ml(10px);
      .mr(15px);
    }
    .messageClose {
      .pa();
      .pos-r(15px);
      .pointer();
      .fc(#c0c4cc);
      .iconfont{
        .left();
        .f(14px);
      }
    }
  }
  .info,
  .success,
  .warning,
  .error{
    .iconfont {
      .f(13px);
    }
  }
  .messageCont {
    .pa();
    .pos-t(50%);
  }
  // 默认样式
  .define {
    .bgc(#edf2fc);
    .bs(1px, solid, #ebeef5);
    .fc(#909399);
    .messageCont {
      .fc(#909399) !important;
    }
  }
  // 提示
  .info {
    .bgc(#edf2fc);
    .bs(1px, solid, #ebeef5);
    .fc(#909399);
    .messageCont {
      .fc(#909399) !important;
    }
  }
  // 成功
  .success {
    .bgc(#f0f9eb);
    .bs(1px, solid, #e1f3d8);
    .fc(#67c23a);
    .messageCont {
      .fc(#67c23a) !important;
    }
  }
  // 警告
  .warning {
    .bgc(#fdf6ec);
    .bs(1px, solid, #faecd8);
    .fc(#e6a23c) !important;
    .messageCont {
      .fc(#e6a23c) !important;
    }
  }
  // 错误
  .error {
    .bgc(#fef0f0);
    .bs(1px, solid, #fde2e2);
    .fc(#f56c6c);
    .messageCont {
      .fc(#f56c6c) !important;
    }
  }
}
</style>

2在项目里创建一个js文件

import messageVue from '../../components/pcComponents/message'
const messageBox = {
  install (Vue) {
    const MessageBoxInstance = Vue.extend(messageVue)
    let currentMsg
    const initInstance = () => {
      // 实例化vue实例
      currentMsg = new MessageBoxInstance()
      let msgBoxEl = currentMsg.$mount().$el
      document.body.appendChild(msgBoxEl)
    }
    // 在Vue的原型上添加实例方法,以全局调用
    Vue.prototype.$message = function (options) {
      initInstance()
      currentMsg._data = Object.assign(currentMsg._data, options)
      return currentMsg.messOpen()
    }
  }
}
export default messageBox

3,在main.js中引入你创建的js文件,以插件形式安装

import Vue from 'vue'
import message from './common/js/mesShow'
Vue.use(message)

最后,当你需要用的时候就直接,特别适合在ajax回调函数里面用来提示

this.$message({
          type: 'success',
          message: '替换icon图标',
          iconStyle: {
            name: 'icondredge-circle',
            color: '#ff7c10',
            fontSize: '14px'
          }
相关标签: 前端 js vue