美文网首页
js拖拽自动排列思路

js拖拽自动排列思路

作者: 三省吾身_9862 | 来源:发表于2021-10-26 16:58 被阅读0次
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>拖拽排序</title>
  <style>
    *{padding: 0;margin: 0;}
    li{list-style: none;}
    .drag-wrap{
      position: relative;
      width: 500px;
    }
    .drag-wrap .drag-item{
      transition: unset;
      z-index: 2;
    }
    .drag-wrap li{
      box-shadow: 0 2px 2px rgba(0, 0, 0, 0.15);
      position: absolute;
      width: 90px;
      margin: 5px;
      height: 60px;
      user-select: none;
      background-color: blueviolet;
      transition: left 0.3s ease-in-out,
                  top 0.3s ease-in-out;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  </style>
</head>
<body>
  <ul class="drag-wrap">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
    <li>9</li>
    <li>10</li>
    <li>11</li>
    <li>12</li>
  </ul>
<script>
var dragSort = {
  // 容器元素
  el: null,
  // 节点宽度
  nodeWidth: 100,
  // 节点高度
  nodeHeight: 70,
  // 每行节点个数
  nodeNumber: 5,
  // 容器下所有卡片的节点
  nodeList: [],
  // 记录拖拽中,被拖拽节点的序号;防止重复排序
  index: 0,

  init(el) {
    this.el = el;
    // 获取容器下所有卡片的节点
    this.nodeList = [...this.el.children];
    // 给所有节点初始化序号,绑定事件
    this.nodeList.forEach((node,index)=> {
      node.sort = index;
      node.addEventListener('mousedown', this.addDragEvent.bind(this));
    });
    // 进行第一次排序
    this.sortNodePosition(this.nodeList);
  },

  /**
   * 给每个节点进行一次排序
   * @param {Array} 元素节点数组
   */
  sortNodePosition(nodeList) {
    nodeList.forEach(node => {
      node.style.left = node.sort % this.nodeNumber * this.nodeWidth + 'px';
      node.style.top = Math.floor(node.sort / this.nodeNumber) * this.nodeHeight + 'px';
    })
  },

  /**
   * 绑定拖拽事件
   * @param {Object} e  事件对象
   */
  addDragEvent(e) {
    // 当前拖拽的节点
    let { target } = e;
    // 增加class,取消动效,防止拖拽掩饰;增加zIndex层级
    target.className = 'drag-item';
    let styleLeft = parseInt(target.style.left),
        styleTop = parseInt(target.style.top);
    let startLeft = e.clientX,
        startTop = e.clientY;

    // 拖动节点
    const mousemoveFn = (moveEvent) => {
      let endLeft = styleLeft + (moveEvent.clientX - startLeft),
          endTop = styleTop + (moveEvent.clientY - startTop);
      target.style.left = endLeft + 'px';
      target.style.top = endTop + 'px';
      this.changeNodeSort(target, endLeft, endTop);
    }
    document.addEventListener('mousemove', mousemoveFn);

    // 释放拖动的节点
    const mouseupFn = () => {
      // 因为移动的时候要保证移动位置,不能对当前节点排序,所有鼠标释放,进行下排序
      this.sortNodePosition([target]);
      setTimeout(() => {target.removeAttribute('class')});
      // 这步可以不做,为了和谷歌一样,把dom也进行排序
      this.sortDom();
      document.removeEventListener('mousemove', mousemoveFn);
      document.removeEventListener('mouseup', mouseupFn);
    }
    document.addEventListener('mouseup', mouseupFn);
  },

  /**
   * 计算出需要排序变化的节点,改变节点sort属性
   */
   changeNodeSort(dragNode, x, y) {
    // 元素移动:水平方向超过 nodeWidth 一半,算sort+1;垂直方向超过 nodeHeight 一半,算进入到下一排(sort + nodeNumber)
    var newSort = Math.round(y / this.nodeHeight) * this.nodeNumber + Math.round(x / this.nodeWidth);
    newSort = newSort > this.nodeList.length - 1 ? this.nodeList.length - 1 : newSort;
    newSort = newSort < 0 ? 0 : newSort;
    // 在移动过程中,当前节点sort没有改变,不需要重复计算排序。
    if (newSort !== this.index) {
      this.index = newSort;
      var oldSort = dragNode.sort;
      this.nodeList.forEach(node => {
        // 往前移动,老位置 - 新位置(包含)之间的所有节点,排序都加1
        if (newSort < oldSort) {
          if (node.sort >= newSort && node.sort < oldSort) node.sort++;
        } 
        // 往后移动,老位置 - 新位置(包含)之间的所有节点,排序都减1
        else {
          if (node.sort <= newSort && node.sort > oldSort) node.sort--;
        }
      })
      // 给当前节点排序重新赋值,不要漏了这个
      dragNode.sort = newSort
      // 把除了当前节点的,所有节点都重新排序下位置
      this.sortNodePosition(this.nodeList.filter(node => node!==dragNode));
    }
  },

  /**
   * 对DOM排序
   */
  sortDom() {
    let newSortWrap = document.createDocumentFragment();
    this.nodeList = [...this.el.children].sort((a,b) => a.sort - b.sort);
    this.nodeList.forEach(node => {
      newSortWrap.appendChild(node);
    });
    this.el.appendChild(newSortWrap);
  }
}

dragSort.init(document.querySelector('.drag-wrap')); 
  
</script>
</body>
</html>

相关文章

  • js拖拽自动排列思路

  • js拖拽自动排列

    上一次写了拖拽,其实主要还是想实现拖拽之后实现自动排列,跟手机屏幕那样移动图标可以自动排列,先看效果: 很常见的一...

  • 浅谈js拖拽

    前言 本文依据半年前本人的分享《浅谈js拖拽》撰写,算是一篇迟到的文章。 基本思路 虽然现在关于拖拽的组件库到处都...

  • js拖拽html元素工具类

    复制就能用的拖拽js方法 原生js实现拖拽元素方法 使用(注意拖拽目标元素需绝对定位 position: 'abs...

  • 拖拽

    一、JS拖拽JS里拖拽三事件, onmousedown onmousemove onmouseup 是实现交互性效...

  • 原生js实现拖拽(碰撞检测)

    js实现拖拽

  • js实现拖拽

    ①鼠标按下+鼠标移动 → 拖拽②鼠标松开 → 无拖拽③鼠标偏移 → 拖拽距离 js实现 ① onmousedown...

  • 对“继承的应用”心得

    思路: 1.编写拖拽盒子DragBox的js(用对象的方法编写),注意:this的替换 2.创建一个新的函数,继承...

  • h5拖拽相关事件

    拖拽 Sortable.js插件拖拽的时候主要由这几个事件完成,

  • jquery插件——拖拽自动排序

    前言 本插件主要应用于文字列表拖拽后自动排序,应用于ol或ul标签下。 步骤 css样式 html js 完整实例

网友评论

      本文标题:js拖拽自动排列思路

      本文链接:https://www.haomeiwen.com/subject/xplyaltx.html