react 拖拽排序组件

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

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

react 拖拽排序组件_第1张图片

安装

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 (
      
{ console.log(list); // 返回排序结果 this.setState({ list }); }} > {list.map(v => { return (
{v}
); })}
); } }

原理解析

  • 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 的标签内容。比如

  • 错误的示范
 {
    console.log(list); // 返回排序结果
    this.setState({ list });
  }}
>
  {list.map(v => {
    return (
      // 直接使用antd的组件
      
    );
  })}

  • 正确的用法
 {
    console.log(list); // 返回排序结果
    this.setState({ list });
  }}
>
  {list.map(v => {
    return (
      // 先使用html5标签,再使用antd的组件
      
); })}

你可能感兴趣的:(技术)