js implements drag and drop sorting

Cut the nonsense, go directly to the code:

Example code 1:

<!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>js拖拽排排序1</title>

    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 90vw;
        height: 80vh;
      }
      .list {
        width: 500px;
        height: 335px;
      }
      .list-item {
        width: 100%;
        height: 50px;
        background-color: rgb(11, 137, 11);
        margin: 5px 0;
        border-radius: 5px;
        cursor: move;
        user-select: none;
      }
      .list-item.moving {
        background: transparent;
        color: transparent;
        border: 1px dashed #333;
        transition: all 0.3s linear;
      }
    </style>
  </head>
  <body>
    <div class="list">
      <div draggable="true" class="list-item">1</div>
      <div draggable="true" class="list-item">2</div>
      <div draggable="true" class="list-item">3</div>
      <div draggable="true" class="list-item">4</div>
      <div draggable="true" class="list-item">5</div>
      <div draggable="true" class="list-item">6</div>
    </div>

    <script>
      const list = document.querySelector('.list')
      // 目前正在拖动的元素
      let sourceNode
      // 拖动元素
      list.ondragstart = (e) => {
        setTimeout(() => {
          e.target.classList.add('moving')
        }, 0)
        sourceNode = e.target
        e.dataTransfer.effectAllowed = 'move'
      }

      // 拖动元素放置到目标上
      list.ondragover = (e) => {
        e.preventDefault()
      }

      // 拖动元素进入放置目标
      list.ondragenter = (e) => {
        e.preventDefault()
        if (e.target === list || e.target === sourceNode) return
        console.log(e.target)
        // 拿到父元素的所有子元素,并转换为数组
        const children = Array.from(list.children)
        // 找到正在拖动元素的下标
        const sourceIndex = children.indexOf(sourceNode)
        // console.log('拖动元素的下标', sourceIndex)
        // 找到目标元素的下标
        const targetIndex = children.indexOf(e.target)
        console.log('目标元素的下标', targetIndex)

        // 比较拖动元素和目标元素的下标来判断是向上拖动还是向下拖动
        if (sourceIndex < targetIndex) {
          console.log('向下拖动')
          // 拖动元素下标比目标元素小,插入到目标元素的后面
          list.insertBefore(sourceNode, e.target.nextElementSibling)
        } else {
          console.log('向上拖动')
          // 拖动元素下标比目标元素大,插入到目标元素的前面
          list.insertBefore(sourceNode, e.target)
        }
      }
      // 拖动完成
      list.ondragend = (e) => {
        e.target.classList.remove('moving')
      }
    </script>

    <script src="./flip.js"></script>
  </body>
</html>

Example code 2:

<!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>Document</title>
    <style>
      * {
        list-style: none;
        margin: 0;
        padding: 0;
      }

      #container {
        width: 500px;
        margin: 100px auto;
      }

      .ele {
        width: 100%;
        height: 40px;
        border: 1px solid #999;
        background: cadetblue;
        margin-top: 2px;
        border-radius: 10px;
        padding-left: 10px;
        color: white;
        cursor: move;
      }
    </style>
  </head>
  <body>
    <ul id="container">
      <li class="ele" draggable="true">1</li>
      <li class="ele" draggable="true">2</li>
      <li class="ele" draggable="true">3</li>
      <li class="ele" draggable="true">4</li>
    </ul>
    <script>
      var node = document.querySelector('#container')
      var draging = null
      //使用事件委托,将li的事件委托给ul
      node.ondragstart = function (event) {
        //console.log("start");
        //firefox设置了setData后元素才能拖动!!!!
        //event.target出发事件的元素
        event.dataTransfer.setData('te', event.target.innerText) //不能使用text,firefox会打开新tab
        //event.dataTransfer.setData("self", event.target);
        draging = event.target
        console.log('draging', draging)
      }
      node.ondragover = function (event) {
        //console.log("onDrop over");
        //取消默认行为
        event.preventDefault()
        var target = event.target
        console.log('target', target)
        //因为dragover会发生在ul上,所以要判断是不是li
        if (target.nodeName === 'LI') {
          if (target !== draging) {
            //getBoundingClientRect()用于获取某个元素相对于视窗的位置集合
            var targetRect = target.getBoundingClientRect()
            console.log('targetRect', targetRect)
            var dragingRect = draging.getBoundingClientRect()
            console.log('dragingRect', dragingRect)

            if (target) {
              if (target.animated) {
                return
              }
            }
            if (_index(draging) < _index(target)) {
              //nextSibling 属性可返回某个元素之后紧跟的节点(处于同一树层级中)。
              target.parentNode.insertBefore(draging, target.nextSibling)
            } else {
              target.parentNode.insertBefore(draging, target)
            }
            _animate(dragingRect, draging)
            _animate(targetRect, target)
          }
        }
      }
      //获取元素在父元素中的index
      function _index(el) {
        var index = 0

        if (!el || !el.parentNode) {
          return -1
        }
        //previousElementSibling属性返回指定元素的前一个兄弟元素(相同节点树层中的前一个元素节点)。
        while (el && (el = el.previousElementSibling)) {
          //console.log(el);
          index++
        }

        return index
      }

      function _animate(prevRect, target) {
        var ms = 300

        if (ms) {
          var currentRect = target.getBoundingClientRect()
          //nodeType 属性返回以数字值返回指定节点的节点类型。1=元素节点  2=属性节点
          if (prevRect.nodeType === 1) {
            prevRect = prevRect.getBoundingClientRect()
          }
          _css(target, 'transition', 'none')
          _css(target, 'transform', 'translate3d(' + (prevRect.left - currentRect.left) + 'px,' + (prevRect.top - currentRect.top) + 'px,0)')

          target.offsetWidth // 触发重绘
          //放在timeout里面也可以
          // setTimeout(function() {
          //     _css(target, 'transition', 'all ' + ms + 'ms');
          //     _css(target, 'transform', 'translate3d(0,0,0)');
          // }, 0);
          _css(target, 'transition', 'all ' + ms + 'ms')
          _css(target, 'transform', 'translate3d(0,0,0)')

          clearTimeout(target.animated)
          target.animated = setTimeout(function () {
            _css(target, 'transition', '')
            _css(target, 'transform', '')
            target.animated = false
          }, ms)
        }
      }
      //给元素添加style
      function _css(el, prop, val) {
        var style = el && el.style

        if (style) {
          if (val === void 0) {
            //使用DefaultView属性可以指定打开窗体时所用的视图
            if (document.defaultView && document.defaultView.getComputedStyle) {
              val = document.defaultView.getComputedStyle(el, '')
            } else if (el.currentStyle) {
              val = el.currentStyle
            }

            return prop === void 0 ? val : val[prop]
          } else {
            if (!(prop in style)) {
              prop = '-webkit-' + prop
            }

            style[prop] = val + (typeof val === 'string' ? '' : 'px')
          }
        }
      }
    </script>
  </body>
</html>

Guess you like

Origin blog.csdn.net/weixin_52020362/article/details/127874692