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. 栈及其简单应用(python代码)

    栈属于线性结构(Linear Struncture),要搞清楚这个概念,首先要明白”栈“原来的意思,如此才能把握本质."栈“者,存储货物或供旅客住宿的地方,可引申为仓库.中转站,所以引入到计 ...

  2. Java 8中Lambda表达式默认方法的模板方法模式,你够了解么?

    为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行.在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容. 模板 ...

  3. sourcetree关于注册的问题

    当前只有Win的版本,Mac自行百度(笑) 很多人用git命令行不熟练,那么可以尝试使用sourcetree进行操作. 然鹅~~sourcetree又一个比较严肃的问题就是,很多人不会跳过注册或者操作 ...

  4. ES6系列之项目中常用的新特性

    ES6系列之项目中常用的新特性 ES6常用特性 平时项目开发中灵活运用ES6+语法可以让开发者减少很多开发时间,提高工作效率.ES6版本提供了很多新的特性,接下来我列举项目中常用的ES6+的特性: l ...

  5. Golang 解析Yaml格式

    Golang官方并没有提供Yaml解析包,所以需要使用第三方包.可用的第三方包有不少,这里选择的是 gopkg.in/yaml.v2,这个包在github上有不少的star,也的确挺好用.其使用的是A ...

  6. IT技术人,“三十而已”

    最近电视剧<三十而已>热播,我家的电视机自然也是被霸屏,我还是跟着妹纸看了看,开头和结局完整看完,中间看了一点,大部分都是在微信公众号上通过别人的文章看完的.我个人也已经30+了,今天也和 ...

  7. 机器学习:支持向量机(SVM)

    SVM,称为支持向量机,曾经一度是应用最广泛的模型,它有很好的数学基础和理论基础,但是它的数学基础却比以前讲过的那些学习模型复杂很多,我一直认为它是最难推导,比神经网络的BP算法还要难懂,要想完全懂这 ...

  8. 浏览器自动化的一些体会6 增强的webBrowser控件

    这里谈两点 1.支持代理服务器切换 一种方法是修改注册表,不是太好的做法,而且,只能改全局设置,不能改局部(比如只让当前的webBrowser控件使用代理,而其他应用不用代理) 另外一个较好的方法,示 ...

  9. [NOIP2019] 划分

    题目 题解 首先YY一个最简单的dp $dp[i][j]=min(dp[j][k]+(sum[i]-sum[j])^2 (sum[i]-sum[j]>=sum[j]-sum[k])$ $dp[i ...

  10. css3 属性 text-overflow 实现截取多余文字内容 以省略号来代替多余内容

    css3 属性 text-overflow: ellipsis 前言 正文 结束语 前言 我们在设计网站的时候有时会遇到这样一个需求:因为页面空间大小的问题,需要将多余的文字隐藏起来,并以省略号代替, ...