localeCode: en-US order: 26 category: Plus title: DragMove icon: doc-dragmove dir: column brief: Set elements to change their position by dragging
It is used to set the element that can be dragged to change its position. It supports limiting the drag range and customizing the elements that trigger dragging.
DragMove supported from v2.71.0.
import { DragMove } from '@douyinfe/semi-ui';
Elements wrapped by DragMove
will be able to change their position by dragging.
Notice
DragMove needs to apply DOM event listeners to children. If the child element is a custom component, you need to ensure that it can pass properties to the underlying DOM element. The following types of children are supported:
Real DOM nodes, such as span, div, p...
import React, { useRef, useEffect } from 'react';
import { DragMove } from '@douyinfe/semi-ui';
function Demo() {
return (
<DragMove>
<div
style={{ backgroundColor: 'var(--semi-color-primary)',width: 80, height: 80,
display: 'flex', alignItems: 'center',justifyContent: 'center',
borderRadius: 10, fontWeight: 500,
position: 'absolute', color: 'rgba(var(--semi-white), 1)'
}}
>Drag me</div>
</DragMove>
);
}
Passing in constrainer
, this function returns the elements that limit the draggable range.
Note: The elements returned by the constrainer need to be positioned relative
import React, { useRef, useEffect } from 'react';
import { DragMove } from '@douyinfe/semi-ui';
function Demo() {
const containerRef = React.useRef();
return (
<div
style={{
backgroundColor: 'rgba(var(--semi-grey-2), 1)',
width: 300, height: 300, padding: 5, position: 'relative',
color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
}}
ref={containerRef}
>
<span>Constrainer</span>
<DragMove
constrainer={() => containerRef.current}
>
<div
style={{ backgroundColor: 'var(--semi-color-primary)',
width: 80, height: 80, borderRadius: 10,
display: 'flex', alignItems: 'center', justifyContent: 'center',
position: 'absolute', top: 80, left: 80,
}}
>Drag me</div>
</DragMove>
</div>
)
}
Passing in handler
, this function returns the element that triggered the drag. If not set, you can click anywhere to drag; if set, only the part of the element returned by the handler can be dragged.
import React, { useRef, useEffect } from'react';
import { IconTransparentStroked } from '@douyinfe/semi-icons';
import { DragMove } from '@douyinfe/semi-ui';
function Demo(){
const handlerRef = React.useRef();
const containerRef = React.useRef();
return (
<div
style={{ backgroundColor: 'rgba(var(--semi-grey-2), 1)',
width: 300, height: 300, padding: 5, position: 'relative',
color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
}}
ref={containerRef}
>
<span>Constrainer</span>
<DragMove
handler={() => handlerRef.current}
constrainer={() => containerRef.current}
>
<div
style={{
backgroundColor: 'var(--semi-color-primary)',
width: 80, height: 80, borderRadius: 10,
position: 'absolute', top: 50, left: 50,
display: 'flex', alignItems: 'center', justifyContent: 'center',
}}
>
<div
style={{ width: 'fit-content', height: 'fit-content' }}
ref={handlerRef}
><IconTransparentStroked size={'large'}/></div>
</div>
</DragMove>
</div>
)
}
You can customize the position processing after dragging through customMove
. After this parameter is set, the DragMove component will only return the calculated position through the parameters without setting it. The user can set the new position as needed.
import React, { useRef, useEffect } from'react';
import { DragMove } from '@douyinfe/semi-ui';
function CustomMove() {
const containerRef = React.useRef();
const elementRef = React.useRef();
const startPoint = React.useRef();
const customMove = useCallback((element, top, left) => {
if (left + 100 > containerRef.current.offsetWidth) {
element.style.right = `${containerRef.current.offsetWidth - left - element.offsetWidth}px`
element.style.left = 'auto';
} else {
element.style.left = left + 'px';
}
element.style.top = top + 'px';
}, [])
const onMouseDown = useCallback((e) => {
startPoint.current = {
x: e.clientX,
y: e.clientY,
}
}, []);
const onMouseUp = useCallback((e) => {
if (startPoint.current) {
const { x, y } = startPoint.current;
if (Math.abs(e.clientX - x) < 5 && Math.abs(e.clientY - y) < 5) {
if (elementRef.current.style.width === '50px') {
elementRef.current.style.width = '100px';
} else {
elementRef.current.style.width = '50px';
}
}
}
startPoint.current = null;
}, []);
return (
<>
<span>Click on the blue color block to change the width. The blue color block will not exceed the range limit before and after the change.</span>
<br /><br />
<div
style={{
backgroundColor: 'rgba(var(--semi-grey-2), 1)', width: 300, height: 300,
position: 'relative', padding: 10,
color: 'rgba(var(--semi-white), 1)', fontWeight: 500,
}}
ref={containerRef}
>
<span>Constrainer</span>
<DragMove
constrainer={() => containerRef.current}
customMove={customMove}
>
<div
style={{ backgroundColor: 'var(--semi-color-primary)',width: 50, height: 50,
display: 'flex', alignItems: 'center',justifyContent: 'center',
position: 'absolute', top: 50, left: 50, borderRadius: 10, padding: 5
}}
onMouseDown={onMouseDown}
onMouseUp={onMouseUp}
ref={elementRef}
>Drag me</div>
</DragMove>
</div>
</>
)
}
Property | Description | Type | Default value |
---|---|---|---|
allowInputDrag | Whether to allow dragging when clicking on native input/textarea | boolean | false |
allowMove | Determine whether dragging is allowed when clicking/touching. | (event: TouchEvent |MouseEvent, element: ReactNode) => boolean | - |
constrainer | Returns the element that limits the draggable range. | () => ReactNode | 'parent' | - |
customMove | Customize position processing after dragging | (element: ReactNode, top: number, left: number) => void | - |
handler | Returns the element that triggers dragging. | () => ReactNode | - |
onMouseDown | Callback when mouse is pressed | (e: MouseEvent) => void | - |
onMouseMove | Callback when mouse moves | (e: MouseEvent) => void | - |
onMouseUp | Callback when mouse is raised | (e: MouseEvent) => void | - |
onTouchCancel | Callback when touch cancels | (e: TouchEvent) => void | - |
onTouchEnd | callback when touch ends | (e: TouchEvent) => void | - |
onTouchMove | Callback when touch moves | (e: TouchEvent) => void | - |
onTouchStart | Callback when touch starts | (e: TouchEvent) => void | - |