У меня есть проект с интересной дилеммой. Я создал компонент (из Рекомендуемый способ сделать 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 () не работают?
Спасибо.