超简单的原生Hmtl实现元素拖拽交换顺序

目录

前言

解析

代码

属性方法解释


前言

相信大家在进行项目开发时都会遇到元素拖拽交换顺序的需求,要实现这个需求有很多种方式,可以通过外部组件,也可以通过原生的draggable方法,此片文章将介绍一下draggable的使用,无需任何外部组件。

解析

拖拽交换顺序有两种,一种是将元素拖拽到其他元素的前面或后面,另一种是将元素拖拽到其他元素的位置,并直接交换它们的位置。

在此我们演示将张三拖拽到王五的位置:

拖拽前

拖拽后

可以看到,第一种是直接将张三插入到了王五的后面,第二种则是将张三与王五交换了顺序。第一种还加入了拖拽的标识线,在拖拽过程中可以确定拖拽后是插入到目标元素前面还是后面。

代码

<template>
  <div style="display: flex; height: 100%; text-align: center">
    <div style="height: 100%">
      <span>拖拽到目标元素之前或者之后</span>
      <div
        v-for="(item, index) in Array"
        :key="index"
        class="drag_div"
        draggable="true"
        @dragover.prevent
        @dragover="handleOver(index)"
        @dragstart="handleDragStart(index)"
        @drop="handleDrop(index)"
        @dragend="clearLine"
      >
        <span>{{ item }}</span>
      </div>
    </div>
    <div style="margin-left: 20px">
      <span>拖拽后直接与目标元素交换位置</span>
      <div
        v-for="(item, index) in Array2"
        :key="index"
        class="drag_div"
        draggable="true"
        @dragover.prevent
        @dragstart="handleDragStart(index)"
        @drop="handleDropChange(index)"
      >
        <span>{{ item }}</span>
      </div>
    </div>
    <div class="edit-container">
      <div class="leftBox">
        <textarea
          wrap="off"
          cols="2"
          id="leftNum"
          disabled
          onscroll="document.getElementById('rightNum').scrollTop = this.scrollTop;"
        ></textarea>
      </div>
      <textarea
        id="rightNum"
        v-model="code"
        onscroll="document.getElementById('leftNum').scrollTop = this.scrollTop;"
        spellcheck="false"
        class="area-content"
        readonly
        style="width: 650px"
      ></textarea>
      <div class="copyBtn" @click="copyText">{{ isCopy ? '已复制' : '复制' }}</div>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { onMounted, ref } from 'vue';
  import { tem } from '@/view/config';
  import { copyTextToClipboard } from '@/utils/common.ts';

  const Array = ref(['张三', '李四', '王五', '赵六']);
  const Array2 = ref(['张三', '李四', '王五', '赵六']);

  const code = ref(tem);

  // 拖拽开始时触发,获取拖拽元素的索引
  const startIndex: any = ref(0);
  function handleDragStart(index) {
    if (index !== startIndex.value) {
      startIndex.value = index;
    }
  }

  // 拖拽到目标元素上松开鼠标时,插入到目标元素之前或之后
  function handleDrop(index) {
    if (startIndex.value !== null) {
      Array.value.splice(index, 0, Array.value.splice(startIndex.value, 1)[0]);
      startIndex.value = null;
    }
  }

  // 拖拽到目标元素上松开鼠标时,交换顺序
  function handleDropChange(index) {
    if (startIndex.value !== null) {
      const temp = Array2.value[index];
      Array2.value[index] = Array2.value[startIndex.value];
      Array2.value[startIndex.value] = temp;
      startIndex.value = null;
    }
  }

  // 经过目标元素时生成拖拽标识线
  function handleOver(index) {
    const body: any = document.getElementsByClassName('drag_div')[index];
    body.style.position = 'relative';
    clearLine();
    const line = document.createElement('div');
    line.style.height = '2px';
    line.className = 'line-border';
    line.style.background = '#1677ff';
    line.style.width = body.offsetWidth + 'px';
    line.style.position = 'absolute';
    if (startIndex.value < index) {
      body.appendChild(line);
      line.style.bottom = '-2px';
    } else if (startIndex.value > index) {
      body.appendChild(line);
      line.style.top = '-2px ';
    }
  }

  function clearLine() {
    const elements = document.getElementsByClassName('line-border');
    for (let i = elements.length - 1; i >= 0; i--) {
      elements[i].parentNode.removeChild(elements[i]);
    }
  }

  const isCopy = ref(false);
  function copyText() {
    // 调用函数,将需要复制的文本传递给它,并处理返回的Promise
    const tip = copyTextToClipboard(code.value);
    if (tip) {
      isCopy.value = true;
      setTimeout(() => {
        isCopy.value = false;
      }, 2000);
    }
  }

  const num = ref('');
  onMounted(() => {
    let str: any = code.value;
    str = str.replace(/\r/gi, '');
    str = str.split('\n');
    let n = str.length;
    let lineBbj: any = document.getElementById('leftNum');
    for (let i = 1; i <= n; i++) {
      if (document.all) {
        num.value += i + '\r\n'; //判断浏览器是否是IE
      } else {
        num.value += i + '\n';
      }
    }
    lineBbj.value = num.value;
  });
</script>

<style scoped lang="less">
  .drag_div[data-draggable='true'] {
    -webkit-user-drag: element;
  }

  .drag_div[data-draggable='true']::webkit-drag {
    color: red !important; /* 改变文字颜色 */
    background-color: red !important; /* 改变背景颜色 */
    opacity: 1; /* 调整透明度 */
    transform: scale(1); /* 调整大小 */
    /* 其他你希望应用的样式 */
  }

  .drag_div {
    height: 180px;
    width: 400px;
    margin-top: 10px;
    border-radius: 10px;
    cursor: move;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
  }
  .edit-container {
    border: 1px solid #f5f7fa;
    height: 725px;
    display: flex;
    padding: 10px 10px 10px 0;
    background-color: #f5f7fa;
    border-radius: 5px;
    margin-left: 50px;
    margin-top: 35px;
    position: relative;
    box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.12);
    &:hover {
      .copyBtn {
        opacity: 0.8;
      }
    }
  }
  .leftBox {
    height: 100%;
    text-align: left;
  }
  .area-content {
    padding: 10px 8px;
    width: 100%;
    height: 100%;
    font-size: 13px;
    line-height: 24px;
    color: rgba(0, 0, 0, 0.85);
    font-family: Consolas;
    border: none;
    background: #ffffff;
    box-sizing: border-box;
    outline: none;
    resize: none;
  }
  #leftNum {
    overflow: hidden;
    padding: 10px 4px;
    height: 100%;
    width: 100%;
    line-height: 24px;
    font-size: 13px;
    text-align: right;
    color: rgba(0, 0, 0, 0.25);
    font-weight: bold;
    resize: none;
    outline: none;
    // overflow-y: hidden;
    // overflow-x: hidden;
    border: 0;
    background: #f5f7fa;
    box-sizing: border-box;
  }
  .copyBtn {
    border: 1px solid #d9d9d9;
    white-space: nowrap;
    text-align: center;
    box-sizing: border-box;
    width: 60px;
    display: flex;
    font-size: 14px;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    background: #9999aa;
    height: 32px;
    lineheight: 32px;
    padding: 0 15px;
    fontsize: 14px;
    color: white;
    border-radius: 4px;
    position: absolute;
    right: 30px;
    top: 15px;
    opacity: 0;
  }
</style>

属性方法解释

  • draggable="true" :设置元素可拖拽。
  • @dragover.prevent:阻止默认的拖拽事件。
  • @dragstart="handleDragStart(index)":拖拽开始时调用handleDragStart函数,并传入当前索引。
  • @drop="handleDrop(index)" :拖放操作成功完成的事件,它在拖动元素被放置在目标元素上时触发。只有当拖动元素被放置在目标元素上时,才会被触发。
  • @dragover="handleOver(index)":拖拽经过时触发,会显示一条拖拽插入的位置的标识线。

  • @dragend="handleDragLeave":拖放操作结束的事件,它在拖动元素放下(释放鼠标按键)时触发。无论拖动元素是否被放置在目标元素上,都会被触发。

以上则是原生html实现的两种元素拖拽的效果,可以根据实际情况灵活选用。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

马可家的菠萝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值