Vue 事件的高级使用方法

事件方法

在Vue中提供了4中事件监听方法,分别是:

  • $on(event: string | Array, fn)
  • $emit(event: string)
  • $once(event: string, fn)
  • $off(event?: string|Array, fn?)

1. $on

监听当前实例上的自定义事件。事件可以由 vm.$emit 触发。回调函数会接收所有传入事件触发函数的额外参数。

从上述传参可以看出。第一个参数可以传递一个字符串,或者一个数组,如果传递的是数组,则会对数组中的每一个事件进行监听,只要有一个触发,就会执行后面的回调函数

mounted () {
this.$on('event1', () => {
console.log('ok');
}); this.$on(['event1', 'event2', 'event3'], () => {
console.log('ok');
}); setTimeout(() => {
this.$emit('event1');
}, 1000);
}

当调用 $emit 之后,两个 $on 都会被触发

2. $emit

触发当前实例上的事件。附加参数都会传给监听器回调。

此处的用法非常简单,可以和 $on 配合使用,也可以和组件中的自定义事件配合使用

Vue.component('welcome-button', {
template: `
<button v-on:click="$emit('welcome')">
Click me to be welcomed
</button>
`
}); <div id="emit-example-simple">
<welcome-button v-on:welcome="sayHi"></welcome-button>
</div> methods: {
sayHi: function () {
alert('Hi!')
}
}

3. $once

监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。

4. $off

移除自定义事件监听器

  • 如果没有提供参数,则移除所有的事件监听器;
  • 如果只提供了事件,则移除该事件所有的监听器;
  • 如果同时提供了事件与回调,则只移除这个回调的监听器。

高级用法

1. 使用$on $emit 实现跨组件通信

有时两个组件隔的比较远的情况下,可以通过这两个组件的共同父元素,或者跟节点来派发和监听事件,达到通信的效果。

// components A
<div>
<button @click="clickHandler">click me</button>
</div> export default {
name: 'componentsA',
method: {
clickHandler() {
this.$root.$emit('my-events');
}
}
} // components B
export default {
name: 'componentsB',
mounted () {
this.$root.$on('my-events', () => {
console.log('ok');
});
}
}
// 这里的$root可以换成共同的父元素

2. hookEvents

父组件可以直接通过自定义事件的形式监听子组件中声明周期钩子的变化,固定写法 <componentsA @hook:update="func" />, 目的是当使用了第三方组件,还想要知道里面的生命周期触发了。可以使用此方法监听

// child Events
export default {
name: 'Events2',
data () {
return {
counter: 0
};
},
mounted () {
setTimeout(() => {
this.counter += 1;
}, 2000);
},
updated () {
console.log('update');
}
}; // parent components
<Event2 @hook:updated="updateCounter"/> export default {
components: {
Events2
},
methods: {
updateCounter () {
console.log('hooks ok');
}
}
}

源码分析

  1. 定义事件源码位置:vue/src/core/instance/events.js
export function eventsMixin (Vue: Class<Component>) {
const hookRE = /^hook:/ // hookEvent
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component { // 除了可以使用字符串,还可以监听一个数组,['event1', 'event2']
const vm: Component = this
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
vm.$on(event[i], fn)
}
} else {
// 把事件名称和回调函数存入vm._events中
(vm._events[event] || (vm._events[event] = [])).push(fn) // 一个事件可以对应多个回调函数
// optimize hook:event cost by using a boolean flag marked at registration
// instead of a hash lookup
if (hookRE.test(event)) { // 监听生命周期的钩子事件
vm._hasHookEvent = true // 只要有人监听这个事件。在callHooks中就是会派发一个事件
}
}
return vm
} Vue.prototype.$once = function (event: string, fn: Function): Component {
const vm: Component = this
function on () {
vm.$off(event, on) // 执行一次回调函数后就立刻结束
fn.apply(vm, arguments)
}
on.fn = fn
vm.$on(event, on)
return vm
} Vue.prototype.$off = function (event?: string | Array<string>, fn?: Function): Component {
const vm: Component = this
// all
if (!arguments.length) { // 无参数,清除所有的事件监听
vm._events = Object.create(null)
return vm
}
// array of events
if (Array.isArray(event)) { // 传入的数组,把相关的事件移除
for (let i = 0, l = event.length; i < l; i++) {
vm.$off(event[i], fn)
}
return vm
}
// specific event 解除特定事件
const cbs = vm._events[event]
if (!cbs) {
return vm
}
if (!fn) { // 如果用户没指定fn参数,相关的所有回调都清除
vm._events[event] = null
return vm
}
// specific handler // 如果用户指定fn参数,只移除对应的回调
let cb
let i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
return vm
} Vue.prototype.$emit = function (event: string): Component { // 事件派发
const vm: Component = this
let cbs = vm._events[event]
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)
const info = `event handler for "${event}"`
for (let i = 0, l = cbs.length; i < l; i++) {
invokeWithErrorHandling(cbs[i], vm, args, vm, info)
}
}
return vm
}
}
  1. 派发hookEvents位置:vue/src/core/instance/lifecycle.js
export function callHook (vm: Component, hook: string) {
if (vm._hasHookEvent) { // 如果标记了钩子事件,则额外的派发一个自定义的事件出去
vm.$emit('hook:' + hook) // 比如:@hook:update="xxx"
}
}

