ドロップ ターゲットがネストされている場合、マウス スクロール ホイールを使用してドロップ ターゲット間を循環できる (または、一定時間後に自動サイクルが発生する) ドロップ システムを実装したいと考えています。画面上のまったく同じ領域。
現在、ホバー関数が呼び出されたとき/ isOver propが変更されたときに、ドロップターゲットが自分自身を登録/登録解除するために使用できるコンテナから渡されたコールバックを使用できると考えていますが、それは非常に結合されており、渡す必要がありますコンテナーから DropTargets に props を挿入すると、実際のアプリケーションでは、コンテナーとドロップ ターゲットの間に不明な数のレベルが存在するため、何らかのコールバック システムを設定する必要があり、全体的には理想的なソリューションではありません。また、ドロップターゲットがどれだけ深くネストされているかわからないため、サイクリング時に正しい順序を確保する方法がわかりません(これを実装する方法については、以下のコードを参照してください)。そのようなシステムを実装するためのよりクリーンな方法はありますか?
@DragDropContext(HTML5Backend)
export default class Container extends Component {
constructor (props) {
super(props);
this.state = {
bins: []
};
this.status = {};
this._cycle = this.cycle.bind(this);
this._register = this.register.bind(this);
this._deregister = this.deregister.bind(this);
}
componentWillUnmount () {
if (this.timer) {
window.clearInterval(this.timer);
}
}
register (name) {
if (this.state.bins.findIndex(e => e === name) === -1) {
this.setState({
bins: this.state.bins.concat(name)
});
if (!this.timer) {
this.cycledBins = [];
this.timer = window.setInterval(this._cycle, 3000);
this._cycle();
}
}
}
deregister (name) {
if (this.state.bins.findIndex(e => e === name) !== -1) {
const bins = this.state.bins.filter((e) => e === name);
this.setState({
bins
});
if (!bins.length) {
window.clearInterval(this.timer);
this.timer = undefined;
}
}
}
cycle () {
this.status = {};
const bins = this.state.bins;
let activeBin = -1;
for (let i = 0; i < bins.length; i += 1) {
if (this.cycledBins.findIndex(bin => bin === bins[i]) === -1) {
activeBin = bins[i];
break;
}
}
if (activeBin === -1) {
activeBin = bins[0];
this.cycledBins = [];
}
this.cycledBins.push(activeBin);
this.activeBin = activeBin;
this.status[activeBin] = {
isActive: true,
isOnlyActive: bins.length === 1
}
this.forceUpdate();
}
render () {
return (
<div>
bins = {JSON.stringify(this.state.bins)}<br />
cycledBins = {JSON.stringify(this.cycledBins)}
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Dustbin name="Outer" register={this._register} deregister={this._deregister} status={this.status["Outer"]} >
<Dustbin name="Middle" register={this._register} deregister={this._deregister} status={this.status["Middle"]} >
<Dustbin name="Inner" register={this._register} deregister={this._deregister} status={this.status["Inner"]} />
</Dustbin>
</Dustbin>
</div>
<div style={{ overflow: 'hidden', clear: 'both' }}>
<Box name='Glass' />
<Box name='Banana' />
<Box name='Paper' />
</div>
</div>
);
}
}
const boxTarget = {
hover(props) {
props.register(props.name);
}
};
@DNDDropTarget('Box', boxTarget, (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()//,
//canDrop: monitor.canDrop()
}))
export default class Dustbin extends Component {
static propTypes = {
connectDropTarget: PropTypes.func.isRequired,
isOver: PropTypes.bool.isRequired//,
//canDrop: PropTypes.bool.isRequired
};
componentWIllMount () {
if (!this.props.isOver) {
this.props.deregister(this.props.name);
}
}
componentWillReceiveProps (nextProps) {
if (nextProps.isOver !== this.props.isOver && !nextProps.isOver) {
this.props.deregister(this.props.name);
}
}
render() {
const { canDrop, isOver, connectDropTarget, status } = this.props;
const isOnlyActive = status && status.isOnlyActive;
let isActive = status && status.isActive;
if (!isOver && isActive) {
isActive = false;
}
return connectDropTarget(
<div>
<DropTarget position={BEFORE} shown={isActive} />
{ isActive && !isOnlyActive ? '(' + this.props.name + ')' : undefined }
{ this.props.children ? this.props.children : (
<div style={style}>
{ isActive ?
'Release to drop' :
'Drag a box here'
}
</div>
) }
<DropTarget position={AFTER} shown={isActive} />
</div>
);
}
}