手撸一个vue toast提示框组件及VueBusevent组件vue-happy-bus源码解读,你还不知道的Busevent的使用方法

765 阅读5分钟

前言

        哈喽大家好啊,又有一周不见了呢,这周我们要讲的是个内容一个是上上周讲到的VueBusevent的组件vue-happy-bus的源码解读另外就是手撸一个toast提示框组件。

vue-happy-bus源码解读

        如果没有看过vue-happy-bus使用方法的同学请去看看我的这个文章,里面讲vue-happy-bus的使用方法还是比较适合初学者的。

Vue eventbus 使用中的重复触发解决方案及存在的Bug

        首先说明下面对源码的解读仅代表我的个人观点,如果大家有兴趣还是自己去理解源码,或者在下面讨论区积极评论和讨论,我会随时关注和修改该内容的。

        这里注意一下下面的注释,我把我的理解写在下面的注释里面热,但是还是有些不尽人意的,这里欢迎大家指正。


(function (global, factory) {
    //这里其实就是在判断数据类型,为下面的function准备参数Vue$和exports这两个将要传入下面的function
	typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue')) :
	typeof define === 'function' && define.amd ? define(['exports', 'vue'], factory) :
	(factory((global['happy-bus'] = {}),global.Vue$));
    //	这里规定对象为window,则可以判断window对象是否是绑定了Vue原型,注意这里是严格模式
}(this, (function (exports,Vue$) { 'use strict';
//严格模式下Vue$和Vue$判断自身是否存在default属性,存在Vue$就是efaul,否则只是Vue$本身
Vue$ = Vue$ && Vue$.hasOwnProperty('default') ? Vue$['default'] : Vue$;
//定义版本号
var version = "0.1.0";
//判断window对象是否绑定Vue
var Vue = Vue$;
if (typeof window !== 'undefined' && window.Vue) {
  Vue = window.Vue;
}

// 记录所有的事件类型与事件函数,这里新建了一个Vue作为事件总集
var EventStore = {};
var Bus = new Vue();

// 移除所有事件的方法
var destroyHandler = function destroyHandler() {
  // this 为调用此方法的vue组件
  var currentEventObj = EventStore[this._uid];
  if (typeof currentEventObj === 'undefined') {
    return;
  }
  for (var type in currentEventObj) {
    var key = Array.isArray(type) ? type.join(',') : type;
    // Bus 解绑事件,在调用bus.$emit后直接调用bus.$off事件
    Bus.$off(type, currentEventObj[key]);
  }
  // 删除记录的事件集合
  delete EventStore[this._uid];
};

//定义BusFactory的整体使用方法,分为四个$on,$off,$once,$emit四种。
var BusFactory = function BusFactory(vm) {
  // 当前调用组件的 destroyed 钩子,以销毁方法
  var destroyed = vm.$options.destroyed;
  // 当前组件的唯一标示(vue生成的自增ID),自增id可以做项目的时候看看比如css样式上就有显示
  var uid = vm._uid;
  // 初始化当前组件的事件集合对象
  EventStore[uid] = {};
  // 为当前组件挂载destroyed钩子
  !destroyed.includes(destroyHandler) && destroyed.push(destroyHandler);

  return {
    $on: function $on(type, handler) {
      //取到所有的bus.$emit
      console.log(type, handler)
      var key = Array.isArray(type) ? type.join(',') : type;
      // 循环取出bus.$emit的键值
      console.log(key)
      EventStore[uid][key] = handler;
      //找出bus.$on的使用方法类似于(em) => {
      //  console.log(em)//这样的
      // }
      //这个方法也是取到bus.$on的本身
      console.log(EventStore[uid][key])
      Bus.$on(type, handler);
    },
    //删除合集就不用说了吧,判断type的true或者false即可,就能删除事件合集
    $off: function $off(type, handler) {
      // $off() 时 type 为空,移除所有事件
      if (!type) {
        // 删除该uid下事件集合
        delete EventStore[uid];
        Bus.$off();
        return;
      }
      //其实每个key删除合集都是对应的那个键值删除。删除整个事件合集即可。
      var key = Array.isArray(type) ? type.join(',') : type;
      // 删除对应的事件
      delete EventStore[uid][key];
      Bus.$off(type, handler);
    },
    $once: function $once() {
      //相信我不用多说了吧ones方法只能被调用一次所以也是不存在什么删除的方法的,不过为了以防万一和内存过多的占用只能删除合集才行
      return Bus.$once.apply(Bus, arguments);
    },
    $emit: function $emit() {
      //这个就更好说了,传递方式直接进行传递就行.
      return Bus.$emit.apply(Bus, arguments);
    }
  };
};

BusFactory.$emit = function () {
  //定义emit方法
  return Bus.$emit.apply(Bus, arguments);
};
BusFactory.$once = function () {
  //定义once方法
  return Bus.$once.apply(Bus, arguments);
};

exports['default'] = BusFactory;
exports.version = version;

Object.defineProperty(exports, '__esModule', { value: true });


//最后讲一下BusFactory方法可以通过main.js进行全局绑定这个上上周的文章里已经讲过,可以去看看我上上周的文章
})));

        注意一下这里面注册了四个方法$on,$off,$once,$emit,比较重要的是$off事件在使用完$on事件之后直接在destroyed自动注册了一个销毁事件,这样的方式是比较好的不用我们手动注册销毁它自动进行匹配和销毁操作,在这里销毁之后不用担心二次触发的问题,只要安心去管理好你的传输的值就好。

        这里比较好的一个写法我认为是在创建$emit事件的时候它自动注册了一个$off方法在使用完$emit方法之后直接使用循环查出正在使用$on方法接收的参数,之后在使用完$on方法之后直接在内部进行了销毁,并不会影响二次调用,不过这个组件在解决小项目的时候比较适用,或者在解决项目前期解决紧急上线的时候使用比较好。

