Vue使用vue-draggable 插件在不同列表之间拖拽功能


Posted in Javascript onMarch 12, 2020

今天分享一个vue项目中在不同列表拖拽设置选项的功能,这个功能也是在做项目中遇到的,先说下这个功能的要点(参考下图),有2个列表,左侧列表展示已选,右侧列表展示未选,通过拖拽进行设置,已选的选项不能超过4个,超过的话自动将拖拽之前的最后一项清除到右侧,且如果从已选往未选里拖的时候,右侧显示垃圾桶的提示(如图)。

拖拽功能图片:

Vue使用vue-draggable 插件在不同列表之间拖拽功能

垃圾桶显示图:

Vue使用vue-draggable 插件在不同列表之间拖拽功能

首先讲讲vue-draggable的使用

安装vue-draggable:

npm install vuedraggable

在使用插件的组件内引入vue-draggable并注册组件:

import draggable from "vuedraggable"

components: {
 draggable
}

然后在我们需要拖拽的列表中使用:

<draggable class="selected-list" tag="ul" 
v-model="selectedTheme" 
v-bind="dragOptions"
 :move="onMove"
 @end="onEnd" 
 >
 <li class="selected-theme"
 v-for="item in selectedTheme"
 :key="item.type"
 >{{item.name}}</li>
</draggable>

下面是拖拽功能组件的完整代码:

<template>
 <div class="theme-setting">
 <el-dialog
 title="设置选项"
 :visible.sync="dialogVisible"
 width="648px"
 :close-on-click-modal="false"
 >
 <div class="theme-left">
  <dl class="theme-title">
  <dt class="title">当前选项</dt>
  <dd class="des">从右侧拖拽添加</dd>
  </dl>
  <draggable class="selected-list" tag="ul" 
  v-model="selectedTheme" 
  v-bind="dragOptions"
  :move="onMove"
  @end="onEnd" 
  >
  <li class="selected-theme"
  v-for="item in selectedTheme"
  :key="item.type"
  >{{item.name}}</li>
  </draggable>
 </div>
 <div class="theme-right">
  <h3 class="theme-right-title">全部选项</h3>
  <draggable class="theme-right-list" tag="ul"
  v-model="unSelectTheme"
  v-bind="dragOptions"
  :move="onMove"
  @end="onEnd">
  <li class="theme-right-item"
  v-for="item in unSelectTheme"
  :key="item.type"
  >{{item.name}}</li>
  </draggable>
 </div>
 <div class="drag-drop-del" v-show="isShowDel">
  <img src="../assets/imgs/drapDrop/drag_drop_del.png" alt="">
 </div>
 <span slot="footer" class="dialog-footer">
  <el-button @click="restoreDefault">恢复默认设置</el-button>
  <el-button type="primary" @click="saveThemeSet">保存</el-button>
 </span>
 </el-dialog>
 </div>
</template>

<script>
import {Message} from 'element-ui'
import draggable from "vuedraggable" 
 export default {
 name: 'DragDrop',
 components: {
 draggable
 },
 data() {
 return {
  dialogVisible: false,
  selectedTheme: [{
  type: 1,
  name: '选项1'
  }, {
  type: 2,
  name: '选项2'
  }, {
  type: 3,
  name: '选项3'
  }, {
  type: 4,
  name: '选项4'
  }], // 已选主题列表
  unSelectTheme: [{
  type: 5,
  name: '选项5'
  }, {
  type: 6,
  name: '选项6'
  }], // 未选主题列表
  backSelectedTheme: [], // 选主题列表备份
  backUnSelectTheme: [], // 未选主题列表备份用于恢复默认设置
  relatedListLast: {}, // 已选主题列表最后一项
  isShowDel: false
 }
 },
 methods: {
 showDrag() {
  this.dialogVisible = true
 },
 onMove({ relatedContext, draggedContext, to }) {
  const relatedElement = relatedContext.element
  const draggedElement = draggedContext.element
  let dragInEl = to['className']
  if (dragInEl == 'selected-list') {
  this.isShowDel = false
  if (this.selectedTheme.length === 4) { 
   // 判断往已选列表拖时,如果已经满足4项,则记录已选列表的最后一项
   // 拖拽结束时将此项清除到未选列表中
   this.relatedListLast = this.selectedTheme[this.selectedTheme.length-1]
  }
  } else {
  this.isShowDel = true // 判断如果是往未选列表里拖的话显示垃圾桶
  }
  return (
  (!relatedElement || !relatedElement.fixed) && !draggedElement.fixed
  )
 },
 onEnd(dragObj) {
  let dragInEl = dragObj.to['className']
  if (dragInEl == 'selected-list') {
  if (this.selectedTheme.length > 4) {
   // 判断已选列表大于4项,将记录的最后一项过滤出来,并push到未选列表数组
   this.selectedTheme = this.selectedTheme.filter(item => {
   return item.type != this.relatedListLast.type
   })
   this.unSelectTheme.push(this.relatedListLast)
  }
  }
  if (dragInEl === 'theme-right-list') {
  // 判断是往未选列表拖时,拖拽结束时将垃圾桶隐藏
  this.isShowDel = false
  }
 },
 // 保存设置
 saveThemeSet() {
  const params = {
  taskTopicList: this.selectedTheme
  }
  if (this.selectedTheme.length !== 4) {
  Message({
   type: 'error',
   message: '需设置4个选项 !'
  })
  return false
  }
  $ajax.save(params).then(data => {
  this.dialogVisible = false
  Message({
   type: 'success',
   message: '保存成功!'
  })
  this.$parent.refresh()
  }).catch(err => {
  console.log(err)
  })
 },
 // 恢复默认设置
 restoreDefault() {
  this.selectedTheme = this.backSelectedTheme
  this.unSelectTheme = this.backUnSelectTheme
 }
 },
 computed: {
 dragOptions() {
  return {
  animation: 0,
  group: "description",
  disabled: false,
  ghostClass: "ghost"
  }
 }
 }
 };
</script>
<style lang="less" scoped>
body, ul, dl, dt, dd, li, h1, h3{
 margin: 0;
 padding: 0;
}
ul, ol, li {
 list-style: none;
}
.theme-setting {
 /deep/.el-dialog {
 height: 476px;
 border-radius: 6px;
 .el-dialog__header {
  height: 55px;
  line-height: 56px;
  padding: 0;
  border-bottom: 1px solid rgba(13,20,30, 0.1);
  .el-dialog__title {
  height:21px;
  font-size:16px;
  font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;
  font-weight:bold;
  color:rgba(13,20,30,1);
  line-height:21px;
  }
  .el-dialog__headerbtn {
  margin-top: -4px;
  }
 }
 .el-dialog__body {
  position: relative;
  display: flex;
  height: 331px;
  padding: 0;
  border-bottom: 1px solid rgba(13,20,30, 0.1);
  .theme-left {
  width: 218px;
  margin-left: 24px;
  border-right: 1px solid rgba(13,20,30, 0.1);
  .theme-title {
   display: flex;
   margin-top: 24px;
   .title {
   height:19px;
   margin-right: 4px;
   font-size:14px;
   font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;
   font-weight:bold;
   color:rgba(13,20,30,1);
   line-height:19px;
   }
   .des {
   height:16px;
   font-size:12px;
   font-family:MicrosoftYaHei;
   color:rgba(13,20,30,0.6);
   line-height:19px;
   }
  }
  .selected-list {
   height: 240px;
   margin-top: 24px;
   overflow: hidden;
   .selected-theme {
   width:160px;
   height:48px;
   line-height:48px;
   text-align: center;
   margin-bottom: 16px;
   cursor: pointer;
   background:linear-gradient(180deg,rgba(43,46,83,1) 0%,rgba(108,116,150,1) 100%);
   border-radius:6px;
   font-size:14px;
   font-family:MicrosoftYaHei;
   color:rgba(255,255,255,1);
   }
  }
  }
  .theme-right {
  padding: 0 24px;
  .theme-right-title {
   padding-top: 24px;
   height:19px;
   font-size:14px;
   font-family:MicrosoftYaHei-Bold,MicrosoftYaHei;
   font-weight:bold;
   color:rgba(13,20,30,0.4);
   line-height:19px;
  }
  .theme-right-list {
   width: 357px;
   height: 240px;
   overflow: scroll;
   margin-top: 24px;
   .theme-right-item {
   width: 160px;
   height:48px;
   line-height:48px;
   float: left;
   margin-right: 16px;
   margin-bottom: 16px;
   background:rgba(247,248,252,1);
   border-radius:6px;
   font-size:14px;
   font-family:MicrosoftYaHei;
   color:rgba(13,20,30,0.4);
   text-align: center;
   cursor: pointer;
   }
  }
  .theme-right-list::before, .theme-right-list::after {
   content: "";
   display: table;
  }
  .theme-right-list::after {
   clear: both;
  }
  }
  .drag-drop-del {
  position: absolute;
  right: 1px;
  top: 0;
  width: 404px;
  height: 331px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-image: url('../../src/assets/imgs/drapDrop/drag_drop.png');
  img {
   width: 96px;
   height: 96px;
  }
  }
 }
 .el-dialog__footer {
  height: 88px;
  padding: 24px 24px 0;
  .dialog-footer {
  .el-button+.el-button {
   margin-left: 16px;
  }
  }
 }
 }
}
</style>

