React: دعم مستمعي الأحداث السلبية

تم إنشاؤها على ٧ أبريل ٢٠١٦  ·  62تعليقات  ·  مصدر: facebook/react

https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md

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

وبالمثل ، يمكننا توحيد هذا مع نموذج خيوط React Native. على سبيل المثال ، هناك شيء واحد يمكننا القيام به هناك وهو حظر مؤشر ترابط واجهة المستخدم بشكل متزامن عندما يكون هناك مستمعون نشطون مثل التعامل مع ضغطات المفاتيح.

سم مكعبvjeuxide

DOM React Core Team Big Picture Feature Request

التعليق الأكثر فائدة

لقد تلقيت للتو تحذيرًا في الكروم حول التعامل مع حدث العجلة ، والذي يمكن تحسينه إذا تم تسجيله كمعالج حدث سلبي. لذا فإن الحصول على هذا في React سيكون أمرًا رائعًا!

ال 62 كومينتر

وصل هذا إلى Chrome 51. هل هناك أي خطة محدثة لدعم ذلك في React؟ : يا

كيف يكون هذا ممكنًا إذا كان لدى React مستمع حدث واحد فقط في المستند ، ثم تم تفويضه للآخرين؟
تضمين التغريدة

ما الوضع الحالي لمشكلة الأحداث السلبية؟

لقد تلقيت للتو تحذيرًا في الكروم حول التعامل مع حدث العجلة ، والذي يمكن تحسينه إذا تم تسجيله كمعالج حدث سلبي. لذا فإن الحصول على هذا في React سيكون أمرًا رائعًا!

ستحتاج أيضًا إلى التعامل مع الخيارات التعسفية ، مثل once الذي وصل بالفعل إلى Firefox ليلاً: https://twitter.com/mozhacks/status/758763803991474176. القائمة الكاملة: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener

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

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

اقتراح صغير:

<SomeElement
  onScroll={this.onScrollThatCallsPreventDefault}
  onScrollPassive={this.onScrollThatJustListens}
  ...this.props
/>

romulof نعم ، هذه هي الطريقة التي تسجل بها الأحداث في مرحلة الالتقاط أيضًا

<SomeElement
  onClick={this.onClick}
  onClickCapture={this.onClickCapture}
  onScrollPassive={this.onScrollPassive}
/>

لذلك أتخيل أن هذه ستكون واجهة برمجة التطبيقات المناسبة لدعم الأحداث السلبية أيضًا.

ملاحظة جانبية: السؤال الصعب هو - كيف يمكنك تسجيل الأحداث السلبية لمرحلة الالتقاط؟ أفترض أن هذا غير ممكن ، بسبب طبيعة الأحداث السلبية. نظرًا لأنه لا يُسمح لهم حتى بالاتصال بـ event.preventDefault() ، فمن المحتمل أن هذه ليست مشكلة.

radubrehar ، onScrollCapturePassive يشبه الكتاب المقدس بأكمله في علبة الجمل.

:) ليس الأمر كذلك ، حيث لا توجد أحداث سلبية في مرحلة الالتقاط.

بالتأكيد لا معنى له ، لكنني لن أعتمد عليه. هناك أيضًا أنواع أخرى من ربط الأحداث ، مثل once .

اقتراح آخر:

<SomeElement
  onScroll={this.onScrollThatCallsPreventDefault}
/>
<SomePassiveElement
  onScroll={{
    passive: true,
    capture: true,
    handler: this.onScrollThatJustListens,
  }}
/>

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

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

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

class Foo extends React.Component {
  constructor() {
    this.handleScroll = this.handleScroll.bind(this);
    this.handleScroll.passive = false;
  }

  handleScroll() {
    ...
  }

  render() {
    return <div onScroll={this.handleScroll} />;
  }
}

من الناحية النظرية ، سيعمل هذا بشكل جيد مع المصممين بمجرد هبوطهم.

بالتفكير في هذا الأمر أكثر من ذلك بقليل ، أعتقد أنه سيكون من الأفضل إضافة خاصية خيارات الحدث إلى الوظيفة ، بدلاً من الخيارات الفردية. سيسمح ذلك لـ React بأن تقلق بشأن خاصية واحدة فقط بدلاً من العديد من الخصائص المحتملة. لذلك ، لضبط المثال أعلاه:

