未验证 提交 2bd267a1 编写于 作者: _ __Oasis__ 提交者: GitHub

Merge pull request #624 from irisSong/nutui-react

Nutui react drag组件开发完成
......@@ -152,6 +152,16 @@
{
"name": "操作反馈",
"packages": [
{
"version": "1.0.0",
"name": "Drag",
"type": "component",
"cName": "拖拽",
"desc": "实现可拖拽的任意元素",
"sort": 1,
"show": true,
"author": "songsong"
},
{
"version": "1.0.0",
"name": "Collapse",
......
import React from 'react'
import { Drag } from './drag'
import { Button } from '../button/button'
const DragDemo = () => {
const right = () => {
return document.documentElement.clientWidth - 300 - 9
}
const bottom = () => {
return document.documentElement.clientHeight - 559
}
const btnStyle = {
borderRadius: '25px',
padding: '0 18px',
fontSize: '14px',
color: '#fff',
display: 'inline-block',
lineHeight: '36px',
background: 'linear-gradient(135deg,#fa2c19 0,#fa6419 100%)',
}
return (
<div className="demo">
<h2>基础用法</h2>
<Drag style={{ top: '120px', left: '8px' }}>
<span style={btnStyle}>触摸移动</span>
</Drag>
<h2 style={{ top: '30px', position: 'relative' }}>限制拖拽方向</h2>
<Drag direction={'x'} style={{ top: '200px', left: '8px' }}>
<span style={btnStyle}>只能X轴拖拽</span>
</Drag>
<Drag direction={'y'} style={{ top: '200px', right: '50px' }}>
<span style={btnStyle}>只能Y轴拖拽</span>
</Drag>
<h2 style={{ top: '60px', position: 'relative' }}>自动吸边</h2>
<Drag direction={'x'} attract={true} style={{ top: '275px', left: '8px' }}>
<span style={btnStyle}>拖动我</span>
</Drag>
<h2 style={{ top: '90px', position: 'relative' }}>限制拖动边界</h2>
<div
className="drag-boundary"
style={{
position: 'absolute',
top: '360px',
left: '8px',
width: '300px',
height: '200px',
border: '1px solid red',
}}
></div>
<Drag
boundary={{ top: 361, left: 9, bottom: bottom(), right: right() }}
style={{ top: '400px', left: '50px' }}
>
<span style={btnStyle}>限制拖拽边界</span>
</Drag>
</div>
)
}
export default DragDemo
# Drag 组件
### 介绍
实现可拖拽的任意元素
### 安装
## 代码演示
### 基础用法
## 基本用法
```tsx
<Drag>
<div class="touch-dom">触摸移动</div>
</Drag>
```
## 限制拖拽方向
```tsx
<Drag direction={'x'}>
<div class="touch-dom">只能在X轴拖动</div>
</Drag>
<Drag direction={'y'}>
<div class="touch-dom">只能在Y轴拖动</div>
</Drag>
```
## 自动吸边
```tsx
<Drag direction={'x'} attract={true}>
<div class="touch-dom">拖动我</div>
</Drag>
```
## 限制拖拽边界
```tsx
// const right = () => {
// return document.documentElement.clientWidth - 300 - 9
// }
// const bottom = () => {
// return document.documentElement.clientHeight - 559
// }
<Drag boundary={{ top: 361, left: 9, bottom: bottom(), right: right() }}>
<div class="touch-dom">拖动我</div>
</Drag>
```
## API
### Props
| 参数 | 说明 | 类型 | 默认值 |
| attract | 是否开启自动吸边 | Boolean | false |
| direction | 拖拽元素的拖拽方向限制,**x**/**y**/**all**三选一 | String |'all' |
| boundary | 拖拽元素的拖拽边界 | Object | {top: 0,left: 0,right: 0,bottom: 0} |
.nut-drag {
position: fixed;
display: inline-block;
z-index: 9997 !important;
width: fit-content;
height: fit-content;
}
import React, { FunctionComponent, useState, useEffect, useRef } from 'react'
import './drag.scss'
export interface DragProps {
attract: boolean
direction: string
boundary: {
top: number
left: number
right: number
bottom: number
}
style: any
}
const defaultProps = {
attract: false,
direction: 'all',
boundary: {
top: 0,
left: 0,
right: 0,
bottom: 0,
},
style: {},
} as DragProps
export const Drag: FunctionComponent<Partial<DragProps> & React.HTMLAttributes<HTMLDivElement>> = (
props
) => {
const { attract, direction, boundary, style, children } = { ...defaultProps, ...props }
const elWidth = useRef(0)
const elHeight = useRef(0)
const screenWidth = useRef(0)
const screenHeight = useRef(0)
const startTop = useRef(0)
const startLeft = useRef(0)
const nx = useRef(0)
const ny = useRef(0)
const xPum = useRef(0)
const yPum = useRef(0)
const position = useRef({
x: 0,
y: 0,
})
const boundaryState = useRef({
top: 0,
left: 0,
right: 0,
bottom: 0,
})
const myDrag = useRef<HTMLDivElement>(null)
const getInfo = () => {
const el = myDrag.current
if (el) {
const domElem = document.documentElement
elWidth.current = el.offsetWidth
elHeight.current = el.offsetHeight
screenWidth.current = domElem.clientWidth
screenHeight.current = domElem.clientHeight
}
}
const goLeft = (target: HTMLElement) => {
if (boundary.left) {
if (+target.style.left.split('px')[0] > boundary.left) {
target.style.left = +target.style.left.split('px')[0] - 10 + 'px'
window.requestAnimationFrame(() => {
goLeft(target)
})
} else {
target.style.left = `${boundary.left}px`
}
} else {
if (+target.style.left.split('px')[0] > 10) {
target.style.left = +target.style.left.split('px')[0] - 10 + 'px'
window.requestAnimationFrame(() => {
goLeft(target)
})
} else {
target.style.left = '0px'
}
}
}
const goRight = (target: HTMLElement, rightLocation: number) => {
if (rightLocation - parseInt(target.style.left.split('px')[0]) > 10) {
target.style.left = parseInt(target.style.left.split('px')[0]) + 10 + 'px'
window.requestAnimationFrame(() => {
goRight(target, rightLocation)
})
} else {
target.style.left = rightLocation + 'px'
}
}
const touchMove = (e: TouchEvent) => {
e.preventDefault()
const target = e.currentTarget as HTMLElement
if (e.targetTouches.length === 1) {
const touch = e.targetTouches[0]
const x = touch.clientX - position.current.x
const y = touch.clientY - position.current.y
xPum.current = startLeft.current + x
yPum.current = startTop.current + y
const rightLocation = screenWidth.current - elWidth.current - boundary.right
if (Math.abs(xPum.current) > rightLocation) {
xPum.current = rightLocation
} else if (xPum.current <= boundary.left) {
xPum.current = boundary.left
}
if (yPum.current < boundary.top) {
yPum.current = boundary.top
} else if (yPum.current > screenHeight.current - elHeight.current - boundary.bottom) {
yPum.current = screenHeight.current - elHeight.current - boundary.bottom
}
if (props.direction != 'y') {
target.style.left = `${xPum.current}px`
}
if (props.direction != 'x') {
target.style.top = `${yPum.current}px`
}
}
}
const touchEnd = (e: TouchEvent) => {
const target = e.currentTarget as HTMLElement
const touch = e.changedTouches[0]
let currX = touch.clientX
const rightLocation = screenWidth.current - elWidth.current - boundary.right
if (currX > rightLocation) {
currX = rightLocation
} else if (currX < boundary.left) {
currX = boundary.left
} else {
currX = currX < screenWidth.current / 2 ? boundary.left : rightLocation
}
if (props.direction != 'y' && props.attract) {
if (currX < screenWidth.current / 2) {
window.requestAnimationFrame(() => {
goLeft(target)
})
} else {
window.requestAnimationFrame(() => {
goRight(target, rightLocation)
})
}
}
if (props.direction !== 'x') {
target.style.top = `${yPum.current}px`
}
}
const touchStart = (e: React.TouchEvent<HTMLDivElement>) => {
const target = e.currentTarget as HTMLElement
const touches = e.touches[0]
startTop.current = target.offsetTop
startLeft.current = target.offsetLeft
position.current = { x: touches.clientX, y: touches.clientY }
target.removeEventListener('touchmove', touchMove, false)
target.removeEventListener('touchend', touchEnd, false)
target.addEventListener('touchmove', touchMove, false)
target.addEventListener('touchend', touchEnd, false)
}
useEffect(() => {
getInfo()
}, [])
return (
<div
className="nut-drag"
style={style}
ref={myDrag}
onTouchStart={(event) => touchStart(event)}
>
{children}
</div>
)
}
Drag.defaultProps = defaultProps
Drag.displayName = 'NutDrag'
import { Drag } from './drag'
export default Drag
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册