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

13 篇文章 0 订阅

相信很多人用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'
          }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值