구성 요소 외부에있는 클릭 이벤트를 수신하는 방법 외부에서 클릭이 발생하면 드롭 다운 메뉴를 닫고

드롭 다운 구성 요소 외부에서 클릭이 발생하면 드롭 다운 메뉴를 닫고 싶습니다.

어떻게하나요?



답변

추가 한 요소에서 다음 mousedownmouseup같이합니다.

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가죽 그것.


답변

수명주기 메서드를 사용하여 문서에 이벤트 리스너를 추가 및 제거합니다.

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/component/tube-tracker.jsx#L48-54


답변

이벤트의 대상을 살펴보십시오. 이벤트가 구성 요소에 직접 있거나 해당 구성 요소의 자식에 있으면 클릭이 내부에있는 것입니다. 그렇지 않으면 밖에있었습니다.

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>
        )
    }
});

이것이 많은 구성 요소에서 사용되는 경우 mixin을 사용하면 더 좋습니다.

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/


답변

특정 사용 사례의 경우 현재 허용되는 답변은 약간의 과잉 엔지니어링입니다. 사용자가 드롭 다운 목록을 클릭 할 때 수신 대기하려면 <select>구성 요소를 상위 요소로 사용하고onBlur 처리기를 됩니다.

이 접근 방식의 유일한 단점은 사용자가 이미 요소에 초점을 유지했다고 가정하고 양식 컨트롤에 의존한다는 것입니다 ( tab키가 요소에 초점을 맞추고 흐리게 한다는 점을 고려하면 원하는 것일 수도 있고 아닐 수도 있음). )-그러나 이러한 단점은 더 복잡한 사용 사례에 대한 제한 일 뿐이며,이 경우 더 복잡한 솔루션이 필요할 수 있습니다.

 var Dropdown = React.createClass({

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

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

답변

컴포넌트 외부에서 발생하는 이벤트에 대한 일반 이벤트 핸들러 인 react-outside-event를 작성했습니다 .

구현 자체는 간단합니다.

  • 컴포넌트가 마운트되면 이벤트 핸들러가 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']);

답변

나는 그것이 나를 위해 작동하지 않았지만 대답 중 하나에 투표했습니다. 결국 저를이 솔루션으로 이끌었습니다. 작업 순서를 약간 변경했습니다. 나는 target에서 mouseDown을, target에서 mouseUp을 듣습니다. 둘 중 하나가 TRUE를 반환하면 모달을 닫지 않습니다. 클릭이 등록 되 자마자 어디에서나 두 부울 {mouseDownOnModal, mouseUpOnModal}이 다시 false로 설정됩니다.

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>
    );
}

이것은 모든 코드가 부모가 아닌 자식 구성 요소에 있다는 이점이 있습니다. 이는이 컴포넌트를 재사용 할 때 복사 할 상용구 코드가 없음을 의미합니다.


답변

  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;
}