class Foo extends React.Component {
  constructor() {
    this.handleScroll = this.handleScroll.bind(this);
    this.handleScroll.options = { passive: false };
  }

  handleScroll() {
    ...
  }

  render() {
    return <div onScroll={this.handleScroll} />;
  }
}

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

return <div onScroll={this.handleScroll, { passive: false }} />;

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

هذه الطريقة تشبه إلى حد كبير ما اقترحته سابقًا ، دون تعديل بناء جملة JSX.

return <div onScroll={{ handler: this.handleScroll, passive: true }} />;

وسيكون التوثيق مباشرًا:

div.propTypes = {
  ...
  onScroll: React.PropTypes.oneOf([
    React.PropTypes.func,
    React.PropTypes.shape({
      handler: React.PropTypes.func.isRequired,
      capture: React.PropTypes.bool,
      passive: React.PropTypes.bool,
      once: React.PropTypes.bool,
    }),
};

هل الأحداث المتفاعلة سلبية بشكل افتراضي؟ يبدو أن الأمر كذلك بالنسبة للأحداث التي تعمل باللمس ، على الأقل. لست قادرًا على preventDefault ما لم أعود إلى مستمعي حدث على مستوى مستندات الفانيليا.

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

لست على دراية بتفاصيل التنفيذ ، لكنني أعلم أن preventDefault يعمل على الأقل _ طالما أن المعالجات التي تمنعها هي أيضًا معالجات أحداث React_. كانت هذه تجربتي على أي حال.

مع stopPropagation من المرجح أن تفقد حظك (على سبيل المثال ، لديك مستمع نقرات document لا يمكن ربطه بـ React ، وتريد تجنب ظهور الفقاعات إذا نقرت بالداخل عنصر معين). في هذه الحالة يمكنك استخدام:

function stopPropagation (e) {
  e.stopPropagation();
  e.nativeEvent.stopImmediatePropagation();
}

[[MDN] (https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation)]

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

joshjg @ benwiley4000gaearon قام فريق chrome مؤخرًا بتغيير أسلوبه في أحداث اللمس على مستوى المستند ، مما يجعلها سلبية بشكل افتراضي. ونظرًا لأن React تقوم بإرفاق أحداث على مستوى المستند ، فإنك تحصل على هذا السلوك الجديد.

راجع https://www.chromestatus.com/features/5093566007214080

لقد غيّر هذا بشكل غير مباشر الطريقة التي تتصرف بها React - أفترض أن React لا تذكر صراحة passive: false عند إرفاق الأحداث - ومن هنا جاء التغيير في السلوك.

لقد قمت للتو بذلك أيضًا - لذا فأنت بحاجة إلى تسجيل أحداث اللمس يدويًا باستخدام addEventListener

لاحظ أن التدخل السلبي افتراضيًا في Chrome ينطبق فقط على touchstart و touchmove ، وليس wheel . لذا فإن حدث wheel بدون وجود {passive: true} صريح سيظل يفرض التمرير المتزامن ، للتمرير باستخدام عجلة الماوس ولوحة التتبع بإصبعين. (لقد كتبت منشور مدونة حول بعض التفاصيل الدقيقة هنا.)

كما أننا (فريق Edge) ليس لدينا أي نية لتنفيذ نفس التدخل ، لذلك عندما نشحن مستمعين للأحداث السلبية ، ستظل ترغب في تحديد {passive: true} بشكل صريح.

لمعلوماتك ، لقد بدأت في النزول إلى المبني للمجهول: مسار خاطئ لمنع الجسم من التمرير على الهاتف المحمول عندما يكون هناك div تمرير ، ولكن من الصعب قليلاً استخدام مفتاح منع التخلف () لمنع التمرير. يمكنني إضافة المعالج وإزالته اعتمادًا على ما إذا كان div موجودًا ، أو الرجوع إلى الجسم. الارتفاع = نهج 100٪. يبدو إصلاح الارتفاع بالجسم قليلًا من الاختراق ، لكن بعد ذلك لن أحتاج إلى سلبية: خطأ على الإطلاق.

حالة الاستخدام الخاصة بي هي أنني أرغب في استخدام طريقة event.preventDefault() لمنع تمرير الحاوية عندما يسحب المستخدم عنصرًا بداخلها.

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

لسوء الحظ ، لا يمكنني استخدام نمط touch-action: none; لأنه يتم تطبيقه بعد بدء اللمس وربما لهذا السبب لا يكون له أي تأثير.

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

وإذا أحدثت تغييرات جذرية ، فليكن. قد أفتقد جزء من القصة بالرغم من ذلك.

أحب توقيع مستمع الحدث الجديد الذي اقترحه romulof في https://github.com/facebook/react/issues/6436#issuecomment -254331351.
إلى جانب إصلاح المشكلة الموصوفة هنا ، سيكون من الممكن تحديد خيارات EventListenerOptions أخرى مثل once

لقد واجهت هذه المشكلة للتو. لدي لوحة قماشية حيث يمكن للمستخدم الرسم. عند الرسم على Android ، في بعض الأحيان "يسحب للتحديث" بدلاً من القيام بضربة رسم. هذا يدل على أنها مشكلة حقيقية. سأتجنب onTouch{Start,Move,End} في الوقت الحالي وأستخدم addEventListener يدويًا كحل بديل.

يعجبني كثيرًا النهج الذي اقترحه romulof . يبدو أن الحل أيضًا لا يتطلب تغيير التغييرات.

bobvanderlinden يجب أن تعمل إضافة touch-action: none; إلى نمط اللوحة القماشية من أجلك ، فهي تتألق حقًا لحالة الاستخدام هذه. يمكن أن تكون

ومع ذلك ، كما أشار @ piotr-cz ، ​​فإن touch-action لا يحل مشكلة الأحداث السلبية بشكل عام. أواجه أيضًا نفس المشكلة المتمثلة في منع حاوية من التمرير أثناء سحب عنصر فرعي. جميع الحلول معقدة للغاية وتضيف ديونًا تقنية.

لسوء الحظ ، يمكن أن يتسبب وجود أي مستمع غير سلبي في حدوث مشكلة كبيرة ، حتى لو لم يكن هناك معالجات لأرض المستخدمين مرتبطة بها بالفعل. سيخبرك Chrome بذلك عند مستويات السجل verbose : [Violation] Handling of 'wheel' input event was delayed for 194 ms due to main thread being busy. Consider marking event handler as 'passive' to make the page more responsive. (هذا هو معالج المستوى الأعلى الذي تمت إضافته بواسطة https://github.com/facebook/react/blob/92b7b172cce9958b846844f0b46fd7bassignc5140d/packages/ رد فعل dom / src / الأحداث / ReactDOMEventListener.js # L155)

romuloflencioniradubrehar هل أنت على بينة من حقيقة أن العلم السلبي وليس المقصود للاستخدام على المستمعين الحدث التمرير؟ يجب استخدامه في أحداث مثل touchmove وما إلى ذلك حتى لا يتعارض مع أداء التمرير بالمتصفح. الأمثلة الخاصة بك محيرة للغاية بالنسبة لي.

الإعداد الخامل ليس مهمًا لحدث التمرير الأساسي ، حيث لا يمكن إلغاؤه ، لذلك لا يمكن للمستمع الخاص به حظر عرض الصفحة على أي حال.

المصدر: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners

معلومات إضافية: https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md

نعم ، أنا على علم بذلك الآن. لقد تم تضليلي عندما كتبت في وقت سابق
تعليقات. شكرا للتوضيح!

في الأربعاء ، 6 ديسمبر 2017 ، الساعة 8:25 صباحًا ، Martin Hofmann [email protected]
كتب:

romulof https://github.com/romuloflencioni
https://github.com/lencioni radubrehar https://github.com/radubrehar
هل أنت على دراية بحقيقة أن العلم الخامل ليس مخصصًا للاستخدام في
المستمعين الحدث التمرير؟ يجب استخدامه في أحداث مثل touchmove وما إلى ذلك.
لعدم التدخل في أداء التمرير للمتصفح. الأمثلة الخاصة بك
مربكة للغاية بالنسبة لي.

الإعداد الخامل ليس مهمًا لحدث التمرير الأساسي ، لأنه لا يمكنه ذلك
يتم إلغاؤها ، لذلك لا يمكن للمستمع أن يمنع عرض الصفحة على أي حال.

مصدر:
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Improving_scrolling_performance_with_passive_listeners

معلومات اضافية:
https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md

-
أنت تتلقى هذا لأنه تم ذكرك.

قم بالرد على هذا البريد الإلكتروني مباشرة ، وقم بعرضه على GitHub
https://github.com/facebook/react/issues/6436#issuecomment-349691618 ،
أو كتم الخيط
https://github.com/notifications/unsubscribe-auth/AAL7zgbNCpHNui-TX7r2FYdhVxZfdBX8ks5s9r_4gaJpZM4ICWsW
.

@ el-moalo-loco ، أنا متأكد من أنني قرأت بعض الوثائق على موقع Google Developers حول استخدام المستمعين السلبيين لأحداث التمرير لتحسين الأداء. لابد أنني أخطأت في القراءة أو تغير شيء ما على طول الطريق. على أي حال ، شكرا جزيلا للتوضيح!

romuloflencioni @ EL-moalo-مقام https://developers.google.com/web/tools/lighthouse/audits/passive-event-listeners
يجب أن يظل المستمعون على عجلة القيادة سلبيين حتى لو لم يكن من الضروري أن تكون مستمعات التمرير كذلك. أعتقد أن هذا قد يكون مصدر الارتباك.

sebmarkbage ما رأيك؟ هل يدعم مستمع الحدث السلبي هذا طريقه إلى React في وقت ما؟

أهلا،

كان علي فقط إضافة مستمع حدث نشط في componentDidMount مثل هذا:

global.addEventListener("touchstart", this.touchStart(), { passive: false })

حتى يمكنني الاتصال بـ e.preventDefault() لإيقاف التمرير الافتراضي لمتصفح Chrome ونقل عنصر في touchStart() .

من أجل معرفة العنصر الذي يتعين علي نقله ، كان علي إضافة onTouchStart إلى عنصر JSX مثل هذا:

onTouchStart={this.touchStartSetElement(element)}

في touchStartSetElement() قمت بتعيين خاصية حكومية element يمكنني قراءتها بـ touchStart()

إذا كانت React ستدعم مستمعي الأحداث النشطين ، فسيتم اختصار هذا إلى سطر واحد.

شكرا،

فيليب

ملاحظة: إذا حاولت الاتصال بـ e.preventDefault() في مستمع حدث سلبي ، فستتلقى هذا الخطأ في Chrome 56:

[التدخل] غير قادر على منع التخلف داخل مستمع الحدث السلبي بسبب معاملة الهدف على أنه خامل. راجع https://www.chromestatus.com/features/5093566007214080

أصبحت الأحداث السلبية افتراضيًا في Chrome 56 من خلال " تدخل " Google وتعطيل الويب بطريقة ما - ولكن أيضًا جعل التمرير أسرع.

أصبحت هذه مشكلة أكثر منذ أن تم تعيين Safari اعتبارًا من iOS 11.3 افتراضيًا أيضًا على الوضع الخامل ، والحل الكلاسيكي touch-action:none غير مدعوم هناك .

لقد اقترحت RFC https://github.com/reactjs/rfcs/pull/28 من شأنه أن يسمح بإنشاء معالجات مرجعية مخصصة تعمل مثل الدعائم (أي أنك تستخدم خصائص مثل onClick ولكن بدلاً من ذلك تستخدم محسوبة بناء جملة الخاصية ويحصل المعالج على معلومات وتحديثات المرجع وقيمة الدعامة). يمكن استخدام هذه لإنشاء مكتبات لأي حالة استخدام متقدمة لديك.

  • من السهل التعامل مع الأحداث السلبية ، وغير المبنية على نحو صريح ، والأحداث التي يتم التقاطها مرة واحدة.
  • يمكن القيام بأشياء أكثر تقدمًا من مجرد تسجيل معالج الأحداث معهم.
  • من وجهة نظر المستخدم ، فهي سهلة الاستخدام ، ما عليك سوى تمرير ما تمنحك المكتبة كخاصية محسوبة إلى أي عنصر. على سبيل المثال ، import {onScroll} from 'react-passive-events'; <div [onScroll]={scrollHandler} />

أنا لا أعتقد أن هذه يجب أن تكون وسيلة لتسجيل جميع الأحداث.

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

جميع أحداث اللمس أصبحت الآن سلبية بشكل افتراضي في iOS 11.3. وبالتالي فإن استدعاء event.preventDefault () في أي معالج حدث يعمل باللمس أصبح الآن غير فعال 😢

https://codesandbox.io/s/l4kpy569ol

بدون القدرة على إجبار معالجات الأحداث غير السلبية ، فإننا نواجه صعوبة في العمل على تغييرات iOS 11.3 https://github.com/atlassian/react-beautiful-dnd/issues/413

جئت لأرى كيف كان Vue.js يتعامل مع هذا ، وأنا أحب أسلوبهم تمامًا:

<!-- the click event's propagation will be stopped -->
<a v-on:click.stop="doThis"></a>

<!-- the submit event will no longer reload the page -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- modifiers can be chained -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- just the modifier -->
<form v-on:submit.prevent></form>

توجد قائمة المعدلات هذه:

  • .قف
  • .يحول دون
  • .إلتقاط
  • .الذات
  • .بمجرد
  • .مبني للمجهول

ويمكنك تأليف الأحداث بالطريقة التي تريدها. ربما يمكن أن يساعد هذا كمصدر إلهام لهذه المشكلة.

KeitIG أنا أعمل على مفترق Vue-loader المصمم لـ React

https://github.com/stalniy/react-webpack-loader

هذا يحزنني

selection_028

لست متأكدًا مما إذا كان هذا مقترحًا بالفعل - أو إذا كان منطقيًا لأي شخص آخر سواي ، ولكن:

onTouchStart={listener} 

إلى

onTouchStart={listener, options}

سيجعل كلاهما خيارات التمرير مثل { passive, true, once: true } طريقة طبيعية للقيام بذلك ، وسيتطابق أيضًا مع مخطط

سيؤدي الانتقال إلى onEventNameCapture الموجودة اليوم

alexreardon أعتقد حقًا أن هذا ليس خيارًا ، لأنه في js العادية ، listener, options هو تعبير ، يتم تقييمه إلى options ، لذا فإن البناء أعلاه ليس كما تقصده. سيتطلب ذلك تغيير طريقة ترجمة jsx إلى js وسيكون تغييرًا جذريًا. أشك في أن فريق رد الفعل سوف يسلك هذا الطريق.

آراء؟

فيما يتعلق بكونه تعبيرًا ، يمكن أن يتم بشكل مختلف بنفس النية.

ربما هناك الكثير من الخيارات. تشمل الخيارات:

import {handler} from 'React';

onTouchStart={handler(listener, options)}
onTouchStart={{listener, options}}

أو

onTouchStart={[listener, options]}

أو

onTouchStart={listener} onTouchStartOptions={options}

أحب فكرة تمرير كائن أكثر من أي شيء آخر. في كلتا الحالتين ، هذا يحتاج إلى حل.

هل يوجد حل الان؟

هل يوجد حل الان؟

الكلاسيكية الخاصة بك addEventListener و removeEventListener في componentDidMount و componentWillUnmount على التوالي.

نعم ، هذا مقرف.

وما رأيك في حلها باستخدام خطاف؟

...
const onClickPassive = useEventListener((e) => {
 console.log('passive event')
}, { passive: true })

return (
  <button onClick={onClickPassive}>Click me</button>
)

@ ara4n استخدام الخطاف جيد ، ولكن لا تزال هناك حاجة لحل كلاسيكي للتفاعل غير الخطاف

sebmarkbage أي تحديثات على هذا؟ لقد شحن Chrome للتو هذا وكسر تطبيقنا.

https://www.chromestatus.com/features/6662647093133312

[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/6662647093133312
يحدث ذلك مرة أخرى ، عندما حاولت منع سلوك التمرير الافتراضي في مستمع الحدث onWheel

kychanbi نفس الشيء بالنسبة لي ، لكني أواجه هذا الخطأ فقط على Windows chrome.

kychanbi أوه ، إنها إحدى ميزات Chrome 73 التي تتعامل مع مستمعي حدث عجلة / عجلة الماوس على مستوى المستند على

يمكنك استخدام خاصية css في إجراء اللمس div الخاص بحاوية المكون: لا شيء

.وعاء {
اللمس العمل: لا شيء ؛
}

madcher يبدو أنه لا يعمل مع أحداث الفأرة.
لقد قمت بحلها أخيرًا باستخدام جافا سكريبت الأصلي
element.addEventListener("wheel", eventHandler);

مقتطف صغير لمساعدة أولئك الذين يواجهون هذه المشكلة:

import React, { useRef, useEffect } from 'react'

const BlockPageScroll = ({ children }) => {
  const scrollRef = useRef(null)
  useEffect(() => {
    const scrollEl = scrollRef.current
    scrollEl.addEventListener('wheel', stopScroll)
    return () => scrollEl.removeEventListener('wheel', stopScroll)
  }, [])
  const stopScroll = e => e.preventDefault()
  return (
    <div ref={scrollRef}>
      {children}
    </div>
  )
}

const Main = () => (
  <BlockPageScroll>
    <div>Scrolling here will only be targeted to inner elements</div>
  </BlockPageScroll>
)

تضمين التغريدة

بطريقة ما لا تعمل الدعائم onWheel مع css touch-action: none;

    componentRef = React.createRef(null);
    handleWheel = (e) => {
      e.preventDefault();
    }
    render() {
      <Container style={{ touchAction: 'none' }} onWheel={this.handleWheel}>
        ...
      </Container>
    }

لا يزال هذا الخطأ يحصل:
[Intervention] Unable to preventDefault inside passive event listener due to target being treated as passive. See <URL>

نسخة العمل

بديل لحل الخطافات

    componentRef = React.createRef();
    handleWheel = (e) => {
      e.preventDefault();
    }
    componentDidMount() {
      if (this.componentRef.current) {
        this.componentRef.current.addEventListener('wheel', this.handleWheel);
      }
    }
    componentWillUnmount() {
      if (this.componentRef.current) {
        this.componentRef.current.removeEventListener('wheel', this.handleWheel);
      }
    }
    render() {
      <Container ref={this.componentRef}>...</Container>
    }

Fonger على الأرجح بسبب # 14856

تم اقتراح شيء من هذا القبيل ولكن إليك بعض الأفكار الأخرى.

function MyComponent() {
  function onScroll(event) { /* ... */ }
  onScroll.options = {capture, passive, ...};
  return <div onScroll={onScroll} />;
}

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

js function MyComponent() { function onScroll(event) { /* ... */ } onScroll.shouldPreventDefault = (event): boolean => { // some logic to decide if preventDefault() should be called. } onScroll.shouldStopPropagation = (event): boolean => { // some logic to decide if stopPropagation() should be called. } return <div onScroll={onScroll} />; }
سيكون من الصعب التأكد من أن هذا لن يصبح تغييرًا مفاجئًا ، ولكن إذا تم فرض ذلك ، فسيتم عزل كل الكود لتحديد ما إذا كان الحدث المطلوب أن يكون preventDefault ed سيتم عزله في الكود وسيكون React قادرًا على ذلك قم بتشغيل هذا الجزء فقط على الخيط الرئيسي وتشغيل كل شيء آخر في عامل منفصل أو بشكل غير متزامن.

حتى يتم حل هذا ، أعتقد أنه سيكون من الأفضل إزالة المراجع إلى event.preventDefault() من المستندات أو على الأقل تم تمييزها بتحذير بخصوص عدم قدرة Chrome على preventDefault في الأحداث السلبية.

أتساءل عن الآثار المترتبة على تغيير تفويض الحدث من الإصدار 17 من React. لدى Lighthouse قاعدة https://web.dev/uses-passive-event-listeners/ تختبر ضد الأحداث غير السلبية.

في السابق ، كان يتم تسجيل <div onTouchStart /> في المستند ، وهو أمر خامل افتراضيًا . ومع ذلك ، في الإصدار 17 من React ، يتم تسجيل الحدث على جذر شجرة React ، والتي لم تعد سلبية دون طلبها تحديدًا.

الاستنساخ: https://codesandbox.io/s/material-demo-forked-e2u72؟file=/demo.js ، مباشر: https://csb-e2u72.netlify.app/

Capture d’écran 2020-08-19 à 16 11 31

نعم. يبدو مقلقا. سأقدم قضية جديدة.

تم تقديمه https://github.com/facebook/react/issues/19651 لمناقشة React 17.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات