zoukankan      html  css  js  c++  java
  • 【Vue源码相关】用Vue.extend()来做一个全局提示组件

    全局方法

    用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;下面我用一个全局提示组件为例,类似element-ui的message组件为大家演示一遍如何封装一个包含操作dom的的全局组件的,步骤主要有3步:

    1, 在componenets/Message 目录下新建一个Message.vue组件
    <template>
    <transition name="fade">
        <div class="message" :class="type" v-show="show">
          <i class="icon"></i>
          <span class="text">{{text}}</span>
        </div>
    </transition>
    </template>
    
    <script type="text/ecmascript-6">
      export default {
        name: 'message',
        props: {
          type: {
            type: String,
            default: 'info',
            validator: val => ['info', 'success', 'warning', 'error'].includes(val)
    //['info', 'success', 'warning', 'error'] 表示type只接收这四个字符串作为参数传入message组件
          },
          text: {
            type: String,
            default: ''
          },
          show: {
            type: Boolean,
            default: false
          }
        }
      }
    </script>
    
    <style scoped lang="stylus">
      @import "~@/common/style/global.styl"
       // fade动画 <transition name="fade"> </transition>
       // 下面的样式可以自己改
      .fade-enter-active,
      .fade-leave-active 
         transition: opacity .3s
      .fade-enter,
      .fade-leave-to
         opacity: 0
      .message
        position fixed
        top 40px
        text-align center
        left 50%
        transform translateX(-50%)
        min-width 400px
        padding 10px 20px
        color $strong-text-color
        background #f5f5f5
        font-size 14px
        line-height 1.4
        border-radius 4px
        z-index 1000
        box-shadow 0 0 10px rgba(0, 0, 0, .3)
        &.info
          color $strong-text-color
        &.success
          color $success-color
        &.error
          color $danger-color
        &.warning
          color $warning-color
    </style>
    2, 在componenets/Message目录准备一个index.js
    import Message from './Message.vue'
    
    const MESSAGE = {
      duration: 3000, // 显示的时间 ms
      animateTime: 300, // 动画时间,表示这个组件切换show的动画时间
      install(Vue) {
        if (typeof window !== 'undefined' && window.Vue) {
          Vue = window.Vue
        }
        Vue.component('Message', Message)
    
        function msg(type, text, callBack) {
          let msg
          let duration = MESSAGE.duration
          if (typeof text === 'string') {
            msg = text
          } else if (text instanceof Object) {
            msg = text.text || ''
            if (text.duration) {
              duration = text.duration
            }
          }
          let VueMessage = Vue.extend({
            render(h) {
              let props = {
                type,
                text: msg,
                show: this.show
              }
              return h('message', {props})
            },
            data() {
              return {
                show: false
              }
            }
          })
          let newMessage = new VueMessage()
          let vm = newMessage.$mount()
          let el = vm.$el
          document.body.appendChild(el) // 把生成的提示的dom插入body中
          vm.show = true
          let t1 = setTimeout(() => {
            clearTimeout(t1)
            vm.show = false  //隐藏提示组件,此时会有300ms的动画效果,等动画效果过了再从body中移除dom
            let t2 = setTimeout(() => {
              clearTimeout(t2)
              document.body.removeChild(el) //从body中移除dom
              newMessage.$destroy()
              vm = null // 设置为null,好让js垃圾回收算法回收,释放内存
    
              callBack && (typeof callBack === 'function') && callBack() 
          // 如果有回调函数就执行,没有就不执行,用&&操作符,
          // 只有&&左边 的代码为true才执行&&右边的代码,避免用面条代码:
          // if(true){
          //   ... 
          //   if(true){
          //   ...
          //   }
          // }
            }, MESSAGE.animateTime)
          }, duration)
        }
    
    // 挂载到vue原型上,暴露四个方法
        Vue.prototype.$message = {
          info(text, callBack) {
            if (!text) return
            msg('info', text, callBack)
          },
          success(text, callBack) {
            if (!text) return
            msg('success', text, callBack)
          },
          error(text, callBack) {
            if (!text) return
            msg('error', text, callBack)
          },
          warning(text, callBack) {
            if (!text) return
            msg('warning', text, callBack)
          }
        }
      }
    }
    export default MESSAGE
    上面的代码关键点就是用Vue.extend()构造出一个Vue子类实例,(注意我这里模板渲染只用到render函数,没有用template选项,因为template选项 要求装Vue时要加入模板编译器那块代码,用render函数更加简洁,只需要装运行时版本,Vue体积更加小);然后调用$mount()方法生成需要的dom,再拿到对应的$el,实例内部自己维护插入dom和移除dom的操作,对外暴露了四个方法info、success、error、warning方便不同的场景调用;类似的组件还有confrim组件、alert组件等,大同小异。
    3,在main.js中引入components/Message/index.js,以插件形式安装
    import Vue from 'vue'
    import vMessage from './components/Message/index' 
    Vue.use(vMessage)

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

    this.$message.info('普通消息') 
    this.$message.error('错误消息') 
    this.$message.warning('警告消息') 
    this.$message.success('成功消息')

     转自:https://www.jianshu.com/p/b931abe383e3

  • 相关阅读:
    git 教程
    gruntjs
    arm linux
    2021最佳迎接元旦的方式是什么!程序员:中国新冠疫苗上市!
    元旦表白神器!C语言实现浪漫烟花表白(有背景音乐+示例源码)
    大学期间,为啥我能学好C语言?只因我做到了这五点!
    为什么都说代码改变世界?是因为这五位程序员创造了未来!
    C++丨常见的四种求最大公约数方法!赶紧收藏!
    【腾讯C++面试题】如何才能获得腾讯的offer?掌握这20道终身受益!
    惊呆了!字节跳动成唯一上榜的中国公司!它是如何做到脱颖而出的?
  • 原文地址:https://www.cnblogs.com/vickylinj/p/13095001.html
Copyright © 2011-2022 走看看