javascript - 求解读element-ui源码(vue2.0)

查看:120
本文介绍了javascript - 求解读element-ui源码(vue2.0)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

主要看main.js,然后解答下我注释里的疑问!谢谢!

先说用法:

test.vue

<template>
  <div id="test" @click="open">
    <!--内容填充,点击div调出message-->
  </div>
</template>

<script>
  import Vue from 'vue'
  import Message from './messages/index.js'//1.引进message组件
  export default {
    methods: {
      open() {
        this.$message({//2.这里应该就是下面源代码mian.js里面的options
          message: '恭喜你,这是一条成功消息',
          type: 'success'
        });
      }
    }
  }
</script>

源码:

message/src/main.js

import Vue from 'vue'
let MessageConstructor = Vue.extend(require('./main.vue'));
let instance;
let instances = [];
let seed = 1;
let Message = function(options) {
  options = options || {};
  if(typeof options === 'string'){
    options = {
      message: options
    };
  }
  let userOnClose = options.onClose;//3.options并没有这个属性啊
  let id = 'message_' + seed++;

  options.onClose = function(){//4.这个如果放到3前面就好解释了,为什么在3后面呢?
    Message.close(id, userOnClose);//5.为什么又把userOnClose传进去了?不就是等于传自己进去吗?
  };
  instance = new MessageConstructor({
    data: options
  });
  instance.id = id;
  instance.vm = instance.$mount();
  instance.vm.visible = true;
  instance.dom = instance.vm.$el;
  instances.push(instance);
};

['succes', 'warning', 'info', 'error'].forEach(type => {
  Message[type] = options => {//6.Message在上文是函数啊,Message哪里跑出来的type属性?
    if(typeof options === 'string'){
      options = {
        message: options
      };
      options.type= type;
      return Message(options);
    };
  }
});

Message.close = function(id, userOnClose){//7.不是很懂这段代码的意思,作用是什么?
  for (let i = 0, len = instances.length; i < len; i++) {
    if (id === instances[i].id) {
      if (typeof userOnClose === 'function') {
        userOnClose(instances[i]);
      }
      instances.splice(i, 1);
      break;
    }
  }
}

export default Message;

message/src/main.vue

<template lang="html">
  <transition name"b-message-fade">
    <div class="b-message" v-show="visible" @mouseenter="clearTimer" @mouseout="startTimer">
      <img class="b-message-icon" :src="imgType" alt=""/>
      <div class="b-message-group">
        <p>{{ message }}</p>
        <div v-if="showClose" class="b-message-closeBtn b-icon-close" @click="handleClose"></div>
      </div>
    </div>
  </transition>
</template>

<script>
export default {
  data() {
    return {
      visible: false,
      message: '',
      duration: 3000,
      type: 'success',
      onClose: null,
      shoClose: false,
      closed: false,
      timer: null
    }
  },
  computed: {
    imgType() {
      return require(`../assets/${ this.type }.svg`);
    }
  },
  watch: {
    closed(newValue) {
      if (newValue) {
        this.visible = false;
        this.$el.addEventListener('transitionend', () => {
          this.$destroy(true);
          this.$el.parentNode.removeChild(this.$el);
        });
      }
    }
  },
  methods: {
    handleClose() {
      this.closed = true;
      if (typeof this.onClose === 'function') {
        this.onClose(this);
      }
    },
    clearTimer() {
      clearTimeout(this.timer);
    },
    startTimer() {
      if (this.message.duration > 0) {
        this.timer = setTimeout(() => {
          if (!this.closed) {
            this.handleClose();
          }
        }, this.duration);
      }
    },
    mouted() {
      this.startTimer();
    }
  }
}
</script>

<style lang="css">
.b-message {
  width: 300px;
  height: 40px;
  box-shadow: 0 2px 4px 0 rgba(0, 0, 0, .12), 0 0 6px 0 rgba(0, 0, 0, .04);
  min-width: 300px;
  min-height: 40px;
  padding: 10px 12px;
  border-radius: 2px;
  position: absolute;
  left: 0;
  right: 0;
  top: 20px;
  margin: auto;
  transition: all .3s ease;
}

.b-message-icon {
  width: 40px;
  height: 40px;
  position: absolute;
  left: 0;
  top: 0;
}

.b-message-group {
  margin-left: 40px;
  position: relative;
}

.b-message-group p {
  font-size: 14px;
  line-height: 20px;
  margin: 0 34px 0 0;
  white-space: nowrap;
  color: #8492a6;
  text-align: justify;
}

.b-message-closeBtn {
  font-family: element-icons!important;
  top: 0;
  right: 0;
  position: absolute;
  cursor: pointer;
  color: #c0ccda;
  font-size: 14px;
}

