2

ドロップ ターゲットがネストされている場合、マウス スクロール ホイールを使用してドロップ ターゲット間を循環できる (または、一定時間後に自動サイクルが発生する) ドロップ システムを実装したいと考えています。画面上のまったく同じ領域。

現在、ホバー関数が呼び出されたとき/ 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>
    );
  }
}
4

0 に答える 0