Регистрация нажатия на разные компоненты в React - PullRequest
0 голосов
/ 10 июля 2020

У меня есть проект с интересной дилеммой. Я создал компонент (из Рекомендуемый способ сделать React component / div перетаскиваемым ) и изменил его так, чтобы onMouseDown находился только в элементе, а не в документе. На той же странице у меня есть событие, которое не регистрирует событие щелчка, хотя оно получает фокус при щелчке правой кнопкой мыши. Я прилагаю сюда весь свой код как элемента, так и макета ввода, если кто-нибудь может определить, почему я не могу щелкнуть, чтобы сосредоточиться на вводе текста.

Перетаскиваемый. js

import React from 'react';
import PropTypes from 'prop-types';

class Draggable extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            relX: 0,
            relY: 0,
            x: parseInt(props.left),
            y: parseInt(props.top),
            dragged: false
        };
        this.gridX = props.gridX || 2;
        this.gridY = props.gridY || 2;
        this.onMouseDown = this.onMouseDown.bind(this);
        this.onMouseMove = this.onMouseMove.bind(this);
        this.onMouseUp = this.onMouseUp.bind(this);
        this.onContext = this.onContext.bind(this);
        this.clickRef = React.createRef();
    }

    static propTypes = {
        onMove: PropTypes.func,
        onStop: PropTypes.func,
        onContext: PropTypes.func,
        left: PropTypes.number.isRequired,
        top: PropTypes.number.isRequired,
        gridX: PropTypes.number,
        gridY: PropTypes.number
    };

    onStart(e) {
        if (this.props.enabled) {
            this.setState({
                relX: e.pageX - this.props.left,
                relY: e.pageY - this.props.top
            })
        }
    }

    onMove(e, current) {
        if (this.props.enabled) {
            const x = Math.trunc((e.pageX - this.state.relX) / this.gridX) * this.gridX;
            const y = Math.trunc((e.pageY - this.state.relY) / this.gridY) * this.gridY;

            if (x !== this.state.x || y !== this.state.y) {
                this.setState({
                    x,
                    y,
                    dragged: true
                });
                this.props.onMove && this.props.onMove({ left: this.state.x, top: this.state.y });
            }
        }
    }

    onMouseDown(e) {
        if (e.button !== 0) return;
        this.onStart(e);
        this.clickRef.current.addEventListener('mousemove', this.onMouseMove);
        this.clickRef.current.addEventListener('mouseup', this.onMouseUp);
        e.preventDefault();
    }

    onMouseUp(e) {
        this.clickRef.current.removeEventListener('mousemove', this.onMouseMove);
        this.clickRef.current.removeEventListener('mouseup', this.onMouseUp);
        this.props.onStop && this.props.onStop(e, this.props.index ? this.props.index : null, { left: this.state.x, top: this.state.y, dragged: this.state.dragged });
        this.setState({ dragged: false });
        if (this.props.onStop) e.preventDefault();
    }

    onMouseMove(e) {
        this.onMove(e, this.props.index ? this.props.index : null, { left: this.state.x, top: this.state.y });
        e.preventDefault();
    }

    onContext(e) {
        if (this.props.onRightClick) {
            e.preventDefault();
            this.props.onRightClick(e, this.props.index ? this.props.index : null);
        }

    }

    render() {
        let style = {}
        if (this.props.style) {
            style = { ...this.props.style }
        }
        if (!(style.position && style.position === 'fixed')) {
            style.position = 'absolute';
        }
        style.left = this.state.x + 'px';
        style.top = this.state.y + 'px'

        return <div
            onMouseDown={this.onMouseDown}
            onContextMenu={this.onContext}
            onMouseMove={this.onMouseMove}
            onMouseUp={this.onMouseUp}
            style={style}
            ref={this.clickRef}
        >
            {this.props.children}
        </div>;
    }
}

export default Draggable;

