react 拖拽排序组件

react 拖拽排序组件git 仓库源码

基于 html5 的 dragable 属性,可以自己封装个拖拽组件,react 相关的拖拽组件都非常的难以使用。只要掌握拖拽的原理,那么封装个这样的组件也不是难事,我最开始的难点就是,只能知道拖拽后在哪一个 element 上,但是并不知道放在哪个位置上去。最后观察拖拽组件,发现这个放置的位置是跟现在拖拽的元素和最后停留的元素位置上有关系的。

安装

npm install --save mys-react

使用

import React from "react";
import { Drag } from "mys-react";

export default class Test extends React.Component {
  state = {
    list: [1, 2, 3, 4]
  };

  render() {
    return (
      <div>
        <Drag
          style={{ width: 100, margin: 100 }}
          list={list}
          onChange={list => {
            console.log(list); // 返回排序结果
            this.setState({ list });
          }}
        >
          {list.map(v => {
            return (
              <div style={{ borderBottom: "1px solid #ddd" }} key={v}>
                {v}
              </div>
            );
          })}
        </Drag>
      </div>
    );
  }
}

原理解析

  • 1、获取到组件的子元素,vue 中就是插槽内容
import React from "react";

export default class Drag extends React.Component {
  componentDidMount() {
    this.init();
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.list !== this.props.list) {
      this.init(nextProps);
    }
  }

  init(nextProps) {
    const { children, list } = nextProps || this.props;
    this.setState({ children, list }, () => {
      this.initItem(this.dragContainer);
    });
  }
}
  • 2、给子元素每项设置属性
initItem(dragContainer) {
  const items = Array.prototype.slice.call(dragContainer.children);
  const that = this;
  items.forEach((v, k) => {
    that.addAttributes(v);
    v.ondragstart = function(e) {
      that.dragIndex = k;
      e.dataTransfer.setData("Text", k);
    };
    v.ondragover = function() {
      that.currentIndex = k;
    };
    v.ondragend = function() {
      const { currentIndex, dragIndex } = that;
      let { children } = that.state;
      if (currentIndex === dragIndex) return;
      children = that.getNewList(children);
      that.setState({ children }, () => {
        that.updateList();
      });
    };
  });
}
addAttributes(v) {
  const { cursor } = this.props;
  v.draggable = true;
  v.style.cursor = cursor || "move";
  v.style.marginBottom = "10px";
}
  • 3、拖拽排在位置的确定,这也是核心部分,就是现在拖拽的元素 key 小于停留的元素,那么放置其后,如果现在拖拽的元素 key 大于于停留的元素,放置其前
getNewList(list) {
  const { currentIndex, dragIndex } = this;
  if (currentIndex === dragIndex) return;
  if (currentIndex < dragIndex) {
    //放在前面
    list.splice(currentIndex, 0, list[dragIndex]);
    list.splice(dragIndex + 1, 1);
  }
  if (currentIndex > dragIndex) {
    //放在后面
    list.splice(currentIndex + 1, 0, list[dragIndex]);
    list.splice(dragIndex, 1);
  }
  return list;
}

注意事项

这个拖拽组件可以与 antd 的组件嵌套使用,但是组件的子元素第一层必须是 html5 的标签内容。比如

  • 错误的示范
<Drag
  style={{ width: 100, margin: 100 }}
  list={list}
  onChange={list => {
    console.log(list); // 返回排序结果
    this.setState({ list });
  }}
>
  {list.map(v => {
    return (
      // 直接使用antd的组件
      <Button style={{ borderBottom: "1px solid #ddd" }} key={v}>
        {v}
      </Button>
    );
  })}
</Drag>
  • 正确的用法
<Drag
  style={{ width: 100, margin: 100 }}
  list={list}
  onChange={list => {
    console.log(list); // 返回排序结果
    this.setState({ list });
  }}
>
  {list.map(v => {
    return (
      // 先使用html5标签,再使用antd的组件
      <div>
        <Button style={{ borderBottom: "1px solid #ddd" }} key={v}>
          {v}
        </Button>
      </div>
    );
  })}
</Drag>
  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值