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

  • Vue实现拖拽穿梭框功能四种方式已关闭评论
  • 116 次浏览
  • A+
所属分类:Web前端
摘要

点击打开视频讲解更加详细效果图:
vuedraggable 是标准的组件式封装,并且将可拖动元素放进了 transition-group 上面,过渡动画都比较好。


一、使用原生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实现拖拽穿梭框功能四种方式

三、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> 

若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!!!