图标的拖动排序

2018-12-14  本文已影响16人  楠楠_c811

最近遇到一个新的需求,要求弹窗展示一个图标列表,然后每个图标都可以拖动排序......
what?
拖动排序?然后满脑子就是碰撞、判断、上下左右......
为什么一个小图标要做的这么复杂?能看不就好了么?
......当然,如果你打不过产品经理,还说不过他,你还能做什么呢????
乖乖去找方法解决喽,还能咋地?
当然了,我一直认为技术不能逾越市场,也不能让技术引领产品潮流。因为毕竟术业有专攻,在产品设计这件事情上,听产品的不是错。
这块代码是一个的react的子组件,最后会被作为组件调用。

// 我是一个独立封装的子组件
import React from 'react'
// 定义当前要拖拽的图标
let curDragIndex = null;

// 封装子组件
export default function dragSort(props){
  // 定义所有需要拖拽的图标
  let container = props.children;
  // from 是要拖拽的列,to是行,封装变化事件函数
  function onChange(from, to){
    // 如果是同一个,说明没有执行拖拽,直接返回
    if(from === to ) return ;
    // 定义当前被拖拽的数据
    let curValue = props.data;
    // 定义执行后当前最新的数组
    let newValue = arrMove(curValue, from, to);
    // 判断传进来的参数是否有 onChange 方法,如果有就执行父级的onChange
    if(typeof props.onChange === 'function'){
      // 如果调用父级的onChange函数方法,就根据传参返回最新的数组
      return props.onChange(newValue, from ,to);
    }
  }
  return (
    <div>
      {/* 循环遍历表格的每一项*/}
      {container.map((item, index)=>{
        // 判断是不是react组件。用来增加代码的健壮性,防止渲染的时候出错
        if(React.isValidElement(item)){
          // 如果是,克隆并返回一个新的 ReactElement (内部子元素也会跟着克隆),
          // 新返回的元素会保留有旧元素的 props、ref、key,也会集成新的 props(只要在第二个参数中有定义)
          return React.cloneElement(item, {
            // 设置元素可拖动
            draggable:"true",
            // 开始拖拽
            onDragStart: function(){
              // 获取被拖拽的数据的起始位置下标
              curDragIndex = index
            },
            // 拖拽过程中
            onDragEnter: function() {
              // 执行onChange函数,获取最新位置,达到互换效果
              onChange(curDragIndex, index)
              // 当前拖拽的数据顶替之前这个位置的数据
              curDragIndex = index;
            },
            // 拖拽停止
            onDragEnd: function(){
              curDragIndex = null;
              // 判断如果这里有调用函数事件
              if(typeof props.onDragEnd === 'function'){
                // 就让他调用停止事件
                props.onDragEnd()
              }
            }
          })
        }
        // 将最终的item return 出去
        return item;
      })}
    </div>
    )
}
// 设置函数,接收参数
function arrMove(arr, fromIndex, toIndex){
  // 合并原有数组赋值给一个新数组
  arr = [].concat(arr);
  // 取到传进来的起始位置的值  item是需要插入的内容
  let item = arr.splice(fromIndex, 1)[0];
  // 将插入的内容加到目的点的后面,返回一个新的数组
  arr.splice(toIndex , 0, item);
  return arr;
}

封装好这个组件之后,剩下的就是传参调用了。我这个拖拽排序是写在一个弹框里的,实现效果是打开弹框,获取到数据,然后拖拽操作。

// 记得要在最上面引入封装的组件文件哦

class Currency extends Component{
//拖动排序事件
  handleTableChange = (pagination, filters, sorter) => {
    this.setState({newSort: sorter.order, newSortField: sorter.field}, () =>
      this._getTokenList(pagination.current - 1, pagination.pageSize, this.state.newSort, this.state.newSortField, this.state.searchInput, this.state.searchBlack, this.state.searchAble, this.state.searchAsset));
  };

  handleDragMove = (data, from, to) => {
    this.setState({
      curMoveItem: to,
      tokenList: data
    })
  };

  handleDragEnd = () => {
    this.setState({
      curMoveItem: null
    })
  };
  render(){
    return(
      <div>
        // 弹框
        <Modal
            title="我是antd的弹框组件"
            visible={this.state.sort}
            onOk={this.handleOk}
            onCancel={this.handleCancel}
        >
             <p>上下拖动可调整展示排序</p>
            // 我是上面封装的组件哦
             <DragSort onDragEnd={this.handleDragEnd} 
                        onChange={this.handleDragMove} 
                        data={this.state.tokenList}>
                {
                    this.state.tokenList.map((token,index)=>{
                       return (
                            <ul>
                              <li>
                                <div key={index}>
                                  <span>{token.id}</span>
                                  <img style={{width: 50, height: 50, margin:10 }} src={token.icon} />
                                  <span>{token.symbol}</span>
                                </div>
                              </li>
                            </ul>
                          )
                        })
                      }
              </DragSort>
          </Modal>
      </div>
    )
  }
}

上一篇下一篇

猜你喜欢

热点阅读