测试代码地址:https://github.com/Shenjieping/vue-events

Vue 事件的高级使用方法的更多相关文章

  1. vue事件绑定处理

    事件监听指令 v-on 指令监听 DOM 事件来触发一些 JavaScript 代码,通常是触发一个函数,简写@ <template> <div id="app" ...

  2. Vue2.x源码学习笔记-Vue实例的属性和方法整理

    还是先从浏览器直观的感受下实例属性和方法. 实例属性: 对应解释如下: vm._uid // 自增的id vm._isVue // 标示是vue对象,避免被observe vm._renderProx ...

  3. vue解决遮罩层滚动方法

    vue 遮罩层阻止默认滚动事件 在写移动端页面的时候,弹出遮罩层后,我们仍然可以滚动页面. vue中提供 @touchmove.prevent 方法可以完美解决这个问题 <div class=& ...

  4. 设计能长按并有动画效果且能触发事件的高级view

    设计能长按并有动画效果且能触发事件的高级view 效果图: 源码: LongTapAnimationView.h 与 LongTapAnimationView.m // // LongTapAnima ...

  5. vue中methods中的方法闭包缓存问题

    vue中methods中的方法闭包缓存问题 问题背景 需求描述 在路由的导航栏中需要, 判断是否为第一次点击 需要一个标志位来记录是否点击过 现状: 这个标志位只在一个函数中用过.不希望存放全局 希望 ...

  6. vue 父子组件传值以及方法调用,平行组件之间传值以及方法调用大全

    vue项目经常需要组件间的传值以及方法调用,具体场景就不说了,都知道.基本上所有的传值都可以用vuex状态管理来实现,只要在组件内监听vuex就好. vue常用的传值方式以及方法有: 1. 父值传子( ...

  7. Vue 事件监听实现导航栏吸顶效果(页面滚动后定位)

    Vue 事件监听实现导航栏吸顶效果(页面滚动后定位) Howie126313 关注 2017.11.19 15:05* 字数 100 阅读 3154评论 0喜欢 0 所说的吸顶效果就是在页面没有滑动之 ...

  8. vue事件修饰符(once:prev:stop)

    vue事件修饰符(once:prev:stop) stop修饰符  效果如下: 当你鼠标在这个div里的时候,x与y的值:会随着鼠标的变化而变化.但是当鼠标放在stopMoving的时候,x与y的值是 ...

  9. Vue事件绑定原理

    Vue事件绑定原理 Vue中通过v-on或其语法糖@指令来给元素绑定事件并且提供了事件修饰符,基本流程是进行模板编译生成AST,生成render函数后并执行得到VNode,VNode生成真实DOM节点 ...

随机推荐

  1. 37 Reasons why your Neural Network is not working

    37 Reasons why your Neural Network is not working Neural Network Check List 如何使用这个指南 数据问题 检查输入数据 试一下 ...

  2. 制作 macOS Sierra U盘USB启动安装盘方法教程 (亲测)

    备注:相关镜像到apple官网下载 https://discussionschinese.apple.com/thread/250596904 进去点击"请使用这个 App Store 链接 ...

  3. Web优化躬行记(4)——用户体验和工具

    一.用户体验 用户体验(UE/UX)是指一个人使用一个特定产品.系统或服务时的行为.情绪与态度,还包含用户对于系统的功能.易用和效率的感受,因此用户体验在本质上可以视为一个人对于系统的主观感受与主观想 ...

  4. zabbix-4.4.4安装教程(亲测可用)

    1.首先添加yum源zabbix.repo [zabbix]name=zabbixbaseurl=https://mirrors.tuna.tsinghua.edu.cn/zabbix/zabbix/ ...

  5. 记好这 24 个 ES6 方法,用来解决实际开发的 JS 问题

    本文主要介绍 24 中 es6 方法,这些方法都挺实用的,本本请记好,时不时翻出来看看. 1.如何隐藏所有指定的元素 const hide = (el) => Array.from(el).fo ...

  6. PHP文件包含学习笔记

    看完下面的几篇文章,然后从第8行开始以后的内容可以忽略!此文是个笔记梳理,是对大佬文章简单的COPY记录,方便以后查看,自己只复现了其中的例子 参考文章: PHP文件包含漏洞利用思路与Bypass总结 ...

  7. linux驱动之内核多线程(四)

    本文摘自 http://www.cnblogs.com/zhuyp1015/archive/2012/06/13/2548494.html 自己创建的内核线程,当把模块加载到内核之后,可以通过:ps ...

  8. Jmeter 常用函数(17)- 详解 __substring

    如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.htm 作用 从字符串中获取指定范围的子串 语法格式 ...

  9. openvswitch 监听端口变化

    命令: ovsdb-client monitor Interface name,ofport,external_ids --format=json 运行效果: [root@ostack1 ~]# ov ...

  10. 基于 abp vNext 微服务开发的敏捷应用构建平台 - 项目介绍

    缘起 目前使用ABP框架已经将近3年了,大大小小的项目也陆陆续续做了很多.由于现有信息系统的架构模式是在底层的技术平台上直接构建信息系统并采用技术主导,使用业务无关的编程工具来开发信息系统的缺陷使得系 ...