react 拖拽排序

react 拖拽排序。项目中用到了,记一笔。没有用react-dnd, 没有用react-beautiful-dnd, 因为需求简单,所以就自己撸了一个。

代码很简单

定义css, 两个动画

.drag-up {
  -webkit-animation: dragup ease 0.2s 1;
          animation: dragup ease 0.2s 1;
  -webkit-animation-fill-mode: forwards;
          animation-fill-mode: forwards;
  background-color: red;
}
.drag-down {
  -webkit-animation: dragdown ease 0.2s 1;
          animation: dragdown ease 0.2s 1;
  -webkit-animation-fill-mode: forwards;
          animation-fill-mode: forwards;
  background-color: green;
}
@-webkit-keyframes dragup {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: 60px;
  }
}
@keyframes dragup {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: 60px;
  }
}
@-webkit-keyframes dragdown {
  from {
    margin-bottom: 10px;
    margin-top: 60px;
  }
  to {
    margin-bottom: 60px;
    margin-top: 10px;
  }
}
@keyframes dragdown {
  from {
    margin-bottom: 10px;
    margin-top: 60px;
  }
  to {
    margin-bottom: 60px;
    margin-top: 10px;
  }
}

  一个是向上拖拽的动画,一个是向下拖拽的样式。

2.写组件

class List extends React.Component {
  constructor(props) {
    super(props);
    this.state = {...props};
  }

  dragStart(e) {
    this.dragged = e.currentTarget;
  }
  dragEnd(e) {
    this.dragged.style.display = ‘block‘;

    e.target.classList.remove("drag-up");
    this.over.classList.remove("drag-up");

    e.target.classList.remove("drag-down");
    this.over.classList.remove("drag-down");

    var data = this.state.data;
    var from = Number(this.dragged.dataset.id);
    var to = Number(this.over.dataset.id);
    data.splice(to, 0, data.splice(from, 1)[0]);

    //set newIndex to judge direction of drag and drop
    data = data.map((doc, index)=> {
      doc.newIndex = index + 1;
      return doc;
    })

    this.setState({data: data});
  }

