نسينا التفويض في جافا سكريبت. وفد الحدث في رد فعل

مرحبا بالجميع. تتناول هذه المقالة تفويض الحدث في JavaScript وتطبيقه في react.js.



ما هو في الواقع حول؟ لماذا ولماذا؟


للبدء ، دعنا نناقش بإيجاز:


  1. ما هو الحدث؟
  2. كيف يحدث التوزيع ؛
  3. معالجة DOM المستوى 2 مع مثال في JavaScript ؛

وأخيرًا: لماذا لا تنس تفويض React.


حدث


تتفاعل JavaScript و HTML مع بعضها البعض من خلال الأحداث. يعمل كل حدث على إخبار JavaScript بأن شيئًا ما قد حدث في نافذة المستند أو المتصفح. من أجل اللحاق بهذه الأحداث ، نحتاج إلى مستمعين (مستمعين) ، مثل معالجات يتم تشغيلها في حالة وقوع حدث.


نشر الحدث


النظام. حل المشكلة: كيفية فهم أي جزء من الصفحة ينتمي الحدث؟ تم تنفيذ طريقتين: في Internet Explorer ، "محتدما الأحداث" ، وفي Netscape Communicator ، "ربط الحدث".


الحدث محتدما


في هذه الحالة ، يتم تشغيل الحدث في أعمق عقدة في شجرة الوثيقة ، وبعد ذلك يرتفع خلال التسلسل الهرمي إلى النافذة نفسها.


<!DOCTYPE html> <html> <head> <title>Some title</title> </head> <body> <div id="myDiv">Click Me</div> </body> </html> 

في هذه الحالة ، سيكون هناك الترتيب التالي:


  1. عنصر div
  2. عنصر الجسم
  3. أتش تي أم أل عنصر
  4. وثيقة
  5. نافذة

الآن يتم دعم التصفح بواسطة جميع المتصفحات الحديثة ، وإن كان ذلك مع تطبيقات مختلفة.

في حالة اعتراض الحدث ، يكون العكس هو الصحيح:


  1. نافذة
  2. وثيقة
  3. أتش تي أم أل عنصر
  4. عنصر الجسم
  5. عنصر div

كان يعتقد أنه يمكن معالجة الحدث قبل أن يصل إلى العنصر المستهدف (كما هو مقرر في Netscape في وقت لاحق قام بالتقاط جميع المتصفحات الحديثة).

نتيجة لذلك ، لدينا الهيكل التالي لتوزيع أحداث DOM:


  1. نافذة
  2. وثيقة
  3. أتش تي أم أل عنصر
  4. عنصر الجسم // تنتهي مرحلة الاعتراض
  5. عنصر div // المرحلة المستهدفة
  6. عنصر الجسم // تبدأ مرحلة الصعود
  7. أتش تي أم أل عنصر
  8. وثيقة
  9. نافذة

ينقسم هذا المخطط إلى ثلاث مراحل: مرحلة الاعتراض - يمكن اعتراض الحدث قبل أن يصل إلى العنصر ، والمرحلة المستهدفة - معالجة العنصر الهدف ومرحلة الصعود - لتنفيذ أي إجراءات نهائية استجابة للحدث.


لذلك ، ننتقل إلى معالجة الحدث


دعونا نرى مثالا نموذجيا للتعامل مع الأحداث في جافا سكريبت.


 const btn = document.getElementById('myDiv') btn.addEventListener("click", handler) // some code btn.removeEventListener("click", handler) 

كل شيء لن يكون شيئًا ، لكننا هنا نتذكر IE المحبوب الذي يشترك في الأحداث باستخدام attachEvent ، ولإزالة detachEvent. ويمكنك الاشتراك في هذا الحدث عدة مرات. ولا تنس أنه من خلال التوقيع على وظيفة مجهولة المصدر ، ليس لدينا فرصة لإلغاء الاشتراك.


لكننا لسنا ز * المبرمجون خارج. دعونا نفعل كل شيء وفقا لكانون:


 var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } } } 

جيد جدا ، لكن ماذا عن موضوع الحدث؟ بعد كل شيء ، في IE لا يوجد. الهدف. srcElement ، منعDefault؟ لا قيمة إرجاع = خطأ. ولكن لا يوجد شيء لإضافة طريقتين:


 var EventUtil = { addHandler: function (elem, type, handler) { if (elem.addEventListener) { elem.addEventListener(type, handler, false) } else if (elem.attachEvent) { elem.attachEvent("on" + type, handler) } else { elem["on" = type] = hendler } }, getEvent: function (event) { return event ? event : window.event }, getTarget: function (event) { return event.target || event.srcElement }, preventDefault: function (event) { if (event.preventDefault) { event.preventDefault() } else { event.returnValue = false } }, removeHandler: function (elem, type, handler) { if (elem.removeEventListener) { elem.removeEventListener(type, handler, false) } else if (elem.detachEvent) { elem.detachEvent("on" + type, handler) } else { elem["on" = type] = null } }, stopPropagation: function (event) { if (event.stopPropagation) { event.stopPropagation() } else { event.cancelBubble = true } } } 

إلخ إلخ وهذه كلها رقصات.


حسنًا لقد فعلنا جيدًا ، لقد حللنا جميع المشكلات ، كل شيء على ما يرام. صحيح ، رمز خرج مرهقة إلى حد ما. الآن تخيل أننا بحاجة إلى الكثير من الاشتراكات في العديد من العناصر. واو ، يستغرق الأمر بضعة أسطر من التعليمات البرمجية. مثال:


 <ul> <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var item1 = document.getElementById('id1') var item2 = document.getElementById('id2') var itemNext = document.getElementById('some-next-id') EventUtil.addHandler(item1, "click", someHandle) EventUtil.addHandler(item2, "click", someHandle2) EventUtil.addHandler(itemNext, "click", someHandle3) 

وهكذا بالنسبة لكل عنصر ، ويجب ألا ننسى الحذف ، والعمل مع الهدف وما شابه


وهنا يأتي وفد الحدث لمساعدتنا.


كل ما نحتاج إليه هو توصيل معالج واحد بأعلى نقطة في شجرة DOM:


 <ul id="main-id"> //  id    <li id="id1">go somewhere</li> <li id="id2">do something</li> <li id="some-next-id">next</li> </ul> var list = document.getElementById('main-id') EventUtil.addHandler(list, "click", function(event) { event = EventUtil.getEvent(event) var target = EventUtil.getTarget(event) switch(target.id) { case "id1": //  -    id1 break case "id2": //  -    id1 break case "some-next-id": //  -    break } }) 

نتيجة لذلك ، لدينا معالج واحد فقط في الذاكرة ، ويمكن استخدام خاصية المعرف للإجراء المطلوب. انخفاض استهلاك الذاكرة يحسن الأداء العام للصفحة. يتطلب تسجيل معالج الأحداث وقتًا أقل ومكالمات أقل إلى DOM. الاستثناء هو ربما الفأرة والماوس ، وكل شيء أكثر تعقيدًا معهم.


الآن ماذا عن رد الفعل


تم فعل كل شيء عن التوافق عبر المستعرض لنا من قبل اللاعبين من facebook. تتلقى جميع معالجات الأحداث الخاصة بنا مثيلًا لـ SyntheticEvent . الذي يعتني بنا إعادة استخدام الأحداث من التجمع ، وإزالة جميع الخصائص بعد استدعاء المعالج.


حسنا.


ومع ذلك ، فإن المعالج الإضافي هو معالج إضافي. التقيت عدة مرات ، وأنا أتوب نفسي ، كتبت هذا النوع من الكود:


 class Example extends React.Component { handleClick () { console.log('click') } render () { return ( <div> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id onClick={() => console.log('click')} /> )} </div> ) } } 

يوضح المثال الحالة عندما يكون هناك نوع من الورقة مع عدد n من العناصر ، وبالتالي مع عدد n من تسجيلات معالجات.


دعنا نركض ، اذهب إلى الصفحة وتحقق من عدد المعالجات التي تعمل الآن. لهذا ، لقد وجدت سيناريو جيد:


 Array.from(document.querySelectorAll('*')) .reduce(function(pre, dom){ var clks = getEventListeners(dom).click; pre += clks ? clks.length || 0 : 0; return pre }, 0) 

يعمل في الكروم ديف أداة.


والآن ، نقوم بتفويض كل ذلك إلى div وهتافات الوالدين ، قمنا فقط بتحسين تطبيقنا n = array.length times. رمز المثال أدناه:


 class Example extends React.Component { constructor () { super() this.state = { useElem: 0 } } handleClick (elem) { var id = elem.target.id this.setState({ useElem: id }) } render () { return ( <div onClick={this.handleClick}> {new Array(20).fill().map((_, index) => <div key={index} // elem.id id={index} // elem.id useElem={index === this.state.useElem} /> )} </div> ) } } 

يعد تفويض أداة جيدة لمعالجة عدد كبير من الاشتراكات ، وفي حالة التقديم الديناميكي وإعادة رسم متكرر ، فإنه ببساطة لا يمكن الاستغناء عنه. شفقة على موارد المستخدم ، فهي ليست غير محدودة.


تستند هذه المقالة إلى كتاب JavaScript لمطوري الويب المحترفين ، كتبه نيكولاس زاكاس.


شكرا جزيلا لاهتمامكم إذا كان لديك شيء لمشاركته أو العثور على نوع من الخلل ، ربما خطأ أو لديك سؤال فقط ، فاكتب في التعليقات. سوف أكون سعيدا بأي ملاحظات!

Source: https://habr.com/ru/post/ar467361/


All Articles