إذا كنت تستخدم كتابة المزيد من الإطار مثل jQuery ، فسوف يتم إغراءك حتماً من قبل JS الأصلي.
في الواقع ، لا ترغب Xiaocai في كتابة هذه المدونة ، ويبدو أنها بدائية للغاية ، ولكن ترى أنها لا تستطيع حتى شرح ملزمة وتفكيك أحداث JS الأصلية على الإنترنت ، قررت أن تصنع بعض العلوم الشعبية.
بادئ ذي بدء ، Xiaocai لا يعرف الكثير ، فقط شارك أفكاري معك.
نموذج الحدث DOM0
تتطور نماذج الأحداث باستمرار ، وتسمى نماذج الأحداث المبكرة مستوى DOM0.
نموذج الحدث DOM0 ، بدعم من جميع المتصفحات.
تسجيل اسم الحدث مباشرة على كائن DOM هو طريقة كتابة DOM0 ، مثل:
نسخة الكود كما يلي:
document.getElementById ("test"). onClick = function (e) {} ؛
وهذا يعني تسجيل حدث onclick. بالطبع ، لها نفس المعنى مثل كتابة هذه الكتابة:
نسخة الكود كما يلي:
document.getElementById ("test") ["onMousemove"] = function (e) {} ؛
هذا لا شيء ، إنه مجرد طريقتين للوصول إلى خصائص كائن JS. يشكل شكل [] بشكل أساسي حل المشكلة التي لا يكون اسم السمة معرفًا قانونيًا. على سبيل المثال ، يجب على Object.123 الإبلاغ عن خطأ ، لكن الكائن ["123"] يتجنب هذه المشكلة. في الوقت نفسه ، يكتب كتابة [] أيضًا JS على قيد الحياة ، باستخدام سلاسل لتمثيل اسم السمة ، والتي يمكن أن تربط الأحداث ديناميكيًا في وقت التشغيل.
بالعودة إلى هذه النقطة ، عندما يتم تشغيل الحدث ، سيتم تمرير المعلمة E افتراضيًا لتمثيل كائن الحدث. من خلال E ، يمكننا الحصول على الكثير من المعلومات المفيدة ، مثل إحداثيات النقر ، وعنصر DOM الذي أثار الحدث على وجه التحديد ، إلخ.
استنادًا إلى أحداث DOM0 ، لنفس عقدة DOM ، يمكن تسجيل واحد فقط ، وسيقوم الحدث نفسه المسجل لاحقًا بتجاوز الأحداث السابقة السابقة. على سبيل المثال:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
btn.onmousemove = function (e) {
تنبيه ("موافق") ؛
} ؛
BTN ["onMousemove"] = Function (e) {
تنبيه ("OK1") ؛
} ؛
ستخرج النتيجة OK1.
دعنا نتحدث عن هذا التالي. عندما يتم تشغيل حدث ما ، يشير هذا إلى كائن DOM الذي يتم تشغيل الحدث. على سبيل المثال:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
btn.onmousemove = function (e) {
تنبيه (this.id) ؛
} ؛
اختبار النتيجة. نظرًا لأن الحدث مسجل على عقدة DOM مع اختبار المعرف ، عندما يتم تشغيل الحدث ، فإن هذا يمثل بالطبع عقدة DOM هذه. يمكن أن يُفهم أن الحدث يسمى عقدة DOM هذه.
لذلك ، من السهل جدًا إلغاء الحدث. ما عليك سوى تسجيل الحدث مرة أخرى وتعيين القيمة على NULL ، على سبيل المثال:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
btn.onclick = function (e) {
تنبيه ("موافق") ؛
} ؛
btn.onclick = null ؛
المبدأ هو أن الحدث المسجل الأخير يجب أن يكتب الحدث السابق. قم بتعيين آخر حدث مسجل على NULL ، والذي سيؤدي إلى إلغاء إثارة الحدث.
لم تنته الأمر بعد ، ويتضمن نموذج أحداث DOM0 أيضًا أحداثًا مكتوبة مباشرة في HTML. على سبيل المثال:
نسخة الكود كما يلي:
<div id = "test" onClick = "exec () ؛" > </div>
تتبع الأحداث المسجلة بهذه الطريقة أيضًا مبدأ التغطية ، ويمكن تسجيل واحد فقط وسيصبح آخرها ساري المفعول.
الفرق هو أن الحدث المسجل بهذه الطريقة يعادل استدعاء وظيفة ديناميكيًا (يعني إلى حد ما يعني) ، لذلك لن يتم تمرير كائن الحدث. في الوقت نفسه ، هذا النقاط إلى النافذة ، ولم يعد كائن DOM الذي يؤدي إلى حدوث الحدث.
نموذج الحدث DOM2
بالمقارنة مع DOM0 ، يفهم Shouca فقط النقطتين التاليتين:
・ يدعم DOM2 تسجيل العديد من الأحداث بنفس عنصر DOM.
・ أضاف DOM2 مفهوم الالتقاط والفقاعات.
تتم إدارة أحداث DOM2 بواسطة AddEventListener و RemainSeventListener ، بالطبع ، هذا هو المعيار.
ومع ذلك ، فإن IE8 والمتصفحات التالية قد أنشأت مرفقًا و detachevent المقابل. نظرًا لأن Xiaocai غير مقصود بعض الشيء ، فإن هذه المقالة لن تناقشها.
AddEventListener هو بالطبع حدث التسجيل. لديها ثلاث معلمات ، وهي: "اسم الحدث" ، "رد الاتصال الحدث" ، و "الالتقاط/الفقاعة". على سبيل المثال:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
btn.addeventListener ("انقر" ، وظيفة (e) {
تنبيه ("موافق") ؛
}، خطأ شنيع)؛
وغني عن القول ، اسم الحدث ليس أكثر من اللازم. بالمقارنة مع DOM0 ، تمت إزالة السابقة فقط.
من السهل أيضًا فهم عروض عمليات الاسترداد للحدث. يجب أن تخطارك إذا تم تشغيل الحدث! عند الاتصال مرة أخرى ، مثل DOM0 ، سيتم تمرير معلمة الحدث افتراضيًا. في الوقت نفسه ، يشير هذا إلى عقدة DOM التي تؤدي إلى الحدث.
المعلمة الأخيرة هي النوع المنطقي ، ويمثل True حدث الالتقاط ، ويمثل خطأ حدث الفقاعة. في الواقع ، من السهل الفهم. دعونا أولاً نقوم بعمل مخطط:
وهذا يعني أنه إذا قام عنصر ما بتوجيه حدث ما ، فإن أول ما يتم إخطاره هو النافذة ، ثم المستند ، ويتسلسل بالتسلسل حتى العنصر (العنصر الهدف) الذي يؤدي فعليًا إلى الحدث. هذه العملية هي التقاط. بعد ذلك ، سيخفق الحدث من العنصر المستهدف ثم يخرج بالتسلسل حتى كائن النافذة. هذه العملية فقاعة.
لماذا تصميم بهذه الطريقة؟ يبدو أن هذا يرجع إلى أصوله التاريخية العميقة ، لذلك لا تعرف Xiaocai الكثير عنها ، لذلك لن تتحدث هراء.
من هذا يمكننا أن نرى أن حدث الالتقاط يتم تشغيله قبل حدث الفقاعة.
لنفترض أن هناك هيكل HTML هذا:
نسخة الكود كما يلي:
<div id = "test">
<div id = "testinner"> </viv>
</div>
ثم نسجل حدثين نقرة على Div الخارجي ، وهما حدث الالتقاط وحدث الفقاعات ، فإن الكود كما يلي:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
// الصيد الأحداث
btn.addeventListener ("انقر" ، وظيفة (e) {
تنبيه ("OK1") ؛
}، حقيقي)؛
// حدث الفقاعات
btn.addeventListener ("انقر" ، وظيفة (e) {
تنبيه ("موافق") ؛
}، خطأ شنيع)؛
أخيرًا ، انقر على Div الداخلي ، First Up Up Ok1 ، ثم يطفو على السطح موافق. بالاقتران مع الرسم التخطيطي أعلاه ، فإن DIV الخارجي يعادل الجسم في الشكل ، ويعادل Div الداخلي DIV السفلي في الشكل ، مما يثبت أن حدث الالتقاط يتم تنفيذه أولاً ، ثم يتم تنفيذ حدث الفقاعة.
لماذا التأكيد على النقر على Div الداخلي؟ نظرًا لأن عنصر DOM الذي يثير حقًا الحدث يجب أن يكون من الطبقة الداخلية ، فإن عنصر DOM للطبقة الخارجية لديه فرصة لمحاكاة الأحداث والتقاطها وأحداث الفقاعات ، والتي يمكن رؤيتها من الرسم التخطيطي.
ماذا لو قمت بتسجيل حدث الالتقاط وحدث الفقاعات على عنصر DOM الذي يؤدي فعليًا إلى الحدث؟
هيكل HTML هو نفسه كما هو مذكور ، ورمز JS كما يلي:
نسخة الكود كما يلي:
var btninner = document.getElementById ("testinner") ؛
// حدث الفقاعات
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("موافق") ؛
}، خطأ شنيع)؛
// الصيد الأحداث
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("OK1") ؛
}، حقيقي)؛
بالطبع ، انقر على Div الداخلي ، والنتيجة هي أن موافق يظهر أولاً ، ثم OK1. من الناحية النظرية ، يجب تشغيل حدث الالتقاط أولاً ، أي OK1 يظهر أولاً ، ولكن هنا مميز ، لأننا نسجل حدثًا على عنصر DOM الذي يؤدي فعليًا إلى الحدث ، وهو ما يعادل التسجيل في DIV في الشكل. من هذا الشكل ، يمكننا أن نرى أن عنصر DOM الذي يؤدي فعليًا إلى الحدث هو نقطة نهاية حدث الالتقاط ونقطة انطلاق حدث الفقاعة ، لذلك لا يوجد تمييز بين الأحداث هنا. أي واحد يسجل أولا ، ينفذ أي واحد أولا. في هذا المثال ، يتم تسجيل حدث الفقاعة أولاً ، لذلك يتم تنفيذه أولاً.
ينطبق هذا المبدأ على أحداث متعددة من نفس النوع. على سبيل المثال ، إذا تم تسجيل 3 أحداث فقاعة في وقت واحد ، فسيكون أمر التنفيذ في ترتيب التسجيل ، والتسجيل الأول والتنفيذ أولاً. على سبيل المثال:
نسخة الكود كما يلي:
var btninner = document.getElementById ("testinner") ؛
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("موافق") ؛
}، خطأ شنيع)؛
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("OK1") ؛
}، خطأ شنيع)؛
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("OK2") ؛
}، خطأ شنيع)؛
والنتيجة هي بالطبع OK و OK1 و OK2 المنبثقة بدورها.
من أجل زيادة فهم نموذج الحدث ، هناك سيناريو آخر. إذا كان Div الخارجي و DIV الداخلي يسجل حدث الالتقاط في نفس الوقت ، ثم عند النقر فوق Div الداخلي ، يجب تشغيل حدث Div الخارجي أولاً. الرمز كما يلي:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
var btninner = document.getElementById ("testinner") ؛
btninner.addeventListener ("Click" ، Function (E) {
تنبيه ("موافق") ؛
}، حقيقي)؛
btn.addeventListener ("انقر" ، وظيفة (e) {
تنبيه ("OK1") ؛
}، حقيقي)؛
والنتيجة هي أن OK1 يظهر أولاً.
إذا كانت كل من Div Outer و Div الداخليين أحداث فقاعة مسجلة ، عند النقر فوق Div الداخلي ، يجب تنفيذ الحدث الداخلي Div أولاً ، والمبدأ هو نفسه.
سيجد القراء الدقيقون أنه بالنسبة لحالة تداخل Div ، إذا قمت بالنقر فوق Div الداخلي ، فإن Div الخارجي سيؤدي أيضًا إلى حدوث حدث ، والذي يبدو أنه يمثل مشكلة!
من الواضح أن النقرة هي Div الداخلية ، ولكن يتم تشغيل حدث Div الخارجي أيضًا ، وهو بالفعل مشكلة.
في الواقع ، عندما يتم تشغيل الحدث ، سيتم تمرير كائن حدث افتراضيًا. كما ذكرنا سابقًا ، هناك طريقة في كائن الحدث هذا: توقف. من خلال هذه الطريقة ، يمكن منع الفقاعات ، حتى لا يتلقى Div الخارجي الحدث. الرمز كما يلي:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
var btninner = document.getElementById ("testinner") ؛
btn.addeventListener ("انقر" ، وظيفة (e) {
تنبيه ("OK1") ؛
}، خطأ شنيع)؛
btninner.addeventListener ("Click" ، Function (E) {
// توقف الفقاعات
E.StopPropagation () ؛
تنبيه ("موافق") ؛
}، خطأ شنيع)؛
أخيرًا ، يجب أن أتحدث عن كيفية حل الحادث. بناء جملة unease: btn.removeeventListener ("اسم الحدث" ، "رد الفعل الحدث" ، "capture/bubble") ؛
هذا هو نفس معلمات حدث الربط ، كما هو موضح بالتفصيل:
・ اسم الحدث يعني إلغاء الحدث.
・ رد الاتصال على الحدث هو وظيفة ، والتي يجب أن تكون هي نفس الوظيفة التي تسجل الحدث.
・ نوع الحدث ، القيمة المنطقية ، يجب أن يكون هذا متسقًا مع النوع عند تسجيل الحدث.
بمعنى آخر ، لا غنى عن الاسم ، والاستعمال ، والكتب ، معا ، أي حدث يجب إلغاؤه ، أمر لا غنى عنه. على سبيل المثال:
نسخة الكود كما يلي:
var btn = document.getElementById ("test") ؛
// تخزين رد الاتصال في متغير
var fn = function (e) {
تنبيه ("موافق") ؛
} ؛
//ملزم
btn.addeventListener ("Click" ، fn ، false) ؛
//إزالة
btn.removeeventListener ("Click" ، fn ، false) ؛
من أجل إلغاء الحدث المسجل ، يجب حفظ وظيفة رد الاتصال ، وإلا لا يمكن إلغاؤه.
مختلط DOM0 و DOM2
الأمور بالفعل فوضوية للغاية ، وهذا استخدام مختلط ، مما يجعل الناس يعيشون. . .
لا تخف ، فلا مشكلة في استخدامه بطريقة مختلطة. يتبع كل منهما نموذج DOM0 ونموذج DOM2 قواعدهما الخاصة ولا يؤثر على بعضهما البعض.
بشكل عام ، لا يوجد شيء آخر إذا تم تسجيله أولاً وتم تنفيذه أولاً.
PostScript
في هذه المرحلة ، تم تقريب حدث JS الأصلي. Xiaocai يعرف هذا فقط. القراء مرحب بهم لإضافة نقاط معرفة أخرى.
في التطبيقات الفعلية ، لن يقوم الخبراء الحقيقيون بتسجيل الكثير من الأحداث. بشكل عام ، تحتاج فقط إلى تسجيل حدث على عنصر DOM الخارجي ، ثم استخدام آلية الالتقاط والفقاعة للعثور على عنصر DOM الذي يؤدي فعليًا إلى الحدث ، وأخيراً استدعاء رد الاتصال بناءً على المعلومات التي يوفرها عنصر DOM الذي يؤدي إلى حدوث الحدث.
بمعنى آخر ، سيقوم الخبراء بإدارة الأحداث بأنفسهم دون الاعتماد على المتصفحات لإدارتها ، والتي يمكن أن تحسن الكفاءة وضمان التوافق. أليس هذا ما يفعله jQuery؟
حسنًا ، ينتهي البرنامج التعليمي هنا ، آمل أن يكون من المفيد للقراء!