প্রতিক্রিয়া উপাদানটির বাইরে ক্লিক করুন


410

আমি একটি উপায় খুঁজছি এই বর্ণনা অনুযায়ী একটি ক্লিকের ঘটনা একটি উপাদানের বাইরে ঘটেছে সনাক্ত করতে, নিবন্ধ । jQuery নিকটতম () দেখার জন্য ব্যবহৃত হয় যে কোনও ক্লিক ইভেন্টের লক্ষ্যটির কোনও পিতামাতার হিসাবে ডোম উপাদান রয়েছে কিনা। যদি কোনও মিল থাকে তবে ক্লিক ইভেন্টটি বাচ্চাদের একটির অন্তর্গত এবং সুতরাং উপাদানটির বাইরে এটি বিবেচনা করা হয় না।

সুতরাং আমার উপাদানটিতে আমি উইন্ডোতে একটি ক্লিক হ্যান্ডলার সংযুক্ত করতে চাই। হ্যান্ডলারটি যখন গুলি চালায় তখন আমার লক্ষ্যটি আমার উপাদানগুলির ডোম বাচ্চাদের সাথে তুলনা করতে হবে।

ক্লিক ইভেন্টে "পাথ" এর মতো বৈশিষ্ট্য রয়েছে যা মনে হয় যে ইভেন্টটি ভ্রমণ করেছে এমন ডোম পাথটি ধরে রেখেছে। আমি কোনটি তুলনা করব বা কীভাবে এটি সর্বোত্তমভাবে অতিক্রম করতে হবে তা আমি নিশ্চিত নই এবং আমি ভাবছি কেউ ইতিমধ্যে একটি চালাক ইউটিলিটি ফাংশনে রেখেছিল ... না?


আপনি কি উইন্ডোটির পরিবর্তে পিতামাতার সাথে ক্লিক হ্যান্ডলারটি সংযুক্ত করতে পারবেন?
জে। মার্ক স্টিভেনস

যদি আপনি সেই अभिभावকের সাথে একটি ক্লিক হ্যান্ডলার সংযুক্ত করেন তবে আপনি জানেন যে উপাদানটি বা তাদের সন্তানদের মধ্যে যখন ক্লিক করা হয় তবে আমি ক্লিক করা সমস্ত অন্যান্য জায়গা সনাক্ত করতে পারি , সুতরাং হ্যান্ডলারের উইন্ডোটির সাথে সংযুক্ত হওয়া দরকার।
থিজস কোয়ারসেলম্যান

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

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

5
আমি আপনাকে একটি খুব ভাল কাজ সুপারিশ করতে চাই। এয়ারবিএনবি দ্বারা নির্মিত: github.com/airbnb/react-outside-click-handler
ওসিয়ান মার্সেল

উত্তর:


681

নিম্নলিখিত সমাধানটি ES6 ব্যবহার করে এবং একটি পদ্ধতির মাধ্যমে রেফ সেট করার পাশাপাশি বাঁধার জন্য সর্বোত্তম অনুশীলনগুলি অনুসরণ করে।

এটি কার্যকরভাবে দেখতে:

শ্রেণি বাস্তবায়ন:

import React, { Component } from 'react';

/**
 * Component that alerts if you click outside of it
 */