手撸一个vue toast提示框组件

        讲一下思路,初始是在想浏览器的默认弹出框太难看了,所以要做一个不用点击的全局提示,所以toast提示框组件就应运而生了,下面讲讲整体思路。

        首先我们在某个验证情况下需要,有各种不同的提示比如,绿色的完成提示,又或者是红色的错误提示,那么我们思路有了,提示都是由一个提示语和显示的颜色组成的,那么这个组件就是需要传入两个参数,第一个提示标题框的颜色,第二个提示语。

        首先创建一个toast.js,里面的写法跟普通的js写法相同


//这里就是两个参数传入一个颜色一个提示语
function toast(color, text){
    //创建一个div之后把参数上的提示语放上去再加入颜色
	const body = document.getElementsByTagName('body')
	const toast = document.createElement("div")
	toast.innerText = text
	toast.className = 'toast' +" "+ color
	document.body.appendChild(toast)
    //定义一个显示时间多少秒之后消失
	setTimeout(function(){
		document.body.removeChild(toast)
	}, 5000)
}
exports.toast= toast;

        接下来就是css


.toast {
    position: fixed;
    top: -100px;
    left: 50%;
    margin-left: -199px;
    width: 398px;
    height: 50px;
    animation: myfirst 5s;
    animation-direction:alternate;
    z-index: 9999999999;
    text-align: center;
}
.toast.red {
    background-color: #fbe7ea;
    border: 1px solid #e57785;
    line-height: 50px;
    color: #e57785;
}
.toast.blue {
    background-color: #c5eafb;
    border: 1px solid #0083ae;
    line-height: 50px;
    color: #0083ae;
}
.toast.green {
    background-color: #dff0d7;
    border: 1px solid #378d4e;
    line-height: 50px;
    box-sizing: border-box;
    color: #378d4e;
}
#toast_close{
    cursor: pointer;
    display: block;
    float: right;
    width: 50px;
    height: 50px;
    text-align: center;
    font-size: 30px;
    position: absolute;
    top: 0;
    right: 0;
}
@keyframes myfirst
{
    0% {top: -200px;display: block;}
    25% {top: 100px;}
    50% {top: 100px;}
    75% {top: 100px;}
    100% {top: -200px;}
}

        之后是在全局引入


//main.js
...
//这里部分的就不做演示了,只演示引入部分
import './lib/toast/toast.css'
import toast from './lib/toast/toast.js'
//把toast.js挂载在原型上进行引用
Vue.prototype.$toast = toast;

        创建a.vue

<template>
    <button v-on:click="toast()">提示</button>
</template>
 export default {
        name: '',
        data: function () {
        
        },
        methods: {
            toast:function(){
                this.$toast.toast('green', '看到了吗,这就是toast提示框')
            }
        }
 }
<script>

</script>

<style>

</style>

        这样调用就完成了,其实非常简单封装vue组件,但是我这个仅适用于我的项目使用,封装还不够完美,另外可以用mixinsqu封装,也可以用vue专门暴露出的方法进行封装,我这里只是作为一个演示,并不代表只有这一种方法可行,另外有兴趣可以去了解一下我之前写过的Vue mixins浅谈使用方法及需要注意的点,下面有链接。

Vue mixins浅谈使用方法及需要注意的点

后记

        感觉今天讲的 有些少,但是文章不在于写多少字而在于它的质量是否精湛,只有这点就足够了,好了有问题需要讨论的个位,请在下面评论区讨论,谢谢,我先闪了去撸vue-router了,这里做个预告下周我会浅析讲解vue-router的使用。