উপাদানগুলির বাইরে থাকা ক্লিক ইভেন্টগুলির জন্য কীভাবে শুনবেন


89

ড্রপডাউন উপাদানটির বাইরে যখন ক্লিক হয় তখন আমি একটি ড্রপডাউন মেনু বন্ধ করতে চাই।

আমি কেমন করে ঐটি করি?

উত্তর:


59

উপাদানটিতে আমি এটি যুক্ত করেছি mousedownএবং mouseupপছন্দ করি:

onMouseDown={this.props.onMouseDown} onMouseUp={this.props.onMouseUp}

তারপরে পিতামাতার মধ্যে আমি এটি করি:

componentDidMount: function () {
    window.addEventListener('mousedown', this.pageClick, false);
},

pageClick: function (e) {
  if (this.mouseIsDownOnCalendar) {
      return;
  }

  this.setState({
      showCal: false
  });
},

mouseDownHandler: function () {
    this.mouseIsDownOnCalendar = true;
},

mouseUpHandler: function () {
    this.mouseIsDownOnCalendar = false;
}

showCalএকটি বুলিয়ান যে যখন trueআমার ক্ষেত্রে শো একটি ক্যালেন্ডার এবং falseএটা লুকিয়ে রাখে।


যদিও ক্লিকটি একটি মাউসের সাথে বিশেষভাবে সংযুক্ত করে। ক্লিকের ইভেন্টগুলি স্পর্শ ইভেন্টের মাধ্যমে উত্পন্ন হতে পারে এবং কীগুলিও প্রবেশ করতে পারে, যা এই সমাধানটি মোবাইল এবং অ্যাক্সেসযোগ্যতার উদ্দেশ্যে উপযুক্ত না করে এটির প্রতিক্রিয়া জানাতে পারবে না = (
মাইক 'পোম্যাক্স' কামারম্যানস

@ মাইক'পোম্যাক্স'কামারম্যানস আপনি এখন মোবাইলের জন্য অন টাচ স্টার্ট এবং অন টাচঅ্যান্ড ব্যবহার করতে পারেন। ফেসবুক.
github.io/react/docs/events.html#touch-events

4
এগুলি দীর্ঘকাল ধরে রয়েছে, তবে অ্যান্ড্রয়েডের সাথে দুর্দান্ত খেলবে না, কারণ আপনাকে preventDefault()তত্ক্ষণাত্ ইভেন্টগুলি বা নেটিভ অ্যান্ড্রয়েড আচরণটি শুরু করতে হবে যা রিএ্যাক্টের প্রিপ্রোসেসিংয়ে হস্তক্ষেপ করে। আমি npmjs.com/package/react-onclickoutside লিখেছি ।
মাইক 'পোম্যাক্স' কামারম্যানস

আমি এটা ভালোবাসি! প্রশংসিত। মোডাউনডে ইভেন্ট শ্রোতাদের সরানো সহায়ক হবে। উপাদানউইলউনমাউন্ট = () => উইন্ডো.রেমওয়েভেন্টলিস্টনার ('মোসডাউন', this.page ক্লিক করুন, মিথ্যা);
জুনি ব্রোসাস

73

জীবনচক্রের পদ্ধতিগুলি ব্যবহার করে দস্তাবেজে ইভেন্ট শ্রোতাদের যুক্ত এবং সরিয়ে দেওয়া হয়।

React.createClass({
    handleClick: function (e) {
        if (this.getDOMNode().contains(e.target)) {
            return;
        }
    },

    componentWillMount: function () {
        document.addEventListener('click', this.handleClick, false);
    },

    componentWillUnmount: function () {
        document.removeEventListener('click', this.handleClick, false);
    }
});

এই উপাদানটির 48-54 লাইনগুলি দেখুন: https://github.com/i- Like-robots/react-tube-tracker/blob/91dc0129a1f6077bef57ea4ad9a860be0c600e9d/app/comp घटक/tube-tracker.jsx#L48-54


এটি নথিতে একটি যুক্ত করে, তবে এর অর্থ এই উপাদানটির যে কোনও ক্লিক ইভেন্টগুলিও নথির ইভেন্টটিকে ট্রিগার করে। এটি তার নিজস্ব সমস্যাগুলির কারণ কারণ ডকুমেন্ট শ্রোতার লক্ষ্য সর্বদা কিছু অংশের শেষে কিছুটা নিম্ন ডাউন ডিভ থাকে, উপাদানটি নিজেই নয়।
অ্যালান হর্টল

আমি আপনার মন্তব্যটি অনুসরণ করি তা সম্পর্কে নিশ্চিত নই তবে আপনি যদি ইভেন্ট শ্রোতাদের দস্তাবেজের সাথে আবদ্ধ করেন তবে আপনি কোনও নির্বাচিত (মানক ইভেন্ট প্রতিনিধি) এর সাথে মিলে বা অন্য কোনও সালিশী প্রয়োজনীয়তা অনুসারে কোনও ক্লিক ইভেন্টগুলিকে ফিল্টার করতে পারেন (ইজি ছিল লক্ষ্য উপাদান অন্য উপাদানের মধ্যে নয় )।
i_ Like_robots

4
@ অ্যালানহোর্টল পয়েন্ট হিসাবে এটি সমস্যার সৃষ্টি করে। একটি প্রতিক্রিয়া ইভেন্টের স্টপপ্রসেশন ডকুমেন্ট ইভেন্ট ইভেন্ট হ্যান্ডলারদের ইভেন্টটি পেতে বাধা দেয় না।
ম্যাট ক্রাইঙ্কলা-ভোগ

4
আগ্রহী যে কারও কাছে ডকুমেন্টটি ব্যবহার করার সময় আমার স্টপপ্রোগেশন নিয়ে সমস্যা ছিল। আপনি যদি আপনার ইভেন্ট শ্রোতাকে উইন্ডোতে সংযুক্ত করেন তবে মনে হয় এই সমস্যাটি ঠিক হয়ে গেছে?
তিতাস

10
যেমনটি উল্লেখ করা হয়েছে getgetDOMNode () অপ্রচলিত। পরিবর্তে এটির মতো ReactDOM ব্যবহার করুন: ReactDOM.findDOMNode (এটি) c কন্টেন্টগুলি (e.target)
আর্ন এইচ বিটুবেক

17

ইভেন্টের লক্ষ্যটি দেখুন, যদি ইভেন্টটি সরাসরি উপাদানটিতে বা সেই উপাদানটির বাচ্চাদের উপর থাকে তবে ক্লিকটি ভিতরে ছিল। অন্যথায় এটি বাইরে ছিল।

React.createClass({
    clickDocument: function(e) {
        var component = React.findDOMNode(this.refs.component);
        if (e.target == component || $(component).has(e.target).length) {
            // Inside of the component.
        } else {
            // Outside of the component.
        }

    },
    componentDidMount: function() {
        $(document).bind('click', this.clickDocument);
    },
    componentWillUnmount: function() {
        $(document).unbind('click', this.clickDocument);
    },
    render: function() {
        return (
            <div ref='component'>
                ...
            </div> 
        )
    }
});

এটি যদি অনেকগুলি উপাদান ব্যবহার করতে হয় তবে এটি মিক্সিন সহ ভাল with

var ClickMixin = {
    _clickDocument: function (e) {
        var component = React.findDOMNode(this.refs.component);
        if (e.target == component || $(component).has(e.target).length) {
            this.clickInside(e);
        } else {
            this.clickOutside(e);
        }
    },
    componentDidMount: function () {
        $(document).bind('click', this._clickDocument);
    },
    componentWillUnmount: function () {
        $(document).unbind('click', this._clickDocument);
    },
}

এখানে উদাহরণ দেখুন: https://jsfiddle.net/0Lshs7mg/1/


@ মাইক'পোম্যাক্স 'কামারম্যানস যা স্থির হয়েছে, আমি মনে করি এই উত্তরটি দরকারী তথ্য যুক্ত করেছে, সম্ভবত আপনার মন্তব্যটি এখন মুছে ফেলা হতে পারে।
জা

আপনি ভুল কারণে আমার পরিবর্তনগুলি ফিরিয়ে দিয়েছেন। this.refs.component0.14 ফেসবুক.
github.io/react/blog/2015/07/03/…

@ গজুসকুইজিনাস - ০.০৪ এর একবার এই পরিবর্তনটি ঠিক করা সর্বশেষতম প্রকাশ (এখন বিটা)।
জা

ডলার কী?
pronebird

4
আমি প্রতিক্রিয়ার সাথে jQuery পোঁকতে ঘৃণা করি যেহেতু তারা দুটি দর্শনের কাঠামো।
আব্দেন্নুর টুমি

11

আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে, বর্তমানে গৃহীত উত্তরটি হ'ল একটি অতিমাত্রায় ইঞ্জিনিয়ারড ered আপনি যদি শুনতে চান যে কোনও ব্যবহারকারী যখন ড্রপডাউন তালিকার বাইরে চলে আসে, কেবলমাত্র <select>মূল উপাদান হিসাবে কোনও উপাদান ব্যবহার করুন এবং এর সাথে একটি onBlurহ্যান্ডলার সংযুক্ত করুন ।

এই পদ্ধতির একমাত্র ত্রুটিগুলি এটি ধরে নেয় যে ব্যবহারকারী ইতিমধ্যে উপাদানটির উপর ফোকাস বজায় রেখেছে, এবং এটি একটি ফর্ম নিয়ন্ত্রণের উপর নির্ভর করে (যা আপনি কী চান তা যদি না হয় তবে আপনি tabকী বিবেচনা করেন এবং কীগুলি উপাদানগুলিকেও ঝাপসা করে urs ) - তবে এই ত্রুটিগুলি আরও জটিল ব্যবহারের ক্ষেত্রে কেবলমাত্র একটি সীমা, এই ক্ষেত্রে আরও জটিল সমাধানের প্রয়োজন হতে পারে।

 var Dropdown = React.createClass({

   handleBlur: function(e) {
     // do something when user clicks outside of this element
   },

   render: function() {
     return (
       <select onBlur={this.handleBlur}>
         ...
       </select>
     );
   }
 });

10

আমার জন্য এটি সমাধান ছিল যা আমি সবচেয়ে সহজ এবং সহজ ব্যবহার করতে পেলাম, আমি এটিকে একটি বোতামের উপাদানটিতে ব্যবহার করছি এবং কবজির মতো কাজ করি। ধন্যবাদ!
আমির 5000

5

উপাদানগুলির বাইরে উত্পন্ন ইভেন্টগুলি, প্রতিক্রিয়া-বাইরে-ইভেন্টের জন্য আমি একটি জেনেরিক ইভেন্ট হ্যান্ডলার লিখেছি ।

বাস্তবায়ন নিজেই সহজ:

  • উপাদান মাউন্ট করা হয়, একটি ইভেন্ট হ্যান্ডলার windowবস্তুর সাথে সংযুক্ত করা হয় ।
  • যখন কোনও ইভেন্ট ঘটে তখন উপাদানটি উপাদানটির মধ্য থেকেই ইভেন্টটির উত্স হয় কিনা তা পরীক্ষা করে। যদি এটি না হয়, তবে এটি onOutsideEventলক্ষ্য উপাদানটিতে ট্রিগার করে।
  • যখন উপাদানটি আনমাউন্ট করা হয় না, ইভেন্ট হ্যান্ডলারটি আলাদা করে দেওয়া হয়।
import React from 'react';
import ReactDOM from 'react-dom';

/**
 * @param {ReactClass} Target The component that defines `onOutsideEvent` handler.
 * @param {String[]} supportedEvents A list of valid DOM event names. Default: ['mousedown'].
 * @return {ReactClass}
 */
export default (Target, supportedEvents = ['mousedown']) => {
    return class ReactOutsideEvent extends React.Component {
        componentDidMount = () => {
            if (!this.refs.target.onOutsideEvent) {
                throw new Error('Component does not defined "onOutsideEvent" method.');
            }

            supportedEvents.forEach((eventName) => {
                window.addEventListener(eventName, this.handleEvent, false);
            });
        };

        componentWillUnmount = () => {
            supportedEvents.forEach((eventName) => {
                window.removeEventListener(eventName, this.handleEvent, false);
            });
        };

        handleEvent = (event) => {
            let target,
                targetElement,
                isInside,
                isOutside;

            target = this.refs.target;
            targetElement = ReactDOM.findDOMNode(target);
            isInside = targetElement.contains(event.target) || targetElement === event.target;
            isOutside = !isInside;



            if (isOutside) {
                target.onOutsideEvent(event);
            }
        };

        render() {
            return <Target ref='target' {... this.props} />;
        }
    }
};

উপাদানটি ব্যবহার করতে, আপনার উচ্চতর অর্ডার উপাদান ব্যবহার করে লক্ষ্য উপাদান উপাদান শ্রেণি ঘোষণাকে মোড়ানো করতে হবে এবং যে ইভেন্টগুলি আপনি পরিচালনা করতে চান তা সংজ্ঞায়িত করতে হবে:

import React from 'react';
import ReactDOM from 'react-dom';
import ReactOutsideEvent from 'react-outside-event';

class Player extends React.Component {
    onOutsideEvent = (event) => {
        if (event.type === 'mousedown') {

        } else if (event.type === 'mouseup') {

        }
    }

    render () {
        return <div>Hello, World!</div>;
    }
}

export default ReactOutsideEvent(Player, ['mousedown', 'mouseup']);

4

আমি উত্তরগুলির একটিতে ভোট দিয়েছি যদিও এটি আমার পক্ষে কার্যকর হয়নি। এটি আমাকে এই সমাধানে নিয়ে গেছে। আমি অপারেশনের ক্রমটি কিছুটা পরিবর্তন করেছি। আমি লক্ষ্যটিতে মাউসডাউন এবং লক্ষ্যটিতে মাউসআপের জন্য শুনি। যদি তাদের মধ্যে দুটি সত্যই ফিরে আসে, আমরা মডেলটি বন্ধ করি না। ক্লিকটি নিবন্ধিত হওয়ার সাথে সাথে, যে কোনও জায়গায়, এই দুটি বুলিয়ান {মাউসডাউনঅনমোডাল, মাউসআপঅনমোডাল back মিথ্যাতে ফিরে গেছে।

componentDidMount() {
    document.addEventListener('click', this._handlePageClick);
},

componentWillUnmount() {
    document.removeEventListener('click', this._handlePageClick);
},

_handlePageClick(e) {
    var wasDown = this.mouseDownOnModal;
    var wasUp = this.mouseUpOnModal;
    this.mouseDownOnModal = false;
    this.mouseUpOnModal = false;
    if (!wasDown && !wasUp)
        this.close();
},

_handleMouseDown() {
    this.mouseDownOnModal = true;
},

_handleMouseUp() {
    this.mouseUpOnModal = true;
},

render() {
    return (
        <Modal onMouseDown={this._handleMouseDown} >
               onMouseUp={this._handleMouseUp}
            {/* other_content_here */}
        </Modal>
    );
}

এটির সুবিধাটি রয়েছে যে সমস্ত কোড সন্তানের উপাদানগুলির সাথে স্থির থাকে, না পিতামাতার। এর অর্থ এই উপাদানটি পুনরায় ব্যবহার করার সময় কপির জন্য কোনও বয়লারপ্লিট কোড নেই।


3
  1. একটি স্থির স্তর তৈরি করুন যা পুরো স্ক্রিনে ছড়িয়ে পড়ে ( .backdrop)।
  2. লক্ষ্য উপাদান ( .target) উপাদানটির বাইরে .backdropএবং বৃহত্তর স্ট্যাকিং সূচক ( z-index) সহ।

তারপরে .backdropউপাদানটির যে কোনও ক্লিককে " .targetউপাদানটির বাইরে" বিবেচনা করা হবে ।

.click-overlay {
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    z-index: 1;
}

.target {
    position: relative;
    z-index: 2;
}

2

আপনি refএটি অর্জন করতে ব্যবহার করতে পারেন, নীচের মতো কিছু কাজ করা উচিত।

যোগ refআপনার উপাদানে:

<div ref={(element) => { this.myElement = element; }}></div>

তারপরে আপনি উপাদানটির বাইরের ক্লিকটি পরিচালনা করার জন্য একটি ফাংশন যুক্ত করতে পারেন:

handleClickOutside(e) {
  if (!this.myElement.contains(e)) {
    this.setState({ myElementVisibility: false });
  }
}

তারপরে অবশেষে ইভেন্ট শ্রোতাদের সংযোজন এবং মুছে ফেলবে উইল মাউন্ট হবে এবং আনমাউন্ট হবে।

componentWillMount() {
  document.addEventListener('click', this.handleClickOutside, false);  // assuming that you already did .bind(this) in constructor
}

componentWillUnmount() {
  document.removeEventListener('click', this.handleClickOutside, false);  // assuming that you already did .bind(this) in constructor
}

আপনার উত্তর পরিবর্তন, এটি আহ্বান প্রসঙ্গে সম্ভব সমস্যার সম্মুখীন হয়েছি handleClickOutsideমধ্যে document.addEventListener()যোগ করে thisরেফারেন্স। অন্যথায় দেয় Uncaught ReferenceError: handleClickOutside সংজ্ঞায়িত করা হয় নাcomponentWillMount()
মুহাম্মদ হান্নান

1

পার্টিতে দেরি হয়ে গেছে, তবে ড্রপডাউন বন্ধ করার জন্য সম্পর্কিত কোডের সাথে ড্রপডাউনটির মূল উপাদানটির উপর একটি অস্পষ্ট ইভেন্ট সেট করার ক্ষেত্রে আমি সাফল্য পেয়েছি, এবং প্যারেন্ট উপাদানটির কাছে একটি মোসডাউন শ্রোতাকে সংযুক্ত করে যা ড্রপডাউনটি খোলা আছে কিনা তা পরীক্ষা করে দেখায় বা না, এবং এটি খোলার পরে ইভেন্টের প্রচার বন্ধ করে দেবে যাতে অস্পষ্ট ইভেন্টটি ট্রিগার হয় না।

যেহেতু মোডাউনড ইভেন্টটি বুদবুদ হয়ে যায় এটি বাচ্চাদের উপর যে কোনও শৈশবকে পিতামাতার উপর ঝাপসা হওয়া থেকে আটকাবে।

/* Some react component */
...

showFoo = () => this.setState({ showFoo: true });

hideFoo = () => this.setState({ showFoo: false });

clicked = e => {
    if (!this.state.showFoo) {
        this.showFoo();
        return;
    }
    e.preventDefault()
    e.stopPropagation()
}

render() {
    return (
        <div 
            onFocus={this.showFoo}
            onBlur={this.hideFoo}
            onMouseDown={this.clicked}
        >
            {this.state.showFoo ? <FooComponent /> : null}
        </div>
    )
}

...

e.preventDefault () যতক্ষণ না আমি যুক্তি বলতে পারি কল করা উচিত নয় তবে ফায়ারফক্স কোনও কারণ ছাড়াই এটি খেলতে পারে না। ক্রোম, ফায়ারফক্স এবং সাফারিতে কাজ করে।


0

আমি এই সম্পর্কে একটি সহজ উপায় খুঁজে।

আপনার কেবলমাত্র onHide(this.closeFunction)মডেলটি যুক্ত করতে হবে

<Modal onHide={this.closeFunction}>
...
</Modal>

ধরে নিচ্ছি মডেলটি বন্ধ করার জন্য আপনার একটি ফাংশন রয়েছে।


-1

চমৎকার প্রতিক্রিয়া-অনক্লিকআউটসাইড মিক্সিন ব্যবহার করুন :

npm install --save react-onclickoutside

এবং তারপর

var Component = React.createClass({
  mixins: [
    require('react-onclickoutside')
  ],
  handleClickOutside: function(evt) {
    // ...handling code goes here... 
  }
});

4
এফওয়াইআই মিক্স-ইনগুলি এখন প্রতিক্রিয়াতে হ্রাস করা হয়েছে।
মেশিনঘস্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.