深入浅出Vue实例事件方法(简单易学)
2020/4/17 11:07:08
本文主要是介绍深入浅出Vue实例事件方法(简单易学),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
简介
大家好,我是六六。今天分析关于Vue实例事件相关的方法。与事件相关的实例方法有四个,vm.$on,vm.$emit,vm.$once,vm.$off。这四个方法都挂载到Vue的prototype属性上,接下里我们详细的讲一讲:
目录
- vm.$on
- vm.$once
- vm.$off
- vm.$emit
- 总结
1. vm.$on
vm.$on( event, callback )
参数:
- {string | Array} event (数组只在 2.2.0+ 中支持)
- {Function} callback
用法:
监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。
示例:
vm.$on('test', function (msg) { console.log(msg) }) vm.$emit('test', 'hi') // => "hi" 复制代码
实现:
其实通过用法我们就知道,可以先把事件的回调函数先收集起来,等到事件触发时,我们从收集的回调函数取出来执行就好了。所以,我们就需要一个对象来存储这些回调函数。事实上,在执行new Vue()时,Vue会执行this._init进行一系列初始化工作,其中就会在实例上创建一个_events属性,来存储事件以及相应的回调函数。
vm._events=Object.create(null) 复制代码
知道了基本原理,我们手动实现一下:
Vue.prototype.$on=function(event,fn){ const vm=this if(Array.isArray(fn)){ for(let i=0,j=event.length;i<j;i++){ this.$on(event,fn[i]) } }else{ (vm._events[event]||(vm.events[event]=[])).push(fn) } return vm } 复制代码
解析:首先我们会先判断event参数是否为数组,然后遍历数组,再继续递归调用,之后将event作为属性名传入vm._events并且属性值为一个数组,接着就将回调函数push进去。等待被触发。
2. vm.$off
vm.$off( [event, callback] )
参数:
- {string | Array} event (只在 2.2.2+ 支持数组)
- {Function} [callback]
用法:
移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
如果只提供了事件,则移除该事件所有的监听器;
如果同时提供了事件与回调,则只移除这个回调的监听器。
实现:
通过用法我们知道vm.$off是用于移除事件的,并且对于参数的不同有三种情况要分析。
2.1 无参数:移除所有事件
Vue.prototype.$off=function(event,fn){ const vm=this if(arguments.length===0){ vm._events=Object.create(null) return vm } return vm } 复制代码
只要满足了arguments.length===0德情况,vm._events属性就会被重置,等于null.之前绑定的所有回调和事件都清楚了。
2.2 二个参数:移除该事件的监听器
Vue.prototype.$off=function(event,fn){ const vm=this // 无参数 if(!arguments){ vm._events=Object.create(null) return vm } // 新增 // 传递事件名和回调函数 else if(fn && typeof event==='string'){ const cbs=vm._events[event] let j=cbs.length for(let i=0;i<j;i++){ // if(fn===cbs[i]||cbs[i].fn===fn){ cbs.splice(i,1) return } } } return vm } 复制代码
首先判断参数evnet为字符串和有回调函数,通过循环该事件的数组,找到该回调函数并使用splice方法移除。
2.3 一个参数:移除该事件的所有监听器
Vue.prototype.$off=function(event,fn){ const vm=this // 无参数 if(!arguments){ vm._events=Object.create(null) return vm } // 新增 // 一个参数 else if(arguments.length===1){ const e=arguments[0] //判断是否为数组 if(Array.isArray(e)){ for(let i=0,j=e.length;i<j;i++){ this.$off(e[i]) } }else{ vm._events[event]=null return vm } } // 传递事件名和回调函数 else if(fn && typeof event==='string'){ const cbs=vm._events[event] let j=cbs.length for(let i=0;i<j;i++){ // if(fn===cbs[i]||cbs[i].fn===fn){ cbs.splice(i,1) return } } } return vm } 复制代码
因为event参数可以为数组或者字符串,所以需要分情况讨论,是数组的话循环加递归就,找到该事件,指向null就移除了。
3. vm.$emit
vm.$emit( eventName, […args] )
参数:
- { string} eventName
- [...args]
用法:
触发当前实例上的事件。附加参数都会传给监听器回调。
实现:
我们知道所有事件监听的回调函数都存储在vm._events里面,那么我们只需要根据事件名找到他们,依次执行列表中的函调函数即可,并将参数传入回调函数。
Vue.prototype.$emit=function(event){ const vm=this let cbs=vm._events[event] if(cbs){ const args=toArray(arguments,1) for(let i=0,j=cbs.length;i<j;i++){ try{ cbs[i].apply(vm,args) }catch(e){ console.log(e) } } } return vm } 复制代码
其实也是很简单,toArray的作用就是将类似于数组的数据转换成真正的数组,第二个参数作为起始位置。
4. vm.$once
vm.$once( event, callback )
参数:
- {string} event
- {Function} callback
用法:
监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。
实现:
vm.$once和 vm.$on的区别就是前者只能实现一次,所以我们就可以当自定义触发了执行拦截器,删除这个监听器并执行一次。
Vue.prototype.$once=function(event,fn){ const vm=this function on (){ vm.$off(event,on) fn.apply(vm,arguments) } on.fn=fn vm.$on(event,on) return vm } 复制代码
我们在vm.$once中使用vm.$on来监听事件。首先我们是将on函数注册到事件中的(这点很重要,并不是fn).当自定义事件被触发时,我们会执行on函数,在这个函数里首先将自己移除掉,在执行fn.所以这个自定义事件就只执行一次。
问题:
我们仔细看一下代码,我们注册的是on函数,但是用户如果通过vm.$off移除的不是on函数啊,而是fn函数。但是fn函数我们没有注册啊,注册的是on函数(用户不知道on函数的存在),所以此时我们可以给on添加一个属性fn为fn这个函数on.fn=fn
,在进行删除时,我们可以判断次函数的fn属性即可:
fn===cbs[i]||cbs[i].fn===fn 复制代码
on函数属性fn正是用户手写的函数,所以可以完美的解决了函数不相同的问题了。
5 总结
不想只做api的搬运工,想要更深入原理的去理解。如果本文有什么问题请大家及时提出来哦。
此文参考《深入浅出Vue.js》
这篇关于深入浅出Vue实例事件方法(简单易学)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-04package.json 文件位置在哪?-icode9专业技术文章分享
- 2024-10-01Craco.js学习:从入门到实践指南
- 2024-10-01Create-React-App学习:入门与实践指南
- 2024-10-01CSS-in-JS学习:从入门到实践指南
- 2024-09-30JSX语法学习:从入门到初步掌握
- 2024-09-30Mock.js学习:入门教程与实战演练
- 2024-09-30React Hooks学习:从入门到实践
- 2024-09-30受控组件学习:React中的基础入门教程
- 2024-09-29JS定时器教程:初学者必看指南
- 2024-09-29JS对象教程:初学者的全面指南