vueイベント関連インスタンスメソッドソース分析
24137 ワード
vm.$on
-vueインスタンス登録イベントのapi
まず,伝達されたeventがイベント配列であるか否かを判断し,もしそうであれば再帰的な考え方でvueインスタンスにイベントを登録する.単一のイベント文字列の場合、イベントが登録されているかどうかを判断し、登録されていない場合は、イベントに空の配列を初期化します.その後、fnすなわちコールバック関数を配列に押し込む.
vm.$off
-vueインスタンスログアウトイベントのapi
分別討論の思想.1.パラメータが入力されていない場合は、イベントリストを直接空にします.作者の考え方は、Object.create方式は、新しいイベントを格納するvueインスタンス属性を生成する.2.入力がイベント配列である場合、構想はonと同じであり、再帰的にログアウトする.3.特判部分(specific event部分)は、このイベントが登録されていない場合は、直接戻ります.ログアウトしたい指定したイベントのコールバックがない場合は、対応するイベント配列を空にします.4.最後に、イベントが送信され、パラメータが送信された場合について説明します.著者らの構想は,逆シーケンスで配列を遍歴し,spliceでイベントコールバックを削除することである.どうしてそうするの?もし遍歴していて、1つの数を削除したばかりで、後ろの数が自動的に前にシフトしたら、私たちは遍歴したことのないコールバックをスキップします.つまり、最後のコールバックを削除する以外は、順方向に遍歴し、削除するたびにコールバックをスキップして処理しません.
vm.$once
明らかに、onceの下位層はonとoffを用いて実現される.一度だけトリガーされたイベントコールバックをon関数、すなわちユーザが自分で追加した属性にマウントし、対応するイベント配列にon関数を押し込む.イベントがトリガーされるとon関数内の論理を実行し、イベント配列を空にし、applyの形式でfnを実行する.
vue.$emit
toArray関数の役割は、提供されるサイズstartに基づいて、配列長-start個の配列要素を後方から前方にコピーすることです.
この関数の論理は大体コールバックを処理することである.emitボディに戻ると、まずイベントに対応するコールバックリストを取得し、イベント配列の長さが1より大きい場合はtoArrayを呼び出して直接コピーします.次に配列をループし、コールバックを処理します.
-vueインスタンス登録イベントのapi
Vue.prototype.$on = function (event, fn) {
var vm = this;
if (Array.isArray(event)) {
for (var i = 0, l = event.length; i < l; i++) {
vm.$on(event[i], fn);
}
} else {
(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
};
まず,伝達されたeventがイベント配列であるか否かを判断し,もしそうであれば再帰的な考え方でvueインスタンスにイベントを登録する.単一のイベント文字列の場合、イベントが登録されているかどうかを判断し、登録されていない場合は、イベントに空の配列を初期化します.その後、fnすなわちコールバック関数を配列に押し込む.
vm.$off
-vueインスタンスログアウトイベントのapi
Vue.prototype.$off = function (event, fn) {
var vm = this;
// all
if (!arguments.length) {
vm._events = Object.create(null);
return vm
}
// array of events
if (Array.isArray(event)) {
for (var i$1 = 0, l = event.length; i$1 < l; i$1++) {
vm.$off(event[i$1], fn);
}
return vm
}
// specific event
var cbs = vm._events[event];
if (!cbs) {
return vm
}
if (!fn) {
vm._events[event] = null;
return vm
}
// specific handler
var cb;
var i = cbs.length;
while (i--) {
cb = cbs[i];
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1);
break
}
}
return vm
};
分別討論の思想.1.パラメータが入力されていない場合は、イベントリストを直接空にします.作者の考え方は、Object.create方式は、新しいイベントを格納するvueインスタンス属性を生成する.2.入力がイベント配列である場合、構想はonと同じであり、再帰的にログアウトする.3.特判部分(specific event部分)は、このイベントが登録されていない場合は、直接戻ります.ログアウトしたい指定したイベントのコールバックがない場合は、対応するイベント配列を空にします.4.最後に、イベントが送信され、パラメータが送信された場合について説明します.著者らの構想は,逆シーケンスで配列を遍歴し,spliceでイベントコールバックを削除することである.どうしてそうするの?もし遍歴していて、1つの数を削除したばかりで、後ろの数が自動的に前にシフトしたら、私たちは遍歴したことのないコールバックをスキップします.つまり、最後のコールバックを削除する以外は、順方向に遍歴し、削除するたびにコールバックをスキップして処理しません.
vm.$once
Vue.prototype.$once = function (event, fn) {
var vm = this;
function on () {
vm.$off(event, on);
fn.apply(vm, arguments);
}
on.fn = fn;
vm.$on(event, on);
return vm
};
明らかに、onceの下位層はonとoffを用いて実現される.一度だけトリガーされたイベントコールバックをon関数、すなわちユーザが自分で追加した属性にマウントし、対応するイベント配列にon関数を押し込む.イベントがトリガーされるとon関数内の論理を実行し、イベント配列を空にし、applyの形式でfnを実行する.
vue.$emit
Vue.prototype.$emit = function (event) {
var vm = this;
{
var 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 + "\"."
);
}
}
var cbs = vm._events[event];
if (cbs) {
cbs = cbs.length > 1 ? toArray(cbs) : cbs;
var args = toArray(arguments, 1);
var info = "event handler for \"" + event + "\"";
for (var i = 0, l = cbs.length; i < l; i++) {
invokeWithErrorHandling(cbs[i], vm, args, vm, info);
}
}
return vm
};
}
function toArray (list, start) {
start = start || 0;
var i = list.length - start;
var ret = new Array(i);
while (i--) {
ret[i] = list[i + start];
}
return ret
}
toArray関数の役割は、提供されるサイズstartに基づいて、配列長-start個の配列要素を後方から前方にコピーすることです.
function invokeWithErrorHandling (
handler,
context,
args,
vm,
info
) {
var res;
try {
res = args ? handler.apply(context, args) : handler.call(context);
if (res && !res._isVue && isPromise(res) && !res._handled) {
res.catch(function (e) {
return handleError(e, vm, info + " (Promise/async)"); });
// issue #9511
// avoid catch triggering multiple times when nested calls
res._handled = true;
}
} catch (e) {
handleError(e, vm, info);
}
return res
}
この関数の論理は大体コールバックを処理することである.emitボディに戻ると、まずイベントに対応するコールバックリストを取得し、イベント配列の長さが1より大きい場合はtoArrayを呼び出して直接コピーします.次に配列をループし、コールバックを処理します.