.b-message-closeBtn:before {
  content: "\E913";
}

.b-message-fade-enter {
  transform: translateY(-100px);
}

.b-message-fade-leave-active {
  transform: translateY(-100px);
}
</style>

message/index.js

module.exports = require('./src/main.js') 

解决方案

import Vue from 'vue';
import { PopupManager } from 'vue-popup';
let MessageConstructor = Vue.extend(require('./main.vue'));

let instance;
let instances = []; // 存放当前未close的message
let seed = 1; // id叠加计数

var Message = function(options) {
  options = options || {};
  if (typeof options === 'string') { // 参数的兼容处理
    options = {
      message: options
    };
  }

  // this.$message({type: 'info',message: 'test',duration: 2000,onClose (vm){console.info(vm)}})
  let userOnClose = options.onClose; // 暂存用户传递的onclose回调
  let id = 'message_' + seed++; // 实例的标识

  options.onClose = function(vm) { // 重写options.onClose交由Message.close代理一层
    console.info(2)
    Message.close(id, userOnClose);
  };

  instance = new MessageConstructor({ // 创建message实例
    data: options
  });
  instance.id = id;
  instance.vm = instance.$mount(); // 在文档之外渲染
  document.body.appendChild(instance.vm.$el); // 挂载到body
  instance.vm.visible = true; // 设置data.visible为可见
  instance.dom = instance.vm.$el;
  instance.dom.style.zIndex = PopupManager.nextZIndex(); // css z-index层级叠加,覆盖之前已出现但还未close的message
  instances.push(instance);
  return instance.vm;
};

// 给Message增加四个直接调用的方法
// 支持this.$message.success('xxx')方式调用,等同于this.$message({type: 'success',message: 'xxx'})
['success', 'warning', 'info', 'error'].forEach(type => { 
  Message[type] = options => {
    if (typeof options === 'string') {
      options = {
        message: options
      };
    }
    options.type = type;
    return Message(options);
  };
});

// 组件的close方法中调用onClose再调该方法
Message.close = function(id, userOnClose) {
  console.info(3)
  for (let i = 0, len = instances.length; i < len; i++) {
    if (id === instances[i].id) { // 通过id找到该message实例
      if (typeof userOnClose === 'function') {
        userOnClose(instances[i]);
      }
      instances.splice(i, 1); // 移除message实例
      break;
    }
  }
};

export default Message;

<template>
  <transition name="el-message-fade">
    <div class="el-message" v-show="visible" @mouseenter="clearTimer" @mouseleave="startTimer">
      <!--<img class="el-message__icon" :src="typeImg" alt="">-->
      <div class="el-message__group">
        <p>{{ message }}</p>
        <div v-if="showClose" class="el-message__closeBtn el-icon-close" @click="close"></div>
      </div>
    </div>
  </transition>
</template>

<script type="text/babel">
  export default {
    data() {
      return {
        visible: false,
        message: '',
        duration: 3000,
        type: 'info',
        onClose: null,
        showClose: false,
        closed: false,
        timer: null
      };
    },

    computed: {
      /*typeImg() {
        return require(`../assets/${ this.type }.svg`);
      }*/
    },

    watch: {
      closed(newVal) {
        if (newVal) {
          this.visible = false;
          this.$el.addEventListener('transitionend', this.destroyElement);
        }
      }
    },

    methods: {
      destroyElement() {
        this.$el.removeEventListener('transitionend', this.destroyElement);
        this.$destroy(true);
        this.$el.parentNode.removeChild(this.$el);
      },

      close() {
        console.info(1)
        this.closed = true;
        if (typeof this.onClose === 'function') {
          this.onClose(this);
        }
      },

      clearTimer() {
        clearTimeout(this.timer);
      },

      startTimer() {
        if (this.duration > 0) {
          this.timer = setTimeout(() => {
            if (!this.closed) {
              this.close();
            }
          }, this.duration);
        }
      }
    },

    mounted() {
      this.startTimer();
    }
  };
</script>

// main.vue
// ....
methods: {
      destroyElement() {
        this.$el.removeEventListener('transitionend', this.destroyElement);
        this.$destroy(true);
        this.$el.parentNode.removeChild(this.$el);
      },

      close() {
        console.info(1)
        this.closed = true;
        if (typeof this.onClose === 'function') {
          this.onClose(this);
        }
      },
  }
  ....

3点 调用message的时候对象里传了onClose就有
4点 用Message.close来代理处理Message.close
7点 为啥会有个Message,我也不太明白,我去掉以后,直接调onClose也没啥问题。可能是出于防止内存泄漏的原因,这里需要显式的干掉每次弹出Message创建的Instance。

这篇关于javascript - 求解读element-ui源码(vue2.0)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