我有一个可拖动的组件,它的行为类似于assistive touch
我想在使动画生效之前,我只需要在用户放开拖动时将x位置设置为窗口最左侧或最右侧,我尝试了以下操作:
import Draggable, { ControlPosition } from 'react-draggable'; // The default
import * as React from 'react';
import './style.less'
export default class FloatingScreenSpace extends React.Component<{}, {position:ControlPosition}> {
state ={
position: {x:90,y:0}
}
draggable: React.RefObject<Draggable> = React.createRef();
onDragEnd = (e:MouseEvent)=>{
if(this.draggable.current){
this.setState({
position:{
x: 0,
y: e.clientY
}
})
}
}
public render() {
return <Draggable position={this.state.position} ref={this.draggable} onStop={this.onDragEnd}>
<div className="floatingActionButton" style={{ width: '100px', height: '100px' }}></div>
</Draggable>
}
}
我认为在setState函数中将x位置设置为0会将其设置在屏幕的最左侧,但是这没有发生。实际上,它似乎根本没有影响。
理想情况下,当用户放开时,我想使按钮动画到屏幕的最近边缘(上,下,左,右)。
答案 0 :(得分:6)
在onStop
处理程序中实现辅助触摸行为听起来很不错。
请检查我的实施并遵循评论:
const Draggable = ReactDraggable
class Example extends React.Component {
constructor(props) {
super(props)
this.state = { position: { x:0, y:0 }}
}
onStop(event, data) {
// Draggable element bounding
const bounding = data.node.getBoundingClientRect()
// Viewport (wrapper)
const documentElement = document.documentElement
const wrapperHeight = (window.innerHeight || documentElement.clientHeight)
const wrapperWidth = (window.innerWidth || documentElement.clientWidth)
// Draggable element center coordinates (x,y)
// Here we assume that the Draggable Button (from the question)
// is a rectangle. But we can easily change it with whatever
// figure we want and fine-tune the calculation.
// Credits: https://stackoverflow.com/a/18932029/4312466
const center = {
x: data.x + (data.node.clientWidth / 2),
y: data.y + (data.node.clientHeight / 2)
}
// The margin from the draggable's center,
// to the viewport sides (top, left, bottom, right)
const margin = {
top: center.y - 0,
left: center.x - 0,
bottom: wrapperHeight - center.y,
right: wrapperWidth - center.x
}
// When we get the nearest viewport side (below), then we can
// use these metrics to calculate the new draggable sticky `position`
const position = {
top: { y: 0, x: data.x },
left: { y: data.y, x: 0 },
bottom: { y: (wrapperHeight - data.node.clientHeight), x: data.x },
right: { y: data.y, x: (wrapperWidth - data.node.clientWidth)}
}
// Knowing the draggable's margins to the viewport sides,
// now we can sort them out and get the smaller one.
// The smallest margin defines the nearest viewport side to draggable.
const sorted = Object.keys(margin).sort((a,b) => margin[a]-margin[b])
const nearestSide = sorted[0]
this.setState({ position: position[nearestSide] })
}
render() {
return <Draggable
position={this.state.position}
onStop={(event, data) => this.onStop(event, data)}
>
<div className='handle'>Drag</div>
</Draggable>
}
}
ReactDOM.render(
<Example />,
document.getElementById('container')
)
body {
overflow-x: hidden;
overflow-y: hidden;
padding: 0;
margin: 0;
}
.handle {
width: 40px;
height: 40px;
line-height: 40px;
background-color: #2662c1;
color: #fff;
cursor: move;
text-align: center;
}
.handle:not(.react-draggable-dragging) {
-webkit-transition: -webkit-transform 0.5s ease-out; /* Safari */
transition: transform 0.5s ease-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/react-draggable@3.0.5/dist/react-draggable.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>