总结

到此这篇关于Vue使用vue-draggable 插件在不同列表之间拖拽功能的文章就介绍到这了,更多相关vue vue-draggable 插件 拖拽内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
js模拟弹出效果代码修正版
Aug 07 Javascript
Prototype 学习 工具函数学习($A方法)
Jul 12 Javascript
jquery中动态效果小结
Dec 16 Javascript
jquery使用ajax实现微信自动回复插件
Apr 28 Javascript
jQuery循环动画与获取组件尺寸的方法
Feb 02 Javascript
解决JS请求服务器gbk文件乱码的问题
Oct 16 Javascript
详解JavaScript中的自定义事件编写
May 10 Javascript
移动端手指放大缩小插件与js源码
May 22 Javascript
Vue.js项目中管理每个页面的头部标签的两种方法
Jun 25 Javascript
在vue中实现点击选择框阻止弹出层消失的方法
Sep 15 Javascript
vue中多个倒计时实现代码实例
Mar 27 Javascript
elementUi vue el-radio 监听选中变化的实例代码
Jun 28 Javascript
js实现动态时钟
Mar 12 #Javascript
package.json各个属性说明详解
Mar 11 #Javascript
package.json中homepage属性的作用详解
Mar 11 #Javascript
vue项目中使用vue-layer弹框插件的方法
Mar 11 #Javascript
Vue组件模板及组件互相引用代码实例
Mar 11 #Javascript
Vue组件间的通信pubsub-js实现步骤解析
Mar 11 #Javascript
Vue事件处理原理及过程详解
Mar 11 #Javascript
You might like
[原创]PHP简单开启curl的方法(测试可行)
2016/01/11 PHP
sina的lightbox效果。
2007/01/09 Javascript
验证用户是否修改过页面的数据的实现方法
2008/09/26 Javascript
Jquery插件写法笔记整理
2012/09/06 Javascript
jquery入门—编写一个导航条(可伸缩)
2013/01/07 Javascript
JavaScript中使用stopPropagation函数停止事件传播例子
2014/08/27 Javascript
javascript容错处理代码(屏蔽js错误)
2017/01/20 Javascript
JS+jQuery实现注册信息的验证功能
2017/09/26 jQuery
解决vue build打包之后首页白屏的问题
2018/03/06 Javascript
vue 简单自动补全的输入框的示例
2018/03/12 Javascript
nuxt中使用路由守卫的方法步骤
2019/01/27 Javascript
javascript自定义右键菜单插件
2019/12/16 Javascript
ant-design-vue 实现表格内部字段验证功能
2019/12/16 Javascript
react 生命周期实例分析
2020/05/18 Javascript
[02:41]DOTA2英雄基础教程 亚巴顿
2014/01/02 DOTA
Python 条件判断的缩写方法
2008/09/06 Python
在Python中使用cookielib和urllib2配合PyQuery抓取网页信息
2015/04/25 Python
python统计文本字符串里单词出现频率的方法
2015/05/26 Python
对python for 文件指定行读写操作详解
2018/12/29 Python
在python中用print()输出多个格式化参数的方法
2019/07/16 Python
python支付宝支付示例详解
2019/08/22 Python
Django实现WebSSH操作物理机或虚拟机的方法
2019/11/06 Python
Django集成MongoDB实现过程解析
2020/12/01 Python
记一次高分屏下canvas模糊问题
2020/02/17 HTML / CSS
电子狗项圈:eDog Australia
2019/12/04 全球购物
怎样声明子类
2013/07/02 面试题
广州地球村科技数据库题目
2016/04/25 面试题
法雷奥SQA(electric)面试问题
2016/01/23 面试题
亲子活动总结
2014/04/26 职场文书
党的群众路线教育实践活动个人对照检查材料(医生)
2014/11/05 职场文书
2014年教师个人工作总结
2014/11/10 职场文书
2014年企业工会工作总结
2014/11/12 职场文书
见义勇为事迹材料
2014/12/24 职场文书
巾帼标兵事迹材料
2014/12/26 职场文书
详解Redis主从复制实践
2021/05/19 Redis
Python各协议下socket黏包问题原理
2022/04/12 Python