2

我想实现一个放置系统,如果放置目标是嵌套的,您可以使用鼠标滚轮在它们之间循环(或在一定时间后发生自动循环)这将特别有用,因为许多嵌套目标占据屏幕上完全相同的区域。

我目前在想,我可以使用从容器传递下来的回调,当它们的悬停函数被调用/当 isOver 道具发生变化时,放置目标可以使用该回调来注册/取消注册自己,但它非常耦合,我必须通过从容器中将道具放入 DropTargets,在现实世界的应用程序中,容器和放置目标之间会有未知数量的级别,所以我可能不得不设置某种回调系统,总的来说它不是一个理想的解决方案。此外,我不确定如何在循环时确保正确的顺序,因为放置目标不知道它们的嵌套程度(请参阅下面的代码了解我是如何实现的)。有没有更清洁的方法来实现这样的系统?

@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