写文章不容易,点个赞呗兄弟 专一 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工做原理,源码版助于了解内部详情,让咱们一块儿学习吧 研究基于 Vue版本 【2.5.17】app
若是你以为排版难看,请点击 下面连接 或者 拉到 下面关注公众号也能够吧dom
Vue 的自定义事件很简单,就是使用 观察者模式 进行事件的监听和分发函数
Vue 封装的这个观察者模式,能够说是很完善了,这个能够独立抽取出来的在其余项目中使用的代码,只须要作一点点改动,把事件存储器换个地方(Vue 放在了实例上)学习
我常常在项目中使用,就是为了解耦或者解决一些异步的问题this
今天来详细探索 Vue 的 自定义事件prototype
首先,Vue 的事件存储器放在那里?3d
没错,放在 vm._events 中code
你看,好比你这样监听事件blog
看到实例上保存了你的事件
vm._events
看下这个事件存储器在哪里生成的
首先,实例在初始化的时候,给实例增长一个事件存储器 _events
Vue.prototype._init = function(options) { initEvents(vm); //...初始化选项数据,解析模板,挂载dom等 } function initEvents(vm) { vm._events = Object.create(null); }
之后,全部这个实例监听的事件,就都存在这里了
那么,接下来就来看 自定义事件的源码了
下面的源码比较不太属于 Vue 的内容,比较独立,很实用,相信你们也都看得懂,这里主要起一个记录的做用
绑定事件,$on
一次性绑定事件,$once
触发事件,$emit
解绑事件,$off
注册事件,接收 事件名和回调,很清楚了,都能看得懂
Vue.prototype.$on = function(event, fn) { var vm = this; if (Array.isArray(event)) { for (var i = 0,l = event.length; i < l; i++) { this.$on(event[i], fn); } } else { (vm._events[event] || (vm._events[event] = [])).push(fn); } // 为了链式调用 return vm };
单次注册。只监听一次,触发以后立刻销毁
它妙就妙在,把回调包装了一下,在 回调执行时,先解绑事件,再调用原回调
Vue.prototype.$once = function(event, fn) { var vm = this; function on() { vm.$off(event, on); fn.apply(vm, arguments); } on.fn = fn; vm.$on(event, on); // 为了链式调用 return vm };
触发事件,接收事件名,而后拿到本来设置的回调,遍历调用
Vue.prototype.$emit = function(event) { var vm = this; var _events= event.toLowerCase(); var cbs = vm._events[_events]; if (cbs) { cbs = cbs.length > 1 ? toArray(cbs) : cbs; var args = toArray(arguments, 1); for (var i = 0, l = cbs.length; i < l; i++) { cbs[i].apply(vm, args); } } // 为了链式调用 return vm };
取消监听事件或者移除监听回调
接收事件名 和 绑定时的事件回调
很简单的啦
Vue.prototype.$off = function(event, fn) { var vm = this; if (!arguments.length) { vm._events = Object.create(null); return vm } // 递归调用 if (Array.isArray(event)) { for (var i = 0, l = event.length; i < l; i++) { this.$off(event[i], fn); } return vm } var cbs = vm._events[event]; if (!cbs) return vm if (!fn) { vm._events[event] = null; return vm } // 去掉特定的函数 if (fn) { var cb; var len = cbs.length; // 遍历移除相应回调 while (len--) { cb = cbs[len]; if (cb === fn || cb.fn === fn) { cbs.splice(len, 1); break } } } // 为了链式调用 return vm };