И функция, создающая перетаскиваемые компоненты:

    buildDesks = () => {
        const newScale = this.getScale();
        const layout = this.props.layout;
        let container = document.querySelector("#Layout_Map_Container");

        const desks = layout.desks;//.filter(desk => parseInt(desk.SiteId) === parseInt(map.id));
        let ret = desks.map((desk, index) => {
            let deskImg = null;
            try {
                let dImg = layout.deskTypes.find(d => parseInt(d.deskType) === parseInt(desk.deskType));
                deskImg = dImg.deskImage;
            }
            catch (ex) {
                console.log(ex);
            }
            const userName = desk.UserLogon !== (null || '') ? desk.UserLogon : "Unassigned";

            const top = Math.trunc(parseInt(parseInt(desk.y) * newScale));
            const left = Math.trunc(parseInt(parseInt(desk.x) * newScale));
           
            const imgStyle = {
                width: `${parseInt(parseInt(desk.width) * newScale)}px`,
                height: `${parseInt((parseInt(desk.height) * newScale))}px`,
                transform: `rotate(${parseInt(desk.rotation)}deg)`
            }
            const url = `data:image/jpeg;base64,${deskImg}`;
            try {
                return (
                    <Draggable key={desk.DeskID}
                        index={desk.DeskID}
                        enabled={this.state.edit}
                        left={left}
                        top={top}
                        onMove={this.updateProperties}
                        onStop={this.endMove}
                        onRightClick={this.rightClick}
                    >
                        <img style={imgStyle} alt={userName} src={url} />
                    </Draggable>
                );
            }
            catch (ex) {
                console.log(ex);
                return null;
            }
        });//desks.map
        return ret;
    }//buildDesks

Затем создание текстовых полей:

showStatus = () => {
        //screen width - object width - right coordinate
        let left = parseInt(window.innerWidth - 225);
        let top = 106;

        // return (<div></div>);

        return (
            <Draggable enabled={true}
                top={top}
                left={left}
            >
                <div style={{ width: '200px' }} className='editData'
                    style={{ position: 'fixed', top: top + 'px', left: left + 'px' }}>
                    <Row className='statusRow'>
                        <Col sm={12}>
                            <div id="Layout_UserImg" title="Click to upload new user image">
                                <div id="Layout_UserImgLabel">
                                    Click to
                                    upload new
                                    user image</div>
                            </div>
                        </Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Manager</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_Manager" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>User</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_User" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Emp. Id</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_EmpId" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Extension</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_Extension" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Department</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_Department" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>DB Id</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_DBRowId" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Desk ID</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_DeskID" /></Col>
                    </Row>
                    <Row className='statusRow'>
                        <Col sm={5} className='statusDivHeading'>Assets</Col>
                        <Col sm={7} className='statusDivData'><input type='text' id="Layout_Assets" /></Col>
                    </Row>
                    <Row>
                        <Col>
                            <button onClick={this.updateStats}>Save Changes</button>
                        </Col>
                        <Col>
                            <button onClick={this.clearUserStats}>Clear all fields</button>
                        </Col>
                    </Row >
                </div >
            </Draggable >
        )

    }

и, наконец, мой рендер:

   render() {
        if (this.props.layout.isLoading) {
            return (<Loading title="Site Layout" />);
        }
        else if (this.props.layout.isLoadingMap) {
            const map = this.props.layout.maps[this.props.layout.currentMap];
            const siteName = map.SiteName;
            return (
                <Row>
                    <Col sm={1}></Col>
                    <Col sm={10} id="Layout_Map_Container">
                        <Loading title={"map '" + siteName + "'"} />
                    </Col>
                </Row>
            );
        }
        else if (this.props.layout.mapLoaded) {
            return (
                <div>

                    <Row>
                        <Col sm={1}>
                            {this.showAdmin()}
                        </Col>
                        <Col sm={10}>
                            {this.state.details}
                        </Col>
                    </Row>
                    <Row>
                        <Col sm={1}>
                            <select onChange={(e) => this.changeMap(e.target)}>
                                {this.buildMapOptions()}
                            </select>
                        </Col>
                        <Col sm={10} id="Layout_Map_Container">
                            {this.buildMap()}
                            {this.buildDesks()}

                        </Col>
                    </Row >
                    {this.showStatus()}
                </div>
            );
        }
        else {
            return (
                <Row>
                    <Col sm={1}>
                        <select onChange={(e) => this.changeMap(e.target)}>
                            {this.buildMapOptions()}
                        </select>
                    </Col>
                    <Col sm={10} id="Layout_Map_Container">
                    </Col>
                </Row>
            );
        }
    }

Много этого кода все еще не доработан, поэтому, если вы видите какие-либо изменения, которые необходимо внести, также укажите их. А пока, почему текстовые поля в showStatus () не работают?

Спасибо.

1 Ответ

0 голосов
/ 10 июля 2020

Оказывается, проблема возникает, когда форма находится в компоненте ', который применяет onMouseDown к контейнеру для формы. После удаления события щелчка регистрируются правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...