export default class OutsideAlerter extends Component {
  constructor(props) {
    super(props);

    this.setWrapperRef = this.setWrapperRef.bind(this);
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentDidMount() {
    document.addEventListener('mousedown', this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener('mousedown', this.handleClickOutside);
  }

  /**
   * Set the wrapper ref
   */
  setWrapperRef(node) {
    this.wrapperRef = node;
  }

  /**
   * Alert if clicked on outside of element
   */
  handleClickOutside(event) {
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      alert('You clicked outside of me!');
    }
  }

  render() {
    return <div ref={this.setWrapperRef}>{this.props.children}</div>;
  }
}

OutsideAlerter.propTypes = {
  children: PropTypes.element.isRequired,
};

হুক বাস্তবায়ন:

import React, { useRef, useEffect } from "react";

/**
 * Hook that alerts clicks outside of the passed ref
 */
function useOutsideAlerter(ref) {
  useEffect(() => {
    /**
     * Alert if clicked on outside of element
     */
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        alert("You clicked outside of me!");
      }
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function OutsideAlerter(props) {
  const wrapperRef = useRef(null);
  useOutsideAlerter(wrapperRef);

  return <div ref={wrapperRef}>{props.children}</div>;
}

3
আপনি কিভাবে এটি পরীক্ষা করেন? আপনি হ্যান্ডেলক্লিক আউটসাইড ফাংশনে কীভাবে একটি বৈধ ইভেন্ট.আর্টেজ পাঠাবেন?
csilk

5
আপনি কীভাবে প্রতিক্রিয়ার সিন্থেটিক ইভেন্টগুলি document.addEventListenerএখানে ব্যবহার না করে ব্যবহার করতে পারেন ?
রাল্ফ ডেভিড

9
@ polkovnikov.ph 1. contextটি শুধুমাত্র কনস্ট্রাক্টারে আর্গুমেন্ট হিসাবে যদি এটি ব্যবহার করা হয় তবে প্রয়োজনীয়। এই ক্ষেত্রে এটি ব্যবহার করা হচ্ছে না। প্রতিক্রিয়া দলটি propsকনস্ট্রাক্টারে একটি আর্গুমেন্ট হিসাবে রাখার পরামর্শ দেওয়ার কারণ হ'ল this.propsকল করার আগে ব্যবহার super(props)অনির্ধারিত হবে এবং ত্রুটির কারণ হতে পারে। contextঅভ্যন্তরীণ নোডগুলিতে এখনও উপলভ্য, এর পুরো উদ্দেশ্য context। এইভাবে আপনাকে প্রপসগুলির মতো এটির উপাদান থেকে উপাদানগুলিতে যেতে হবে না। ২. এটি কেবল একটি স্টাইলিস্টিক পছন্দ, এবং এই ক্ষেত্রে বিতর্কের ওয়্যারেন্ট দেয় না।
বেন বুড

7
আমি নিম্নলিখিত ত্রুটিটি পেয়েছি: "this.wrapperRef.contains কোনও ফাংশন নয়"
বোগদান

5
@ বোগদান, স্টাইলযুক্ত উপাদান ব্যবহার করার সময় আমি একই ত্রুটি পেয়েছিলাম। শীর্ষ স্তরে একটি <ডিভি>> ব্যবহারের কথা বিবেচনা করুন
ব্যবহারকারীর 3040068

149

কনটেইনারটিতে ইভেন্টগুলি সংযুক্ত না করেই সমাধানটি আমার পক্ষে সবচেয়ে ভাল কাজ করেছে:

কিছু এইচটিএমএল উপাদানগুলিতে " ফোকাস " হিসাবে পরিচিত যা থাকতে পারে , উদাহরণস্বরূপ ইনপুট উপাদানগুলি। এই উপাদানগুলি ঝাপসা ইভেন্টে প্রতিক্রিয়া জানাবে , যখন তারা সেই ফোকাসটি হারাবে।

যে কোনও উপাদানকে ফোকাস করার ক্ষমতা দেওয়ার জন্য, কেবল এটির ট্যাবইন্ডেক্স বৈশিষ্ট্যটি -1 ব্যতীত অন্য কোনওটিতে সেট করা আছে তা নিশ্চিত করুন। নিয়মিত এইচটিএমএলে এটি tabindexবৈশিষ্ট্য নির্ধারণের মাধ্যমে হবে তবে প্রতিক্রিয়াতে আপনাকে ব্যবহার করতে হবে tabIndex( মূলধনটি নোট করুন I)।

আপনি এটি দিয়ে জাভাস্ক্রিপ্টের মাধ্যমেও করতে পারেন element.setAttribute('tabindex',0)

কাস্টম ড্রপডাউন মেনু তৈরি করার জন্য এটি আমি এটি ব্যবহার করছিলাম।

var DropDownMenu = React.createClass({
    getInitialState: function(){
        return {
            expanded: false
        }
    },
    expand: function(){
        this.setState({expanded: true});
    },
    collapse: function(){
        this.setState({expanded: false});
    },
    render: function(){
        if(this.state.expanded){
            var dropdown = ...; //the dropdown content
        } else {
            var dropdown = undefined;
        }

        return (
            <div className="dropDownMenu" tabIndex="0" onBlur={ this.collapse } >
                <div className="currentValue" onClick={this.expand}>
                    {this.props.displayValue}
                </div>
                {dropdown}
            </div>
        );
    }
});

10
এটি কি অ্যাক্সেসযোগ্যতার সমস্যা তৈরি করবে না? যেহেতু আপনি যখন কোনও অতিরিক্ত উপাদানটিকে ফোকাসের মধ্যে / আউট ফোকাসের সময় সনাক্ত করতে চান তবে এটি ইন্টারঅ্যাকশনটি ড্রপডাউন মানগুলিতে হওয়া উচিত?
থিজেস কোয়ারসেলম্যান

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

17
আমার কাছে এই "কাজ" কিছুটা হলেও, এটি দুর্দান্ত একটি হ্যাক। আমার সমস্যাটি হ'ল আমার ড্রপ ডাউন সামগ্রীটি display:absoluteযাতে ড্রপ ডাউন পিতামাতার ডিভের আকারকে প্রভাবিত করে না। এর অর্থ যখন আমি ড্রপডাউনটিতে একটি আইটেম ক্লিক করি, অন্বলুরটি আগুন ধরিয়ে দেয়।
ডেভ

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

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

106

আমি একই ইস্যুতে আটকে ছিলাম। আমি এখানে পার্টিতে কিছুটা দেরি করেছি, তবে আমার কাছে এটি সত্যিই ভাল সমাধান। আশা করি এটি অন্য কারও উপকারে আসবে। আপনার findDOMNodeকাছ থেকে আমদানি করা দরকারreact-dom

import ReactDOM from 'react-dom';
// ... ✂

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

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

handleClickOutside = event => {
    const domNode = ReactDOM.findDOMNode(this);

    if (!domNode || !domNode.contains(event.target)) {
        this.setState({
            visible: false
        });
    }
}

প্রতিক্রিয়া হুক পদ্ধতির (16.8 +)

আপনি একটি পুনরায় ব্যবহারযোগ্য হুক বলা যেতে পারেন useComponentVisible

import { useState, useEffect, useRef } from 'react';

export default function useComponentVisible(initialIsVisible) {
    const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
    const ref = useRef(null);

    const handleClickOutside = (event) => {
        if (ref.current && !ref.current.contains(event.target)) {
            setIsComponentVisible(false);
        }
    };

    useEffect(() => {
        document.addEventListener('click', handleClickOutside, true);
        return () => {
            document.removeEventListener('click', handleClickOutside, true);
        };
    });

    return { ref, isComponentVisible, setIsComponentVisible };
}

তারপরে উপাদানটিতে আপনি নিম্নলিখিতটি করতে কার্যকারিতা যুক্ত করতে চান:

const DropDown = () => {
    const { ref, isComponentVisible } = useComponentVisible(true);
    return (
       <div ref={ref}>
          {isComponentVisible && (<p>Dropdown Component</p>)}
       </div>
    );

}

একটি কোডস্যান্ডবক্সের উদাহরণ এখানে সন্ধান করুন।


1
@ লাইহানকিয়েল সম্পূর্ণরূপে নয় - এই উত্তর ইভেন্ট হ্যান্ডলিংয়ের ক্যাপচার পর্বের সময় ইভেন্ট হ্যান্ডলারদের আহ্বান জানায়, অন্যদিকে বুদ্বুদ পর্যায়ের সময় ইভেন্ট হ্যান্ডলারদের সাথে যুক্ত উত্তরটি যুক্ত হয়।
স্টিভজয়

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

1
ReactDOM.findDOMNodeএবং অবহেলিত হয়েছে, refকলব্যাকগুলি ব্যবহার করা উচিত : github.com/yannickcr/eslint-plugin-react/issues/…
ডেইন

2
দুর্দান্ত এবং পরিষ্কার সমাধান
করিম

1
এটি আমার পক্ষে কাজ করেছে যদিও 200 মিমি পরে আমাকে সত্য থেকে পুনরায় সেট করতে আপনার উপাদানটি হ্যাক করতে হয়েছিল (অন্যথায় আমার মেনুটি আর কখনও দেখায় না)। ধন্যবাদ!
লি মো মো

87

এখানে অনেকগুলি পদ্ধতি চেষ্টা করার পরে, আমি কতটা সম্পূর্ণ তাড়িত কারণে github.com/Pomax/react-onclickoutside ব্যবহার করার সিদ্ধান্ত নিয়েছি ।

আমি এনডিএম এর মাধ্যমে মডিউলটি ইনস্টল করেছি এবং এটি আমার উপাদানটিতে আমদানি করেছি:

import onClickOutside from 'react-onclickoutside'

তারপরে, আমার উপাদান শ্রেণিতে আমি handleClickOutsideপদ্ধতিটি সংজ্ঞায়িত করেছি :

handleClickOutside = () => {
  console.log('onClickOutside() method called')
}

এবং আমার উপাদানটি রপ্তানি করার সময় আমি এটিকে গুটিয়ে রেখেছিলাম onClickOutside():

export default onClickOutside(NameOfComponent)

এটাই.


2
পাবলো প্রস্তাবিত tabIndex/ onBlurপদ্ধতির উপর দিয়ে কি এর কোনও কংক্রিট সুবিধা রয়েছে ? বাস্তবায়ন কীভাবে কাজ করে এবং এর আচরণের onBlurপদ্ধতির থেকে কীভাবে আলাদা হয় ?
মার্ক

4
এটি একটি ট্যাবআইন্ডেক্স হ্যাক ব্যবহার করে একটি নিবেদিত উপাদান ব্যবহারকারীর পক্ষে আরও ভাল। এটি উজ্জীবিত!
অতুল যাদব

5
@ মার্ক অ্যামেরি - আমি এই tabIndex/onBlurপদ্ধতির বিষয়ে মন্তব্য করেছি । ড্রপডাউনটি যেমন কাজ করে না position:absoluteযেমন মেনু অন্য সামগ্রীগুলির উপর ঘুরে বেড়ায়।
বিউ স্মিথ

4
এই ওভার ট্যাবিনডেক্সটি ব্যবহার করার আরেকটি সুবিধা হ'ল আপনি যদি কোনও শিশু উপাদানের দিকে মনোনিবেশ করেন তবে ট্যাবিনডেক্স সমাধানটিও একটি ঝাপসা ঘটনা
ঘটায়

1
@ বিউসমিথ - অনেক অনেক ধন্যবাদ! আমার দিন বাঁচা!
মিকা

38

আমি বেন Alpert একটি সমাধান ধন্যবাদ পাওয়া discuss.reactjs.org । প্রস্তাবিত পদ্ধতির দস্তাবেজটিতে একটি হ্যান্ডলার সংযুক্ত করে তবে এটি সমস্যাযুক্ত হিসাবে প্রমাণিত। আমার গাছের উপাদানগুলির একটিতে ক্লিক করার ফলে একটি রিরেন্ডার তৈরি হয়েছিল যা আপডেটে ক্লিক করা উপাদানগুলি সরিয়ে দেয়। কারণ ডকুমেন্টের বডি হ্যান্ডলার বলার আগেই প্রতিক্রিয়া থেকে রেন্ডারটি ঘটে , কারণ উপাদানটি গাছটির "অভ্যন্তর" হিসাবে সনাক্ত করা যায় নি।

এর সমাধান হ'ল অ্যাপ্লিকেশন রুট উপাদানটিতে হ্যান্ডলার যুক্ত করা।

প্রধান:

window.__myapp_container = document.getElementById('app')
React.render(<App/>, window.__myapp_container)

উপাদান:

import { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';

export default class ClickListener extends Component {

  static propTypes = {
    children: PropTypes.node.isRequired,
    onClickOutside: PropTypes.func.isRequired
  }

  componentDidMount () {
    window.__myapp_container.addEventListener('click', this.handleDocumentClick)
  }

  componentWillUnmount () {
    window.__myapp_container.removeEventListener('click', this.handleDocumentClick)
  }

  /* using fat arrow to bind to instance */
  handleDocumentClick = (evt) => {
    const area = ReactDOM.findDOMNode(this.refs.area);

    if (!area.contains(evt.target)) {
      this.props.onClickOutside(evt)
    }
  }

  render () {
    return (
      <div ref='area'>
       {this.props.children}
      </div>
    )
  }
}

8
প্রতিক্রিয়া ০.০৪..7 নিয়ে এটি আমার পক্ষে আর কাজ করে না - প্রতিক্রিয়া কিছু বদলেছে, বা প্রতিক্রিয়াতে সমস্ত পরিবর্তনগুলির সাথে কোডটি মানিয়ে নেওয়ার সময় আমি একটি ত্রুটি করেছি। আমি পরিবর্তে github.com/Pomax/react-onclickoutside ব্যবহার করছি যা একটি মতো কাজ করে।
নিকোল

1
হুম। এটি কাজ করার কোনও কারণ আমি দেখছি না। অ্যাপ্লিকেশনটির রুট ডিওএম নোডের কোনও হ্যান্ডলার যদি অন্য হ্যান্ডলারের দ্বারা রেন্ডারটি না জমানোর আগে চালিত হয় তার আগে গুলি চালানোর নিশ্চয়তা দেওয়া উচিত কেন document?
মার্ক আমেরিকা

1
একটি খাঁটি ইউএক্স পয়েন্ট: mousedownসম্ভবত clickএখান থেকে ভাল হ্যান্ডলার হতে পারে । বেশিরভাগ অ্যাপ্লিকেশনগুলিতে, ক্লোজ-মেনু-ক্লিক-বাইরের আচরণ এমন মুহুর্ত হয় যখন আপনি মাউস ডাউন করেন, যখন আপনি প্রকাশ করেন না। উদাহরণস্বরূপ, স্ট্যাক ওভারফ্লো এর পতাকা বা ভাগ করে নেওয়ার ডায়ালগ সহ বা আপনার ব্রাউজারের শীর্ষ মেনু বার থেকে ড্রপডাউনগুলির একটি দিয়ে এটি ব্যবহার করে দেখুন।
মার্ক আমেরিকা

ReactDOM.findDOMNodeএবং স্ট্রিংটি অবহেলা করাref হয়েছে, refকলব্যাকগুলি ব্যবহার করা উচিত : github.com/yannickcr/eslint-plugin-react/issues/…
ডেইন

এটি সর্বাধিক সহজ সমাধান এবংdocument
ফ্লিয়নে

37

জেএসকনফ হাওয়াই 2020 এ ট্যানার লিন্সলের দুর্দান্ত আলাপের ভিত্তিতে হুক বাস্তবায়ন :

useOuterClick হুক এপিআই

const Client = () => {
  const innerRef = useOuterClick(ev => { /* what you want do on outer click */ });
  return <div ref={innerRef}> Inside </div> 
};

বাস্তবায়ন

/*
  Custom Hook
*/
function useOuterClick(callback) {
  const innerRef = useRef();
  const callbackRef = useRef();

  // set current callback in ref, before second useEffect uses it
  useEffect(() => { // useEffect wrapper to be safe for concurrent mode
    callbackRef.current = callback;
  });

  useEffect(() => {
    document.addEventListener("click", handleClick);
    return () => document.removeEventListener("click", handleClick);

    // read most recent callback and innerRef dom node from refs
    function handleClick(e) {
      if (
        innerRef.current && 
        callbackRef.current &&
        !innerRef.current.contains(e.target)
      ) {
        callbackRef.current(e);
      }
    }
  }, []); // no need for callback + innerRef dep
  
  return innerRef; // return ref; client can omit `useRef`
}

/*
  Usage 
*/
const Client = () => {
  const [counter, setCounter] = useState(0);
  const innerRef = useOuterClick(e => {
    // counter state is up-to-date, when handler is called
    alert(`Clicked outside! Increment counter to ${counter + 1}`);
    setCounter(c => c + 1);
  });
  return (
    <div>
      <p>Click outside!</p>
      <div id="container" ref={innerRef}>
        Inside, counter: {counter}
      </div>
    </div>
  );
};

ReactDOM.render(<Client />, document.getElementById("root"));
#container { border: 1px solid red; padding: 20px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js" integrity="sha256-Ef0vObdWpkMAnxp39TYSLVS/vVUokDE8CDFnx7tjY6U=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js" integrity="sha256-p2yuFdE8hNZsQ31Qk+s8N+Me2fL5cc6NKXOC0U9uGww=" crossorigin="anonymous"></script>
<script> var {useRef, useEffect, useCallback, useState} = React</script>
<div id="root"></div>

useOuterClick ব্যবহার করে জন্য একটি হাতা এপিআই তৈরি করতে পরিবর্তনীয় রেফ ব্যবহার করে Client। একটি কলব্যাক এর মাধ্যমে স্মরণে না রেখে সেট করা যেতে পারে useCallback। কলব্যাকের বডিটিতে এখনও সর্বাধিক সাম্প্রতিক প্রপস এবং রাজ্যে অ্যাক্সেস রয়েছে (কোনও বাসি বন্ধের মান নেই)।


আইওএস ব্যবহারকারীদের জন্য নোট

আইওএস কেবলমাত্র নির্দিষ্ট উপাদানকে ক্লিকযোগ্য হিসাবে বিবেচনা করে। এই আচরণটি ছিন্ন করতে, এর চেয়ে আলাদা বাইরের ক্লিক শ্রোতা চয়ন করুন document- এর সাথে উপরের কিছুই নয় body। যেমন আপনি divউপরের উদাহরণে প্রতিক্রিয়া মূলটিতে শ্রোতা যুক্ত করতে এবং height: 100vhবাইরের সমস্ত ক্লিকগুলি ধরার জন্য এর উচ্চতা ( বা অনুরূপ) প্রসারিত করতে পারেন। সূত্র: quirksmode.org এবং এই উত্তর


মোবাইলে এত অবিস্মরণীয় কাজ করে না
ওমর

@ ওমর একটি অ্যান্ড্রয়েড ডিভাইসে ফায়ারফক্স 67 67.০.৩ এর সাথে আমার পোস্টে কোডস্যান্ডবক্সটি পরীক্ষা করেছেন - সব ঠিকঠাক কাজ করে। আপনি কোন ব্রাউজারটি ব্যবহার করেন, ত্রুটিটি কী কী তা ব্যাখ্যা করতে পারেন?
ফরড04

কোনও ত্রুটি নেই তবে ক্রোম, আইফোন 7+ এ কাজ করে না। এটি বাইরে কলগুলি সনাক্ত করতে পারে না। মোবাইলে ক্রোম ডেভ সরঞ্জামগুলিতে এটি কাজ করে তবে একটি সত্য আইওএস ডিভাইসে এটি কাজ করে না।
ওমর

1
@ ফরড04 এটি খনন করার জন্য আপনাকে ধন্যবাদ, আমি নিম্নলিখিত কৌশলটির পরামর্শ দিচ্ছিলাম এমন অন্য একটি থ্রেডে হোঁচট খেয়েছি । @media (hover: none) and (pointer: coarse) { body { cursor:pointer } }এটি আমার বৈশ্বিক শৈলীতে যুক্ত করার ফলে সমস্যাটি স্থির হয়েছে বলে মনে হয়।
কোস্টাস সরানটোপলাস

1
@ ফরড0৪ হ্যাঁ, বিটিডব্লিউ এই থ্রেড অনুসারে আরও একটি নির্দিষ্ট মিডিয়া ক্যোয়ারী রয়েছে @supports (-webkit-overflow-scrolling: touch)যা কেবলমাত্র আইওএসকে লক্ষ্য করে তোলে যদিও আমি আরও কতটা জানি না! আমি এটি পরীক্ষা করেছি এবং এটি কাজ করে।
কোস্তাস সরানটোপলস

30

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

এখানে আমার কাছে কাজ করার মত একটি পদ্ধতি রয়েছে:

// Inside the component:
onBlur(event) {
    // currentTarget refers to this component.
    // relatedTarget refers to the element where the user clicked (or focused) which
    // triggered this event.
    // So in effect, this condition checks if the user clicked outside the component.
    if (!event.currentTarget.contains(event.relatedTarget)) {
        // do your thing.
    }
},

আশাকরি এটা সাহায্য করবে.


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

1
ধন্যবাদ! আমাকে অনেক সাহায্য করুন।
অ্যাঞ্জেলো লুকাস

1
আমি এই পদ্ধতিগুলিতে সংযুক্ত হওয়ার চেয়ে ভাল এটি পছন্দ করি document। ধন্যবাদ।
kyw

এটি কাজ করার জন্য আপনাকে নিশ্চিত হওয়া দরকার যে ক্লিক করা উপাদান (সম্পর্কিত টার্গেট) ফোকাসযোগ্য। দেখুন stackoverflow.com/questions/42764494/...
xabitrigo

21

[আপডেট] সঙ্গে সমাধান প্রতিক্রিয়া ^ 16.8 ব্যবহার হুক্স

CodeSandbox

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

const SampleComponent = () => {
    const [clickedOutside, setClickedOutside] = useState(false);
    const myRef = useRef();

    const handleClickOutside = e => {
        if (!myRef.current.contains(e.target)) {
            setClickedOutside(true);
        }
    };

    const handleClickInside = () => setClickedOutside(false);

    useEffect(() => {
        document.addEventListener('mousedown', handleClickOutside);
        return () => document.removeEventListener('mousedown', handleClickOutside);
    });

    return (
        <button ref={myRef} onClick={handleClickInside}>
            {clickedOutside ? 'Bye!' : 'Hello!'}
        </button>
    );
};

export default SampleComponent;

প্রতিক্রিয়া সহ সমাধান ^ 16.3 :

CodeSandbox

import React, { Component } from "react";

class SampleComponent extends Component {
  state = {
    clickedOutside: false
  };

  componentDidMount() {
    document.addEventListener("mousedown", this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClickOutside);
  }

  myRef = React.createRef();

  handleClickOutside = e => {
    if (!this.myRef.current.contains(e.target)) {
      this.setState({ clickedOutside: true });
    }
  };

  handleClickInside = () => this.setState({ clickedOutside: false });

  render() {
    return (
      <button ref={this.myRef} onClick={this.handleClickInside}>
        {this.state.clickedOutside ? "Bye!" : "Hello!"}
      </button>
    );
  }
}

export default SampleComponent;

3
এটি এখন গ-টু সমাধান। আপনি যদি ত্রুটিটি পেয়ে থাকেন তবে .contains is not a functionএটি হতে পারে কারণ আপনি কোনও সত্যিকারের ডোম উপাদানটির পরিবর্তে একটি কাস্টম উপাদানকে রেফ প্রোপ দিচ্ছেন<div>
উইল্লমা

যারা refকাস্টম উপাদানটিতে React.forwardRef
প্রপোস

4

এখানে আমার পদ্ধতির (ডেমো - https://jsfiddle.net/agymay93/4/ ):

আমি নামক একটি বিশেষ উপাদান তৈরি করেছি WatchClickOutsideএবং এটি ব্যবহার করা যেতে পারে (আমি JSXসিনট্যাক্স ধরে নিই ):

<WatchClickOutside onClickOutside={this.handleClose}>
  <SomeDropdownEtc>
</WatchClickOutside>

এখানে WatchClickOutsideউপাদানগুলির কোড রয়েছে :

import React, { Component } from 'react';

export default class WatchClickOutside extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

  componentWillMount() {
    document.body.addEventListener('click', this.handleClick);
  }

  componentWillUnmount() {
    // remember to remove all events to avoid memory leaks
    document.body.removeEventListener('click', this.handleClick);
  }

  handleClick(event) {
    const {container} = this.refs; // get container that we'll wait to be clicked outside
    const {onClickOutside} = this.props; // get click outside callback
    const {target} = event; // get direct click event target

    // if there is no proper callback - no point of checking
    if (typeof onClickOutside !== 'function') {
      return;
    }

    // if target is container - container was not clicked outside
    // if container contains clicked target - click was not outside of it
    if (target !== container && !container.contains(target)) {
      onClickOutside(event); // clicked outside - fire callback
    }
  }

  render() {
    return (
      <div ref="container">
        {this.props.children}
      </div>
    );
  }
}

দুর্দান্ত সমাধান - আমার ব্যবহারের জন্য, আমি স্বল্প বিষয়বস্তুযুক্ত পৃষ্ঠাগুলির ক্ষেত্রে শরীরের পরিবর্তে নথিটি শোনার জন্য পরিবর্তন করেছি এবং স্ট্রিং থেকে ডোম রেফারেন্সে পরিবর্তন করেছি: jsfiddle.net/agymay93/9
বিলি মুন

লেআউট পরিবর্তনের সম্ভাবনা কম থাকায় এবং ডিভের
বিলি মুন

স্ট্রিংটি refঅবচিত করা হয়েছে, refকলব্যাকগুলি ব্যবহার করা উচিত : reactjs.org/docs/refs-and-the-dom.html
dain

4

এর ইতিমধ্যে অনেক উত্তর রয়েছে তবে তারা সমাধান করতে পারে না e.stopPropagation()এবং আপনি যে উপাদানটি বন্ধ করতে চান তার বাইরে প্রতিক্রিয়া লিঙ্কগুলিতে ক্লিক করা বাধা দেয় না।

প্রতিক্রিয়াটির নিজস্ব কৃত্রিম ইভেন্ট হ্যান্ডলার রয়েছে এমন কারণে আপনি ইভেন্ট শ্রোতার জন্য বেস হিসাবে নথিটি ব্যবহার করতে পারবেন না। e.stopPropagation()প্রতিক্রিয়াটি ডকুমেন্টটি নিজেই ব্যবহার করে এমনটি আগে আপনার করা দরকার । আপনি যদি document.querySelector('body')পরিবর্তে উদাহরণস্বরূপ ব্যবহার করেন। আপনি প্রতিক্রিয়া লিঙ্ক থেকে ক্লিক প্রতিরোধ করতে সক্ষম। নীচে আমি কীভাবে বাইরের ক্লিক প্রয়োগ করি এবং বন্ধ করি তার একটি উদাহরণ is
এটি ES6 এবং 16.3 প্রতিক্রিয়া ব্যবহার করে ।

import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      isOpen: false,
    };

    this.insideContainer = React.createRef();
  }

  componentWillMount() {
    document.querySelector('body').addEventListener("click", this.handleClick, false);
  }

  componentWillUnmount() {
    document.querySelector('body').removeEventListener("click", this.handleClick, false);
  }

  handleClick(e) {
    /* Check that we've clicked outside of the container and that it is open */
    if (!this.insideContainer.current.contains(e.target) && this.state.isOpen === true) {
      e.preventDefault();
      e.stopPropagation();
      this.setState({
        isOpen: false,
      })
    }
  };

  togggleOpenHandler(e) {
    e.preventDefault();

    this.setState({
      isOpen: !this.state.isOpen,
    })
  }

  render(){
    return(
      <div>
        <span ref={this.insideContainer}>
          <a href="#open-container" onClick={(e) => this.togggleOpenHandler(e)}>Open me</a>
        </span>
        <a href="/" onClick({/* clickHandler */})>
          Will not trigger a click when inside is open.
        </a>
      </div>
    );
  }
}

export default App;

3

যাদের নিখুঁত পজিশনিং দরকার, তাদের জন্য একটি সহজ বিকল্প আমি বেছে নিয়েছি a তারপরে আপনি নিজের অভ্যন্তর উপাদানটি বন্ধ করতে এই উপাদানটিতে একটি অনক্লিক যুক্ত করতে পারেন।

<div style={{
        position: 'fixed',
        top: '0', right: '0', bottom: '0', left: '0',
        zIndex: '1000',
      }} onClick={() => handleOutsideClick()} >
    <Content style={{position: 'absolute'}}/>
</div>

এখনই যেমন আপনি লিখিত সামগ্রীতে ক্লিক হ্যান্ডলার যুক্ত করেন, ইভেন্টটি ওপরের ডিভিতেও প্রচার করা হবে এবং তাই হ্যান্ডলারআউটসাইড ক্লিককে ট্রিগার করুন। এটি যদি আপনার কাঙ্ক্ষিত আচরণ না হয় তবে আপনার হ্যান্ডলারের ইভেন্টের অগ্রগতি কেবল থামিয়ে দিন।

<Content style={{position: 'absolute'}} onClick={e => {
                                          e.stopPropagation();
                                          desiredFunctionCall();
                                        }}/>

`


এই পদ্ধতির সাথে সমস্যাটি হ'ল আপনার সামগ্রীতে কোনও ক্লিক থাকতে পারে না - পরিবর্তে ডিভটি ক্লিকটি পাবেন receive
রবোনিক

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

3

বেন বাডের গৃহীত উত্তরের উত্তরটি প্রসারিত করতে , আপনি যদি স্টাইলযুক্ত উপাদান ব্যবহার করে থাকেন তবে এইভাবে রেফগুলি পাস করা আপনাকে একটি ত্রুটি দেয় যেমন "this.wrapperRef.contains কোনও ফাংশন নয়"।

প্রস্তাবিত ফিক্স, মন্তব্যে স্টাইলযুক্ত উপাদানটি একটি ডিভের সাথে আবৃত করতে এবং সেখানে রেফটি পাস করার জন্য, কাজ করে। এই বলে যে, তাদের দস্তাবেজে তারা ইতিমধ্যে স্টাইল্ড-উপাদানগুলির মধ্যে রেফের যথাযথ ব্যবহারের কারণ ব্যাখ্যা করেছে:

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

তাই ভালো:

<StyledDiv innerRef={el => { this.el = el }} />

তারপরে আপনি এটিকে সরাসরি "হ্যান্ডেলক্লিকআউটসাইড" ফাংশনের মধ্যে অ্যাক্সেস করতে পারবেন:

handleClickOutside = e => {
    if (this.el && !this.el.contains(e.target)) {
        console.log('clicked outside')
    }
}

এটি "অনব্লুর" পদ্ধতির জন্যও প্রযোজ্য:

componentDidMount(){
    this.el.focus()
}
blurHandler = () => {
    console.log('clicked outside')
}
render(){
    return(
        <StyledDiv
            onBlur={this.blurHandler}
            tabIndex="0"
            innerRef={el => { this.el = el }}
        />
    )
}

3

এই সমস্যাটি সমাধান করার জন্য ম্যাটারিয়াল-ইউআইয়ের একটি ছোট্ট উপাদান রয়েছে: https://matory-ui.com/components/click-away-listener/ যে আপনি এটি চেরি-বাছাই করতে পারেন। এটি 1.5 কেবি ওজনের গিজিপযুক্ত, এটি মোবাইল, আইই 11 এবং পোর্টাল সমর্থন করে।


2

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

উদাহরণ কোড

#HTML
<div className="parent">
  <div className={`dropdown ${this.state.open ? open : ''}`}>
    ...content
  </div>
  <div className="outer-handler" onClick={() => this.setState({open: false})}>
  </div>
</div>

#SASS
.dropdown {
  display: none;
  position: absolute;
  top: 0px;
  left: 0px;
  z-index: 100;
  &.open {
    display: block;
  }
}
.outer-handler {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0;
    z-index: 99;
    display: none;
    &.open {
      display: block;
    }
}

1
হুঁ নিফটি। এটি একাধিক উদাহরণ দিয়ে কাজ করবে? অথবা প্রতিটি স্থির উপাদান অন্যদের জন্য সম্ভাব্যভাবে ক্লিকটি ব্লক করবে?
থিজস কোয়ারসেলম্যান

2
componentWillMount(){

  document.addEventListener('mousedown', this.handleClickOutside)
}

handleClickOutside(event) {

  if(event.path[0].id !== 'your-button'){
     this.setState({showWhatever: false})
  }
}

ইভেন্টটি path[0]ক্লিক করা সর্বশেষ আইটেম


3
উপাদানটি মেমরি পরিচালনার সমস্যাগুলি রোধ করার জন্য উপাদানটি আনমাউন্ট করার সময় আপনি ইভেন্ট শ্রোতাদের সরানোর বিষয়টি নিশ্চিত করুন
agm1984

2

আমি এই মডিউলটি ব্যবহার করেছি (লেখকের সাথে আমার কোনও সম্পর্ক নেই)

npm install react-onclickout --save

const ClickOutHandler = require('react-onclickout');
 
class ExampleComponent extends React.Component {
 
  onClickOut(e) {
    if (hasClass(e.target, 'ignore-me')) return;
    alert('user clicked outside of the component!');
  }
 
  render() {
    return (
      <ClickOutHandler onClickOut={this.onClickOut}>
        <div>Click outside of me!</div>
      </ClickOutHandler>
    );
  }
}

এটা সুন্দরভাবে কাজ করেছে।


এটি দুর্দান্ত কাজ করে! এখানে অন্য অনেক উত্তরগুলির চেয়ে সহজ এবং এখানে কমপক্ষে 3 টি অন্যান্য সমাধানের বিপরীতে যেখানে "Support for the experimental syntax 'classProperties' isn't currently enabled"এই সকলের জন্য আমি এইটি সরাসরি বাক্সে কাজ করেছি। যে কেউ এই সমাধানটি চেষ্টা করছেন তার জন্য, অন্য সমাধানগুলি চেষ্টা করার সময় আপনি যে অনুলিপি কোডটি অনুলিপি করেছেন তা মুছে ফেলতে ভুলবেন না। উদাহরণস্বরূপ ইভেন্ট শ্রোতাদের সাথে এটি যুক্ত হয় না।
ফ্রিকস্টার

2

আমি এই ব্যাপারে কিছুটা অনুসরণ করে এই করেনি এই এবং নিম্নলিখিত refs হ্যান্ডলিং অফিসিয়াল ডক্স যা প্রতিক্রিয়া ^ 16.3 প্রয়োজন প্রতিক্রিয়া দ্বারা। এখানে অন্যান্য পরামর্শের কিছু চেষ্টা করার পরে এটিই আমার পক্ষে কাজ করেছে ...

class App extends Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }
  componentWillMount() {
    document.addEventListener("mousedown", this.handleClick, false);
  }
  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClick, false);
  }
  handleClick = e => {
    if (this.inputRef.current === e.target) {
      return;
    }
    this.handleclickOutside();
  };
handleClickOutside(){
...***code to handle what to do when clicked outside***...
}
render(){
return(
<div>
...***code for what's outside***...
<span ref={this.inputRef}>
...***code for what's "inside"***...
</span>
...***code for what's outside***
)}}

1

কৌশল সঙ্গে একটি উদাহরণ

আমি সরবরাহিত সমাধানগুলি পছন্দ করি যা উপাদানগুলির চারপাশে মোড়ক তৈরি করে একই জিনিসটি ব্যবহার করে।

যেহেতু এটি কৌশল সম্পর্কে আমি বেশি চিন্তা করি এবং নিম্নলিখিতগুলি নিয়ে এসেছি।

আমি প্রতিক্রিয়া সহ নতুন এবং ব্যবহারের ক্ষেত্রে কিছু বয়লারপ্লেট সংরক্ষণ করতে আমার কিছুটা সহায়তা প্রয়োজন

দয়া করে পর্যালোচনা করুন এবং আপনি কী মনে করেন আমাকে বলুন।

ClickOutsideBehavior

import ReactDOM from 'react-dom';

export default class ClickOutsideBehavior {

  constructor({component, appContainer, onClickOutside}) {

    // Can I extend the passed component's lifecycle events from here?
    this.component = component;
    this.appContainer = appContainer;
    this.onClickOutside = onClickOutside;
  }

  enable() {

    this.appContainer.addEventListener('click', this.handleDocumentClick);
  }

  disable() {

    this.appContainer.removeEventListener('click', this.handleDocumentClick);
  }

  handleDocumentClick = (event) => {

    const area = ReactDOM.findDOMNode(this.component);

    if (!area.contains(event.target)) {
        this.onClickOutside(event)
    }
  }
}

নমুনা ব্যবহার

import React, {Component} from 'react';
import {APP_CONTAINER} from '../const';
import ClickOutsideBehavior from '../ClickOutsideBehavior';

export default class AddCardControl extends Component {

  constructor() {
    super();

    this.state = {
      toggledOn: false,
      text: ''
    };

    this.clickOutsideStrategy = new ClickOutsideBehavior({
      component: this,
      appContainer: APP_CONTAINER,
      onClickOutside: () => this.toggleState(false)
    });
  }

  componentDidMount () {

    this.setState({toggledOn: !!this.props.toggledOn});
    this.clickOutsideStrategy.enable();
  }

  componentWillUnmount () {
    this.clickOutsideStrategy.disable();
  }

  toggleState(isOn) {

    this.setState({toggledOn: isOn});
  }

  render() {...}
}

মন্তব্য

আমি উত্তীর্ণ componentজীবনচক্রের হুকগুলি সংরক্ষণ করার এবং পদ্ধতিগুলির সিমিলারের সাহায্যে এগুলিকে ওভাররাইড করার চিন্তা করেছি:

const baseDidMount = component.componentDidMount;

component.componentDidMount = () => {
  this.enable();
  baseDidMount.call(component)
}

componentএর কনস্ট্রাক্টরের কাছে দেওয়া উপাদানটি ClickOutsideBehavior
এটি এই আচরণের ব্যবহারকারীর কাছ থেকে সক্ষম / অক্ষম বয়লারপ্লেটটি সরিয়ে ফেলবে তবে এটি খুব সুন্দর দেখাচ্ছে না


1

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

import React, { useRef, useEffect, useState } from "react";

/**
 * Hook that triggers onClose when clicked outside of ref and buttonRef elements
 */
function useOutsideClicker(ref, buttonRef, onOutsideClick) {
  useEffect(() => {

    function handleClickOutside(event) {
      /* clicked on the element itself */
      if (ref.current && !ref.current.contains(event.target)) {
        return;
      }

      /* clicked on the toggle button */
      if (buttonRef.current && !buttonRef.current.contains(event.target)) {
        return;
      }

      /* If it's something else, trigger onClose */
      onOutsideClick();
    }

    // Bind the event listener
    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      // Unbind the event listener on clean up
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [ref]);
}

/**
 * Component that alerts if you click outside of it
 */
export default function DropdownMenu(props) {
  const wrapperRef = useRef(null);
  const buttonRef = useRef(null);
  const [dropdownVisible, setDropdownVisible] = useState(false);

  useOutsideClicker(wrapperRef, buttonRef, closeDropdown);

  const toggleDropdown = () => setDropdownVisible(visible => !visible);

  const closeDropdown = () => setDropdownVisible(false);

  return (
    <div>
      <button onClick={toggleDropdown} ref={buttonRef}>Dropdown Toggler</button>
      {dropdownVisible && <div ref={wrapperRef}>{props.children}</div>}
    </div>
  );
}

0

আপনি যদি এই কার্যকারিতার জন্য ইতিমধ্যে বিদ্যমান একটি ক্ষুদ্র উপাদান (466 বাইট জিপিড) ব্যবহার করতে চান তবে আপনি এই লাইব্রেরিটি প্রতিক্রিয়া-আউটলিক ক্লিক করতে পারেন

লাইব্রেরি সম্পর্কে ভাল জিনিস এটি আপনাকে উপাদানগুলির বাইরে এবং অন্যটির অভ্যন্তরে ক্লিকগুলি সনাক্ত করতে দেয়। এটি অন্যান্য ধরণের ইভেন্টগুলি সনাক্ত করতে সহায়তা করে।


0

যদি আপনি একটি ক্ষুদ্র উপাদান (466 বাইট জিজেপড) ব্যবহার করতে চান যা ইতিমধ্যে এই কার্যকারিতার জন্য বিদ্যমান রয়েছে তবে আপনি এই লাইব্রেরিটি প্রতিক্রিয়া-আউটলিক ক্লিক করে দেখতে পারেন । এটি প্রতিক্রিয়া উপাদান বা জেএসএক্স উপাদানগুলির বাইরে ইভেন্টগুলি ক্যাপচার করে।

লাইব্রেরি সম্পর্কে ভাল জিনিস এটি আপনাকে উপাদানগুলির বাইরে এবং অন্যটির অভ্যন্তরে ক্লিকগুলি সনাক্ত করতে দেয়। এটি অন্যান্য ধরণের ইভেন্টগুলি সনাক্ত করতে সহায়তা করে।


0

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

উদাহরণ:

hideresults(){
   this.setState({show:false})
}
render(){
 return(
 <div><div onClick={() => this.setState({show:true})}>SHOW</div> {(this.state.show)? <OutsideClickHandler onOutsideClick={() => 
  {this.hideresults()}} > <div className="insideclick"></div> </OutsideClickHandler> :null}</div>
 )
}

0
import { useClickAway } from "react-use";

useClickAway(ref, () => console.log('OUTSIDE CLICKED'));

0

আপনি আপনার সমস্যা সমাধানের একটি সহজ উপায় করতে পারেন, আমি আপনাকে দেখাব:

....

const [dropDwonStatus , setDropDownStatus] = useState(false)

const openCloseDropDown = () =>{
 setDropDownStatus(prev => !prev)
}

const closeDropDown = ()=> {
 if(dropDwonStatus){
   setDropDownStatus(false)
 }
}
.
.
.
<parent onClick={closeDropDown}>
 <child onClick={openCloseDropDown} />
</parent>

এটি আমার পক্ষে কাজ করে, সৌভাগ্য;)


-1

আমি এটি নীচের নিবন্ধ থেকে পেয়েছি:

রেন্ডার () {রিটার্ন ({this.node = নোড;}}> পপওভার টগল করুন {this.state.popup ভিজিবল && (আমি একটি পপওভার!);); }}

এই সমস্যাটি সম্পর্কে এখানে একটি দুর্দান্ত নিবন্ধটি দেওয়া হয়েছে: "প্রতিক্রিয়া উপাদানগুলির বাইরে ক্লিকগুলি পরিচালনা করুন" https://larsgraubner.com/handle-outside-clicks-react/


স্ট্যাক ওভারফ্লোতে স্বাগতম! কেবলমাত্র একটি লিঙ্ক হিসাবে দেওয়া উত্তরগুলি সাধারণত:: মেটা.স্ট্যাকওভারফ্লো / প্রশ্ন / 251006 /… তে নষ্ট হয় । ভবিষ্যতে, প্রশ্নের সাথে সম্পর্কিত তথ্য সহ একটি উদ্ধৃতি বা কোড উদাহরণ অন্তর্ভুক্ত করুন। চিয়ার্স!
ফ্রেড স্টার্ক

-1

onClickআপনার শীর্ষ স্তরের ধারকটিতে একটি হ্যান্ডলার যুক্ত করুন এবং যখনই ব্যবহারকারী ভিতরে ক্লিক করে একটি রাষ্ট্রীয় মান বৃদ্ধি করুন। প্রাসঙ্গিক উপাদানটিতে যখনই মানটি পাস করুন এবং যখনই মান পরিবর্তন করে আপনি কাজ করতে পারেন।

এই ক্ষেত্রে this.closeDropdown()যখনই clickCountমান পরিবর্তন হয় আমরা কল করছি ।

incrementClickCountমধ্যে পদ্ধতি দাবানল .appধারক কিন্তু .dropdownকারণ আমরা ব্যবহার event.stopPropagation()ঘটনা সাড়া জাগানো প্রতিরোধ।

আপনার কোডটি এরকম কিছু দেখতে শেষ হতে পারে:

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            clickCount: 0
        };
    }
    incrementClickCount = () => {
        this.setState({
            clickCount: this.state.clickCount + 1
        });
    }
    render() {
        return (
            <div className="app" onClick={this.incrementClickCount}>
                <Dropdown clickCount={this.state.clickCount}/>
            </div>
        );
    }
}
class Dropdown extends Component {
    constructor(props) {
        super(props);
        this.state = {
            open: false
        };
    }
    componentDidUpdate(prevProps) {
        if (this.props.clickCount !== prevProps.clickCount) {
            this.closeDropdown();
        }
    }
    toggleDropdown = event => {
        event.stopPropagation();
        return (this.state.open) ? this.closeDropdown() : this.openDropdown();
    }
    render() {
        return (
            <div className="dropdown" onClick={this.toggleDropdown}>
                ...
            </div>
        );
    }
}

কে ডাউন-ভোটিং করছে তা নিশ্চিত নন তবে বাধ্যতামূলক / আনবাইন্ডিং ইভেন্ট শ্রোতার তুলনায় এই সমাধানটি বেশ পরিষ্কার। এই বাস্তবায়নের সাথে আমার শূন্য সমস্যা রয়েছে।
wdm

-1

করতে 'ফোকাস' ঘটনা শ্রোতাকে সঙ্গে ড্রপডাউন সমাধান কাজ আপনি তাদের সঙ্গে যোগ করতে পারেন onMouseDown পরিবর্তে ঘটনা onClick । এইভাবে ইভেন্টটি চালিত হবে এবং এরপরে পপআপটি এমনভাবে বন্ধ হবে:

<TogglePopupButton
                    onClick = { this.toggleDropup }
                    tabIndex = '0'
                    onBlur = { this.closeDropup }
                />
                { this.state.isOpenedDropup &&
                <ul className = { dropupList }>
                    { this.props.listItems.map((item, i) => (
                        <li
                            key = { i }
                            onMouseDown = { item.eventHandler }
                        >
                            { item.itemName}
                        </li>
                    ))}
                </ul>
                }

-1
import ReactDOM from 'react-dom' ;

class SomeComponent {

  constructor(props) {
    // First, add this to your constructor
    this.handleClickOutside = this.handleClickOutside.bind(this);
  }

  componentWillMount() {
    document.addEventListener('mousedown', this.handleClickOutside, false); 
  }

  // Unbind event on unmount to prevent leaks
  componentWillUnmount() {
    window.removeEventListener('mousedown', this.handleClickOutside, false);
  }

  handleClickOutside(event) {
    if(!ReactDOM.findDOMNode(this).contains(event.path[0])){
       console.log("OUTSIDE");
    }
  }
}

এবং ভুলে যাবেন নাimport ReactDOM from 'react-dom';
ডিপোল_মোমেন্ট

-1

আমি সমস্ত অনুষ্ঠানের জন্য একটি সমাধান তৈরি করেছি।

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

এই উপাদানটির উদাহরণের মধ্যে একটিমাত্র প্রোপ রয়েছে: "অনিক্লিকড আউটসাইড" যা কোনও ফাংশন গ্রহণ করে।

ClickedOutside.js
import React, { Component } from "react";

export default class ClickedOutside extends Component {
  componentDidMount() {
    document.addEventListener("mousedown", this.handleClickOutside);
  }

  componentWillUnmount() {
    document.removeEventListener("mousedown", this.handleClickOutside);
  }

  handleClickOutside = event => {
    // IF exists the Ref of the wrapped component AND his dom children doesnt have the clicked component 
    if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
      // A props callback for the ClikedClickedOutside
      this.props.onClickedOutside();
    }
  };

  render() {
    // In this piece of code I'm trying to get to the first not functional component
    // Because it wouldn't work if use a functional component (like <Fade/> from react-reveal)
    let firstNotFunctionalComponent = this.props.children;
    while (typeof firstNotFunctionalComponent.type === "function") {
      firstNotFunctionalComponent = firstNotFunctionalComponent.props.children;
    }

    // Here I'm cloning the element because I have to pass a new prop, the "reference" 
    const children = React.cloneElement(firstNotFunctionalComponent, {
      ref: node => {
        this.wrapperRef = node;
      },
      // Keeping all the old props with the new element
      ...firstNotFunctionalComponent.props
    });

    return <React.Fragment>{children}</React.Fragment>;
  }
}

-1

ইউজঅনিক্লিকআউটসাইড হুক - 16.8 + প্রতিক্রিয়া জানান

একটি সাধারণ ব্যবহারঅনআউটসাইড ক্লিক ফাংশন তৈরি করুন

export const useOnOutsideClick = handleOutsideClick => {
  const innerBorderRef = useRef();

  const onClick = event => {
    if (
      innerBorderRef.current &&
      !innerBorderRef.current.contains(event.target)
    ) {
      handleOutsideClick();
    }
  };

  useMountEffect(() => {
    document.addEventListener("click", onClick, true);
    return () => {
      document.removeEventListener("click", onClick, true);
    };
  });

  return { innerBorderRef };
};

const useMountEffect = fun => useEffect(fun, []);

তারপরে কোনও কার্যকরী উপাদানগুলিতে হুক ব্যবহার করুন।

const OutsideClickDemo = ({ currentMode, changeContactAppMode }) => {

  const [open, setOpen] = useState(false);
  const { innerBorderRef } = useOnOutsideClick(() => setOpen(false));

  return (
    <div>
      <button onClick={() => setOpen(true)}>open</button>
      {open && (
        <div ref={innerBorderRef}>
           <SomeChild/>
        </div>
      )}
    </div>
  );

};

ডেমো লিঙ্ক

আংশিকভাবে @ pau1fitzgerald উত্তরে অনুপ্রাণিত।

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