Как прикрепить прослушиватели событий перетаскивания к компоненту React

Я создаю компонент, который позволяет перетаскивать локальные файлы на div. Затем выводится информация о сброшенном файле.

Моя проблема в том, что я не знаю, как правильно прикрепить прослушиватели событий drop и dragover при создании моего компонента.

Компонент My App - это то место, где находится вся моя логика (обработчик для удаления и перетаскивания), и я создал отдельный компонент, в который будут сбрасываться файлы - компонент dropZone.

Я попытался поместить прослушиватель событий в тег dropZone в моем компоненте приложения с componentDidMount, где, если мой компонент dropZone был визуализирован, поместите на него прослушиватель событий:

componentDidMount(){
      const dropZone = document.getElementById('dropZone');
      dropZone.addEventListener('dragover', this.allowDrop.bind(this))
      dropZone.addEventListener('drop', this.dropHandler.bind(this))
    } 

это не сработало

Затем я попытался поместить его в свой тег dropZone, который находится в моем компоненте приложения:

<DropZone dropZone = {"dropZone"} onDragOver = {this.allowDrop.bind(this)} 
 onDrop ={this.dropHandler.bind(this)} >      
</DropZone>

это также не добавляло прослушивателя событий в dropZone. Я пробовал еще пару вещей, но это те, над которыми я должен был работать.

Итак, мои вопросы:

  • как добавить прослушиватели событий drop и dragover в dropZone?

  • Должен ли я добавлять эти прослушиватели событий в приложение и передавать их компоненту dropZone в качестве опоры? Или нет необходимости в передаче

  • Или мне следует добавлять прослушиватели событий в dropZone напрямую, чтобы мои функции обработчика событий жили в компоненте dropZone?


person Carol Gonzalez    schedule 01.08.2016    source источник


Ответы (2)


Не нужно использовать реквизит. Вы можете просто добавить все события в свой компонент DropZone.

http://codepen.io/jzmmm/pen/bZjzxN?editors=0011

Здесь я добавляю события:

  componentDidMount() {
    window.addEventListener('mouseup', this._onDragLeave);
    window.addEventListener('dragenter', this._onDragEnter);
    window.addEventListener('dragover', this._onDragOver);
    window.addEventListener('drop', this._onDrop);
    document.getElementById('dragbox').addEventListener('dragleave', this._onDragLeave);
  }

Ваш метод рендеринга:

  render() {
    return (
      <div>
        {this.props.children}
        <div id="dragbox" className={this.state.className}>
          Drop a file to Upload
        </div>
      </div>
    );
  }

Как вы можете видеть в componentDidMount, я также добавил прослушиватель событий в #dragbox. Поскольку после того, как вы перетащите файл по странице, #dragbox окажется под курсором мыши, поэтому его нужно перетащить на случай, если вы решите, что не хотите перетаскивать файл туда.

Кроме того, dragover необходим для захвата drop

Затем в моем компоненте приложения я могу использовать его так:

class App extends React.Component {
  render() {
    return (
      <DropZone>
        <div>
          <h1>Drag A File Here...</h1>
        </div>
      </DropZone>
    );
  }
}
person mnsr    schedule 01.08.2016
comment
Спасибо, jzm! Я также решил свою проблему, добавив слушателей событий в div в компоненте dropZone и использовал слова React eventListener onDrop и onDragOver - < div id= {this.props.dropZone} onDragOver ={this.allowDrop.bind(this)} onDrop = {this.dropHandler.bind(this)}></div>, но мне нравится ваш ответ больше, потому что я вижу, что eventListeners прикреплены к методу жизненного цикла. Я также узнал, что функции для eventListeners должны быть в компоненте dropZone, так что это было здорово. Ваш ответ действительно ясен, и его легко понять! - person Carol Gonzalez; 01.08.2016

Версия ответа @mnsr с использованием библиотеки styled-components и ловушек React

const DragBox = styled.div(({ isVisible }: { isVisible }) =>
    isVisible
        ? `
        position: fixed;
        display: flex;
        border: 15px dashed white;
        width: 100%;
        height: 100%;
        z-index: 2000;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        flex: 1;
        justify-content: center;
        align-items: center;
        text-align: center;
        font-size: 30px;
        font-weight: 600;
        color: white;
        letter-spacing: 1px;
        margin: auto;
`
        : 'display: none;'
);

const DropZone = ({ children }) => {
    const [isVisible, setIsVisible] = useState(false);

    const onDragEnter = useCallback((e) => {
        setIsVisible(true);
        e.stopPropagation();
        e.preventDefault();
        return false;
    }, []);
    const onDragOver = useCallback((e) => {
        e.preventDefault();
        e.stopPropagation();
        return false;
    }, []);
    const onDragLeave = useCallback((e) => {
        setIsVisible(false);
        e.stopPropagation();
        e.preventDefault();
        return false;
    }, []);
    const onDrop = useCallback((e) => {
        e.preventDefault();
        const files = e.dataTransfer.files;
        console.log('Files dropped: ', files);
        // Upload files
        setIsVisible(false);
        return false;
    }, []);

    useEffect(() => {
        window.addEventListener('mouseup', onDragLeave);
        window.addEventListener('dragenter', onDragEnter);
        window.addEventListener('dragover', onDragOver);
        window.addEventListener('drop', onDrop);
        return () => {
            window.removeEventListener('mouseup', onDragLeave);
            window.removeEventListener('dragenter', onDragEnter);
            window.removeEventListener('dragover', onDragOver);
            window.removeEventListener('drop', onDrop);
        };
    }, [onDragEnter, onDragLeave, onDragOver, onDrop]);

    return (
        <div>
            {children}
            <DragBox
                className="bg-secondary"
                isVisible={isVisible}
                onDragLeave={onDragLeave}
            >
                Drop files to Upload
            </DragBox>
        </div>
    );
};
person Bryant    schedule 15.04.2020