以前にこの原則を検索したとき、私は多くの記事に2つの文しか書きませんでした。
ネイティブイベントバインディングは、addEventListenerを介して実際の要素にバインドされます。
コンポーネントイベントのバインドは、Vueのカスタムkey $ onを介して実現されます。
それはどのように起こったのですか?
それを見てみましょう。
// 原生事件绑定
<div @click="fn()"></div>
// 组件绑定
<my-component @click.native="fn" @click="fn1"></my- component>
原則:
イベントの編集:
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}}
コンパイルされた2つは同じではありません
// 前者
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)}}})}
1.1ネイティブdomのバインディング
- Vueは実際のDOMを作成するときにcreateElmを呼び出し、invokeCreateHooksはデフォルトで呼び出されます
- updateDOMListenersメソッドを含む、現在のプラットフォームでの相対属性処理コードをトラバースし、addメソッドは内部で渡されます
ソースコード:
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コンポーネントのバインディングイベント
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)
}
コンポーネントバインディングイベントは、vueのカスタム$ onメソッドを介して実装されます
1.3 $ onはどのように機能しますか?
vm.$on( event, callback )
効果:
現在のインスタンスでカスタムイベントをリッスンします。イベントはvm。$ emitによってトリガーできます。コールバック関数は、着信イベントトリガー関数のすべての追加パラメーターを受け取ります。
原理:
$ onは、従来のパブリッシュ/サブスクライバーデザインパターンを採用しています。まず、イベントセンターを定義し、$ onを介してイベントをサブスクライブし、イベントをイベントセンターに格納してから、$ 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
}
コードを見ると、ロジックは非常に単純です。$ on関数は2つのパラメーターを受け取ります。最初のパラメーターは、サブスクライブされたイベントの名前であり、複数の場合があります。複数ある場合は、イベント名の配列が渡されます。もう1つはコールバック関数です。まず、着信イベントが配列であるかどうかを判断します。配列である場合は、配列をトラバースし、配列内の各イベントに対して$ onメソッドを再帰的に呼び出して、単一のイベントとしてサブスクライブします。配列でない場合は、単一のイベント名として扱い、イベント名をキーとして使用します。まず、現在のインスタンスの_eventsプロパティで対応するイベントリストを取得しようとします。使用できない場合は、空にします。配列をデフォルト値として使用し、2番目のパラメーターコールバック関数を追加します。
もう1つの文、インスタンスの_eventsは何ですか?これは、イベントが初期化されるときに、_event属性がinitEvents関数にバインドされ、空のオブジェクトが割り当てられるときです。この_events属性は、現在のインスタンスのイベントセンターとして使用され、このインスタンスにバインドされているすべてのイベントは、イベントセンターの_events属性に格納されます。
これが$ onの内部原則です。