Draggable menu (React)
Меню, созданное React, я отделил от основного меню. Для разнообразия сделал там три кнопки, переключающими отображение разного содержимого в одном окне.
Первое, что мне было интересно сделать это перемещение окна. Для этого я создал div в виде полосы в верхней части окна. При нажатии на неё активируется Drag Mode, при отпускании клавиши мыши над всем окном Matcap режим отключается.
<div className="MatCap" onMouseUp={disableDragMode} style={ {left:newX, top:newY} }> <div className='dragLine' onMouseDown={enableDragMode} > …
Функция enableDragMode переключает state
const [dragModeEnabled, setDragMode ] = useState(false);
и устанавливает точку, в который произошел клик
const [clickPoint, setClickPoint] = useState({x: undefined, y: undefined}); function enableDragMode () { if( event.buttons !== 1 ) return; let blockStyle = getComputedStyle(event.target.parentNode.parentNode) let blockOffset = {x: blockStyle.left.replace('px',''), y: blockStyle.top.replace('px','')}; let point = {x: event.offsetX, y: event.offsetY, blockOffset: blockOffset} setClickPoint( point ); setDragMode(true); event.stopPropagation() event.preventDefault() }
При переключении режима в useEffect добавляется или удаляется listener на событие движения мыши:
useEffect(() => { if( dragModeEnabled ) { document.addEventListener( "mousemove", onMouseMove, false) } return function cleanup() { document.removeEventListener( "mousemove", onMouseMove, false) } }, [dragModeEnabled] );
При перемещении мыши с зажатой левой клавишей происходит изменение координат div.
const [newX, setNewX] = useState('0px'); const [newY, setNewY] = useState('30px');
Так же добавлены проверки, чтобы div не мог двигаться дальше краев окна.
function onMouseMove () { if( event.pageX < 20 || event.pageX > document.documentElement.clientWidth-20 || event.pageY < 20 || event.pageY > document.documentElement.clientHeight-20 ){ return; } if( event.buttons !== 1 ) { setDragMode(false); return; } moveAt(event.pageX, event.pageY); } function moveAt(pageX, pageY) { setNewX( pageX - clickPoint.x - clickPoint.blockOffset.x + 'px'); setNewY( pageY - clickPoint.y - clickPoint.blockOffset.y + 'px'); }
Полный код компонента Matcap.js
import React, { useState, useEffect, useContext } from 'react'; import './Matcap.css'; import { MatcapContext } from '../../../ReactPanel'; let headers = { 'MatCaps': "Select Matcap", 'Textures': "Select Texture", 'Models': "Select Model" } function Matcap( props ) { const [dragModeEnabled, setDragMode ] = useState(false); const [newX, setNewX] = useState('0px'); const [newY, setNewY] = useState('30px'); const [ cardsDiv, setCardsDiv ] = useState(null); const [clickPoint, setClickPoint] = useState({x: undefined, y: undefined}); const selectedCard = useContext( MatcapContext ) useEffect(() => { if( dragModeEnabled ) { document.addEventListener( "mousemove", onMouseMove, false) } return function cleanup() { document.removeEventListener( "mousemove", onMouseMove, false) } }, [dragModeEnabled] ); useEffect( () => { setCardsDiv( props.cardsDiv ); }, [] ) function clickUseButton () { appState.changeAppState( 'matcapChanged', selectedCard.src ); } function changeCheckbox( e ) { console.log('changeCheckbox', e.target.checked ); } function setPanelInvisible() { props.setPanel("") } function enableDragMode () { if( event.buttons !== 1 ) return; let blockStyle = getComputedStyle(event.target.parentNode.parentNode) let blockOffset = {x: blockStyle.left.replace('px',''), y: blockStyle.top.replace('px','')}; let point = {x: event.offsetX, y: event.offsetY, blockOffset: blockOffset} setClickPoint( point ); setDragMode(true); event.stopPropagation() event.preventDefault() } function onMouseMove () { if( event.pageX < 20 || event.pageX > document.documentElement.clientWidth-20 || event.pageY < 20 || event.pageY > document.documentElement.clientHeight-20 ){ return; } if( event.buttons !== 1 ) { setDragMode(false); return; } moveAt(event.pageX, event.pageY); } function moveAt(pageX, pageY) { setNewX( pageX - clickPoint.x - clickPoint.blockOffset.x + 'px'); setNewY( pageY - clickPoint.y - clickPoint.blockOffset.y + 'px'); } function disableDragMode() { setDragMode(false); } return ( <div className="MatCap" onMouseUp={disableDragMode} style={ {left:newX, top:newY} }> <div className='dragLine' onMouseDown={enableDragMode} > {headers[props.panel]} <button className="addPanel_CloseButton" onClick={ setPanelInvisible }> X </button> </div> <div className="HeadMatCab"> <div className="matCapPreview"> {props.panel === "MatCaps" && selectedCard.img ? <img className="cardImgSelected" src = {selectedCard.img}></img> : "" } </div> <div className="HeadMatCabButtons"> <label>Preview <input type='checkbox' name="checkbox" onChange={ changeCheckbox } /> </label> <button className='addPanel_Buttons' onClick={ clickUseButton }> Use </button> </div> </div> { props.panel === "MatCaps" && cardsDiv } </div> ); } export default Matcap;
Are you building a Trello clone with draggable cards or a table with draggable rows and columns or you are building some other cool application where you allow the user to drag and drop objects? Do, you use react? Well, you don’t really need to implement everything from scratch then. There are packages like react-dnd and react-beautiful-dnd which can help you. While react-dnd is more powerful, react-beautiful-dnd is simple and easy to use.
I’m creating 3d editor. This is mostly educational project, that’s why many things I try to make by myself, I just want to understand how it works. But if this app will be cool, I will be glad ☺️
I think that is among the so much significant information for me. Heidie Emilio Pederson
Article writing is also a excitement, if you be acquainted with afterward you can write otherwise it is complex to write. Brita Pierson Zak
Somebody essentially assist to make seriously posts I would state. Gale Darin Hyde
I think this is among the most vital info for me. And i am glad reading your article. Letitia Leeland Tager
Some truly prime content on this internet site , saved to bookmarks . Kassia Antonino Godding
I was studying some of your articles on this website and I conceive this site is real instructive! Continue putting up. Geneva Poul Celestyn