-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
由Vue的API可知
vm.$on监听当前实例上的自定义事件
vm.$once监听当前实例上的事件,但是只触发一次,在第一次触发后就移除监听器
vm.$off移除自定义事件监听器
- 不传任何参数则移除当前实例上所有的事件监听器
- 如果只提供了事件,则移除该事件所有的监听器
- 如果同时提供了事件与回调,则只移除这个回调的监听器
vm.$emit触发当前实例上的事件
那么我们来看看源码吧
vm._events = Object.create(null) // vm._events初始化为一个对象
vm._hasHookEvent = false
// 标志位 是否监听了生命周期钩子事件 beforeCreate等
export function eventsMixin (Vue: Class<Component>) {
const hookRE = /^hook:/
监听事件
Vue.prototype.$on = function (event: string | Array<string>, fn: Function): Component {
const vm: Component = this
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.$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
}
}
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++) {
this.$off(event[i], fn)
}
return vm
}
// specific event
const cbs = vm._events[event]
if (!cbs) {
return vm
}
if (arguments.length === 1) {
vm._events[event] = null // 移除特定事件监听
return vm
}
if (fn) { // 移除特定事件的特定处理函数
// specific handler
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
if (process.env.NODE_ENV !== 'production') {
const lowerCaseEvent = event.toLowerCase()
if (lowerCaseEvent !== event && vm._events[lowerCaseEvent]) {
tip(
`Event "${lowerCaseEvent}" is emitted in component ` +
`${formatComponentName(vm)} but the handler is registered for "${event}". ` +
`Note that HTML attributes are case-insensitive and you cannot use ` +
`v-on to listen to camelCase events when using in-DOM templates. ` +
`You should probably use "${hyphenate(event)}" instead of "${event}".`
)
}
}
let cbs = vm._events[event]
if (cbs) {
// toArray函数的作用时转换一个类数组对象为真正的数组
cbs = cbs.length > 1 ? toArray(cbs) : cbs
const args = toArray(arguments, 1)//去掉第一个参数(事件名)
for (let i = 0, l = cbs.length; i < l; i++) {
try {
cbs[i].apply(vm, args)// 执行事件处理函数
} catch (e) {
handleError(e, vm, `event handler for "${event}"`)
}
}
}
return vm
}
}
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels