The principle of event binding in Vue

When I searched for this principle before, I only wrote two sentences in many articles:

Native event binding is bound to real elements through addEventListener.
Component event binding is achieved through Vue's custom key$on.

How did that happen? Didn’t say?
Let's take a look at it now.

// 原生事件绑定
<div @click="fn()"></div>

// 组件绑定
<my-component @click.native="fn" @click="fn1"></my- component>

Principle:
Compilation of events:

let compiler = require('vue-template-compiler'); //vue-loader
let r1 = compiler.compile('<div @click="fn()"></div>'); 
let r2 = compiler.compile('<my-component @click.native="fn" @click="fn1"></my- component>'); console.log(r1); 
// {on:{click}} console.log(r2); 
// {nativeOn:{click},on:{click}}

The two compiled are not the same

// 前者
with (this){
    
    return _c('div',{
    
    on:{
    
    "click":function($event){
    
    return fn()}}})}

// 后者
with (this){
    
    return _c('my-component',{
    
    on:{
    
    "click":fn1},nativeOn:{
    
    "click":function($event){
    
    return fn($event)}}})}

Insert picture description here

1.1 Binding of native dom

  • Vue will call createElm when creating a real dom, and invokeCreateHooks will be called by default
  • Will traverse the relative attribute processing code under the current platform, including the updateDOMListeners method, and the add method will be passed in internally

Source code:

function updateDOMListeners (oldVnode: VNodeWithData, vnode: VNodeWithData) {
    
     
	if (isUndef(oldVnode.data.on) && isUndef(vnode.data.on)) {
    
     return }
	const on = vnode.data.on || {
    
    } const oldOn = oldVnode.data.on || {
    
    } 
	target = vnode.elm 
	normalizeEvents(on) 
	updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context) 
	target = undefined 
}
function add ( 
	name: string, 
	handler: Function, 
	capture: boolean, 
	passive: boolean 
) {
    
    
	target.addEventListener( // 给当前的dom添加事件 
		name, 
		handler, 
		supportsPassive 
		? {
    
      capture, passive  } 
		: capture 
	) 
}

1.2 Binding events in components

export function updateComponentListeners ( 
	vm: Component, 
	listeners: Object, 
	oldListeners: ?Object 
) {
    
    
	target = vm updateListeners(
		listeners, oldListeners || {
    
    }, 
		add, 
		remove,
		createOnceHandler, vm)
		target = undefined 
}

function add (event, fn) {
    
     
	target.$on(event, fn) 
}

Component binding events are implemented through the custom $on method in vue

1.3 How does $on work?

vm.$on( event, callback )

effect:

Listen for custom events on the current instance. The event can be triggered by vm.$emit. The callback function will receive all the extra parameters of the incoming event trigger function.

principle:

$on adopts the classic publish-subscriber design pattern. First, define an event center, subscribe to events through $on, store the events in the event center, and then trigger the subscription events stored in the event center through $emit.

Vue.prototype.$on = function (event, fn) {
    
    
    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[event] || (vm._events[event] = [])).push(fn)
    }
    return vm
}

Looking at the code, the logic is very simple. The $on function receives two parameters. The first is the name of the subscribed event, which can be multiple. If there are multiple, an array of event names is passed in. The other is the callback function. First, determine whether the incoming event is an array. If it is, then traverse the array and recursively call the $on method for each event in the array to subscribe it as a single event. If it is not an array, treat it as a single event name, use the event name as the key, first try to get the corresponding event list in the _events property of the current instance, if it is not available, give it an empty array as the default Value and add the second parameter callback function.

One more sentence, what is the _events of the instance? This is when the event is initialized, the _event attribute is bound in the initEvents function and assigned an empty object. This _events attribute is used as the event center of the current instance, and all events bound to this instance will be stored in the event center _events attribute.

This is the internal principle of $on.

Guess you like

Origin blog.csdn.net/Beth__hui/article/details/114089801