  dragOver(e) {
    e.preventDefault();

    this.dragged.style.display = "none";

    if (e.target.tagName !== "LI") {
      return;
    }

    //判断当前拖拽target 和 经过的target 的 newIndex

    const dgIndex = JSON.parse(this.dragged.dataset.item).newIndex;
    const taIndex = JSON.parse(e.target.dataset.item).newIndex;
    const animateName = dgIndex > taIndex ? "drag-up" : "drag-down";

    if (this.over && e.target.dataset.item !== this.over.dataset.item) {
      this.over.classList.remove("drag-up", "drag-down");
    }

    if(!e.target.classList.contains(animateName)) {
      e.target.classList.add(animateName);
      this.over = e.target;
    }
  }
  render() {
    var listItems = this.state.data.map((item, i) => {
      return (
        <li
          data-id={i}
          key={i}
          style={{height: "60px", border: "solid 1px #cccccc", margin: "10px 30%", borderRadius: "5px", backgroundColor: "green", color: "#ffffff"}}
          draggable=‘true‘
          onDragEnd={this.dragEnd.bind(this)}
          onDragStart={this.dragStart.bind(this)}
          data-item={JSON.stringify(item)}
        >{item.color}</li>
      )
     });
    return (
      <ul onDragOver={this.dragOver.bind(this)} className ="contain">
        {listItems}
      </ul>
    )
  }
}
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [
        {
          newIndex: 1,
          color: "red"
        },

        {
          newIndex: 2,
          color: "green"
        },

        {
          newIndex: 3,
          color: "blue"
        },

        {
          newIndex: 4,
          color: "yellow"
        },

        {
          newIndex: 5,
          color: "orange"
        },

        {
          newIndex: 6,
          color: "black"
        }
      ]
    }
  }
  render() {
    return (
      <div>
        <List data={this.state.data} />
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById(‘app‘),
);

解释几个三个方法
1.dragStart  把 target 赋值给了this

2.dragOver 把经过的 li 赋值给了 this, 并且在经过的li上,添加对应的class, 实现动画效果。 这里比较了序号,判断当前是向哪个方向拖拽。  并且比较了 经过li是否是同一个,不是的话,移除动画效果。

3.dragEnd, 移除动画效果, 并且比较数据,setState到最新的数据。

总结, 有点dom操作的思想。

demo地址: https://codepen.io/jhonyoung/pen/PeGpNL

原创。

原文地址:https://www.cnblogs.com/jhonyoung/p/8954512.html

时间: 2024-11-02 21:23:28

react 拖拽排序的相关文章

使用knockout-sortable实现对自定义菜单的拖拽排序

在开始之前,照例,我们先看效果和功能实现. 关于自定义菜单的实现,这里就不多说了,需要了解的请访问:http://www.cnblogs.com/codelove/p/4838766.html 这里需要说明的是排序的实现. 我们先来看看关键的页面代码: <div class="row"> <div class="col-lg-12 full-width" id="leftMenus"> <div class=&quo

RecyclerView实现条目Item拖拽排序与滑动删除

RecyclerView实现条目Item拖拽排序与滑动删除 版权声明:转载请注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 效果演示 直播视频讲解:[http://pan.baidu.com/s/1miEOtwG1 推荐大家结合我直播的视频看效果更好. 本博客源码传送门. 需求和技术分析 RecyclerView Item拖拽排序::长按RecyclerView的Item或者触摸Item的某个按钮. RecyclerView Item滑动删除:

jQuery拖拽插件制作拖拽排序特效

基于jQuery拖拽插件制作拖拽排序特效是一款非常实用的鼠标拖拽布局插件.效果图如下: 在线预览   源码下载 实现的代码. html代码: <h1>水平拖拽</h1> <div class="demo"> <div class="item item1"><span>1</span></div> <div class="item item2"><

jquery -- 拖拽排序分析

今天应一个朋友的委托,研究一下拖拽排序,我记得我上次写拖拽排序,因为方法太死板,效果我一直不是很满意,一直想再从写一个,一直没机会(懒),这次因为公司部门变动所以有了一些时间(无聊)来写,本来准备使用Vue写,奈何功夫不到家在自定义指令的时候,问题卡住了,研究了一段时间之后,还是决定放弃,研究一下Vue再来写过,所以本次还是用了Jquery来写. 直接上代码 这是CSS部分 1 *{/*Css*/ 2 margin: 0px; 3 padding: 0px; 4 list-style: none

自定义控件——可拖拽排序的ListView

前言 最经研究了一下拖拽排序的ListView,跟酷狗里的播放列表排序一样,但因为要添加自己特有的功能,所以研究了好长时间.一开始接触的是GitHub的开源项目--DragSortListView,实现的效果和流畅度都很棒.想根据他的代码自己写一个,但代码太多了,实现的好复杂,看别人的代码你懂的了,就去尝试寻找其他办法.最后还是找到了更简单的实现方法,虽然跟开源项目比要差一点,但对我来说可以了,最重要的是完全可以自定义. 实现的效果如下: 主要问题 如何根据触摸的位置确定是哪个条目? ListV

最近写的一个控件——Well Swipe 拖拽排序实现

如图: >删除过渡动画 >拖拽排序

ztree使用系列四(ztree实现同级拖拽排序并将排序结果保存数据库)

ztree这个系列的最后一篇,也是ztree功能强大的体现之一--排序功能.ztree可以实现所有节点之间随意的拖拽排序功能,我这里根据需要实现了只允许同级之间随意拖拽排序,其实原理都一样,只是范围缩小了一些,多了一些判断而已.下面是每一层的代码,还是采取只贴出功能代码,因为这个拖拽排序功能我感觉很不错,所以单独拿出一篇博客来展示,也方便理解. Jsp页面实现功能的js代码如下: //拖拽前执行 var dragId; function beforeDrag(treeId, treeNodes)

zTree的拖拽排序

ztree本身是可以支持拖拽的,但是却没有找到明确的支持拖拽的排序,也就是说,在拖拽过程中,需要自定义维护拖拽后的顺序并保存至后台. 在这样一个比较常规的需求情况下,网上也有朋友给出了一些解决方案,比如自定义一个tree传入ztree, 不使用ztree的识别字段,而是使用自定义字段,然后当ztree的节点发生变化时,维护这些自定义字段,从而使得整个tree是有序的,并支持拖拽. 上边的这个解决方案,有一个问题,就是使用javascript构造的tree,传入ztree之后,会发生堆栈溢出,初步

PagedDragDropGrid拖拽排序

PagedDragDropGrid拖拽排序 长按界面上某个item,item会抖动,并且可以拖动item,重新排列位置. 下载地址:http://www.devstore.cn/code/info/881.html 运行截图: