Vue实现拖拽穿梭框功能四种方式实例详解

 

一、使用原生js实现拖拽

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Lazyload</title>
    <style>
      .drag {
        background-color: skyblue;
        position: absolute;
        line-height: 100px;
        text-align: center;
        width: 100px;
        height: 100px;
      }
    </style>
  </head>
  <body>
    <!-- left和top要写在行内样式里面 -->
    <div class="drag" style="left: 0; top: 0">按住拖动</div>
    <script src="./jquery-3.6.0.min.js"></script>
    <script>
      // 获取DOM元素
      let dragDiv = document.getElementsByClassName('drag')[0]
      // 鼠标按下事件 处理程序
      let putDown = function (event) {
        dragDiv.style.cursor = 'pointer'
        let offsetX = parseInt(dragDiv.style.left) // 获取当前的x轴距离
        let offsetY = parseInt(dragDiv.style.top) // 获取当前的y轴距离
        let innerX = event.clientX - offsetX // 获取鼠标在方块内的x轴距
        let innerY = event.clientY - offsetY // 获取鼠标在方块内的y轴距
        // 按住鼠标时为div添加一个border
        dragDiv.style.borderStyle = 'solid'
        dragDiv.style.borderColor = 'red'
        dragDiv.style.borderWidth = '3px'
        // 鼠标移动的时候不停的修改div的left和top值
        document.onmousemove = function (event) {
          dragDiv.style.left = event.clientX - innerX + 'px'
          dragDiv.style.top = event.clientY - innerY + 'px'
          // 边界判断
          if (parseInt(dragDiv.style.left) <= 0) {
            dragDiv.style.left = '0px'
          }
          if (parseInt(dragDiv.style.top) <= 0) {
            dragDiv.style.top = '0px'
          }
          if (
            parseInt(dragDiv.style.left) >=
            window.innerWidth - parseInt(dragDiv.style.width)
          ) {
            dragDiv.style.left =
              window.innerWidth - parseInt(dragDiv.style.width) + 'px'
          }
          if (
            parseInt(dragDiv.style.top) >=
            window.innerHeight - parseInt(dragDiv.style.height)
          ) {
            dragDiv.style.top =
              window.innerHeight - parseInt(dragDiv.style.height) + 'px'
          }
        }
        // 鼠标抬起时,清除绑定在文档上的mousemove和mouseup事件
        // 否则鼠标抬起后还可以继续拖拽方块
        document.onmouseup = function () {
          document.onmousemove = null
          document.onmouseup = null
          // 清除border
          dragDiv.style.borderStyle = ''
          dragDiv.style.borderColor = ''
          dragDiv.style.borderWidth = ''
        }
      }
      // 绑定鼠标按下事件
      dragDiv.addEventListener('mousedown', putDown, false)
    </script>
  </body>
</html>

 

二、VUe使用js实现拖拽穿梭框

<template>
<div>
  <h3 style="text-align: center">拖拽穿梭框</h3>
  <div id="home" @mousemove="mousemove($event)">
    <div class="tree-select-content">
      <span
        class="select-content"
        :id="'mouse' + index"
        v-for="(item, index) in leftData"
        :key="item.id"
        @mousedown="mousedown(index, 1)"
        @mouseup="mouseup(item, 1, index)"
      >
        <span class="select-text">{{ item.label }}</span>
        <span class="select-text-X" @click="handerClickX(item, index, 1)"
          >X</span
        >
      </span>
    </div>
    <div class="tree-select-content">
      <span
        class="select-content"
        :id="'deleteMouse' + index"
        v-for="(item, index) in rightData"
        :key="item.id"
        @mousedown="mousedown(index, 2)"
        @mouseup="mouseup(item, 2, index)"
      >
        <span class="select-text">{{ item.label }}</span>
        <span class="select-text-X" @click="handerClickX(item, index, 2)"
          >X</span
        >
      </span>
    </div>
  </div>
</div>
</template>

<script>
export default {
name: "home",
data() {
  return {
    leftData: [
      { label: "首页", id: 1 },
      { label: "咨询", id: 2 },
      { label: "生活", id: 3 },
      { label: "财富", id: 4 },
      { label: "我的", id: 5 },
    ],
    rightData: [{ label: "世界", id: 6 }],
    isMoveTrue: false,
    isMove: false,
    moveId: "",
  };
},
mounted() {},
components: {},
methods: {
  mousedown(index, val) {
    this.isMoveTrue = true;
    if (val == 1) {
      this.moveId = "mouse" + index;
    } else {
      this.moveId = "deleteMouse" + index;
    }
  },
  mousemove(event) {
    if (this.isMoveTrue) {
      this.isMove = true;
      document.getElementById(this.moveId).style.position = "absolute";
      document.getElementById(this.moveId).style.top = event.clientY + "px";
      document.getElementById(this.moveId).style.left = event.clientX + "px";
      document.getElementById(this.moveId).style.transform =
        "translate(-50%,-50%)";
    }
  },
  mouseup(item, val, index) {
    if (!this.isMove) {
      this.isMoveTrue = false;
      this.moveId = "";
    }
    if (this.isMoveTrue && val == 2) {
      this.$nextTick(() => {
        this.rightData.splice(index, 1);
        this.leftData.push(item);
      });
    } else if (this.isMoveTrue && val) {
      this.leftData.splice(index, 1);
      this.rightData.push(item);
    }
    document.getElementById(this.moveId).style.display = "none";
    this.isMoveTrue = false;
    this.isMove = false;
    this.moveId = "";
  },
  handerClickX(item, index, val) {
    if (val == 1) {
      this.leftData.splice(index, 1);
      this.rightData.push(item);
    } else {
      this.rightData.splice(index, 1);
      this.leftData.push(item);
    }
  },
},
};
</script>

<style scoped>
#home {
display: flex;
justify-content: space-around;
}
.tree-select-content {
width: 40%;
height: 300px;
background: #f9faff;
border: 1px solid #dee0ec;
border-radius: 4px;
display: flex;
flex-wrap: wrap;
align-content: baseline;
}
.select-content {
width: max-content;
height: 20px;
padding: 1.6%;
border: 1px solid #d6dbed;
margin: 2% 1% 0;
background: #ffffff;
box-shadow: 0 0 8px 0 rgba(72, 119, 236, 0.1);
border-radius: 4px;
}
.select-content:hover span {
color: #4877ec;
}
.select-content:hover {
cursor: pointer;
background: #f8faff;
border: 1px solid #3e75f4;
}
.select-text {
font-size: 15px;
color: #2e2f36;
text-align: center;
font-weight: 400;
}
.select-text-X {
font-size: 15px;
color: #4877ec;
letter-spacing: 0;
font-weight: 400;
margin-left: 12px;
cursor: pointer;
}
</style>

效果图:

 

三、Vue 拖拽组件 vuedraggable

vuedraggable 是标准的组件式封装,并且将可拖动元素放进了 transition-group 上面,过渡动画都比较好。

使用方式:

yarn add vuedraggable
import vuedraggable from 'vuedraggable';

在使用的时候,可以通过 v-model 来双向绑定本地 data,如果需要更新或者是触发父组件监听的事件,可以在 updated() 中去 emit。

案例:

<template>
<div>
  <div>{{ drag ? "拖拽中" : "拖拽停止" }}</div>
  <!--使用draggable组件-->
  <draggable
    v-model="myArray"
    chosenClass="chosen"
    forceFallback="true"
    group="people"
    animation="1000"
    @start="onStart"
    @end="onEnd"
  >
    <transition-group>
      <div class="item" v-for="element in myArray" :key="element.id">
        {{ element.name }}
      </div>
    </transition-group>
  </draggable>
  <div class="color-list">
    <div
      class="color-item"
      v-for="color in colors"
      v-dragging="{ item: color, list: colors, group: 'color' }"
      :key="color.text"
    >
      {{ color.text }}
    </div>
  </div>
</div>
</template>
<style scoped>
/*被拖拽对象的样式*/
.item {
padding: 6px;
background-color: #fdfdfd;
border: solid 1px #eee;
margin-bottom: 10px;
cursor: move;
}
/*选中样式*/
.chosen {
border: solid 1px #3089dc !important;
}
</style>
<script>
//导入draggable组件
import draggable from "vuedraggable";
export default {
//注册draggable组件
components: {
  draggable,
},
data() {
  return {
    drag: false,
    //定义要被拖拽对象的数组
    myArray: [
      { people: "cn", id: 10, name: "www.itxst.com" },
      { people: "cn", id: 20, name: "www.baidu.com" },
      { people: "cn", id: 30, name: "www.taobao.com" },
      { people: "us", id: 40, name: "www.yahoo.com" },
    ],
    colors: [
      {
        text: "Aquamarine",
      },
      {
        text: "Hotpink",
      },
      {
        text: "Gold",
      },
      {
        text: "Crimson",
      },
      {
        text: "Blueviolet",
      },
      {
        text: "Lightblue",
      },
      {
        text: "Cornflowerblue",
      },
      {
        text: "Skyblue",
      },
      {
        text: "Burlywood",
      },
    ],
  };
},
methods: {
  //开始拖拽事件
  onStart() {
    this.drag = true;
  },
  //拖拽结束事件
  onEnd() {
    this.drag = false;
  },
},
};
</script>

 

四、Awe-dnd指令封装

vue-dragging 的 npm 包的名字是 awe-dnd ,并不是 vue-dragging,这个库的特点是封装了 v-dragging 全局指令,然后通过全局指令去数据绑定等。

相比及 vuedraggable 来说, awe-dnd 是没有双向绑定(这里没有双向绑定并不是很严谨,准确的来说没有暴露双向绑定的方式),因此提供了事件,在拖拽结束的时候用来更新列表(不需要手动更新列表,其实内部是实现了双向绑定的)或者是去触发父组件监听的事件。

安装依赖:

npm install awe-dnd --save
yarn add awe-and

main.js

import VueDND from 'awe-dnd'
Vue.use(VueDND)

案例:

<template>
<div>
  <div class="color-list">
    <div
      class="color-item"
      v-for="color in colors"
      v-dragging="{ item: color, list: colors, group: 'color' }"
      :key="color.text"
    >
      {{ color.text }}
    </div>
  </div>
</div>
</template>
<style scoped>
/*被拖拽对象的样式*/
.item {
padding: 6px;
background-color: #fdfdfd;
border: solid 1px #eee;
margin-bottom: 10px;
cursor: move;
}
/*选中样式*/
.chosen {
border: solid 1px #3089dc !important;
}
</style>
<script>
export default {
data() {
  return {
    drag: false,
    colors: [
      {
        text: "Aquamarine",
      },
      {
        text: "Hotpink",
      },
      {
        text: "Gold",
      },
      {
        text: "Crimson",
      },
      {
        text: "Blueviolet",
      },
      {
        text: "Lightblue",
      },
      {
        text: "Cornflowerblue",
      },
      {
        text: "Skyblue",
      },
      {
        text: "Burlywood",
      },
    ],
  };
},
methods: {},
};
</script>

关于Vue实现拖拽穿梭框功能四种方式的文章就介绍至此,更多相关vue拖拽穿梭框内容请搜索编程宝库以前的文章,希望以后支持编程宝库

 前言本系列用于撰写作者在学习JavaScript及浏览JavaScript相关书籍时所遇到的一些问题及心得 DOM首先我们要了解JavaScript里面一个非常重要的模型: ...