基于vue-draggable 实现三级拖动排序效果

vue-draggable

之前项目中需要用到拖动排序,就去网上找资料,本来最开始是想用jquery-ui里的拖动的,后面发现不符合我的预期也不知道能不能跟vue.js兼容,后面我试过了,单个的可以但是层级太多就不一样了。

废话少说直接上代码

先看数据结构,和页面的呈现,等会再来上代码。

这就是三层结构渲染出来的图。那个海锚一样的东西是可以点击的,点击后会出现当前类型所带的产品。等会会说的

我们现在来看下我实现后的拖动效果,如下

所有父类型里面的产品拖动如下

控制台的打印

好了,放了那么多图,数据结构也发了。接下来我们来上代码和思路。

先上html的代码,这里我的页面是jsp,但是不影响html兼容,项目中途接手,很古老的jsp我也没办法

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<link rel="stylesheet" href="${ctx}/res/ifw/plugins/datatables/dataTables.bootstrap.css" rel="external nofollow" />
<style>
 [v-cloak] {
 display: none;
 }
 .flip-list-move {
 transition: transform 0.5s;
 }
 .handle {
 float: right;
 padding-top: 2px;
 padding-bottom: 8px;
 }
 .no-move {
 transition: transform 0s;
 }
 .ghost {
 opacity: 0.5;
 background: #c8ebfb;
 }
 .list-group {
 min-height: 20px;
 }
 .list-group-item {
 cursor: move;
 }
 .list-group-item i {
 cursor: pointer;
 }
</style>
<div id="vueSort" class="box box-darkness">
 <div class="box-header with-border">
 <h3 class="box-title">排序</h3>
 <div class="box-tools pull-right">
  <button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i>
  </button>
 </div>
 </div>
 <div class="box-body" style="position: relative">
 <div class="col-md-3">
  <ul id="main-nav1" class="nav nav-tabs nav-stacked">
  <draggable class="list-group" tag="ul" v-model="listProductType":move="getdata" @update="datadragEnd">
   <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="(element,index) in listProductType" :key="element.id">
    <a :href="'#'+forId(element.uuid)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="nav-header collapsed" data-toggle="collapse"><i
     v-show="element.productList.length>0"
     aria-hidden="true"
     :class="{'fa fa-anchor':isActive,'glyphicon glyphicon-pushpin':!isActive}"
     @click="submenu"></i></a>
    {{element.name}}
    <i class="fa fa-align-justify handle" v-show="element.productTypes.length>0"
    @click="showLeve2(index)"></i>
    <template v-if="element.productList.length>0">
    <ur :id="forId(element.uuid)" class="nav nav-list collapse secondmenu">
     <draggable class="list-group" tag="ul":move="getdata" v-model="element.productList"
      @update="datadragEnds">
     <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="e in element.productList" :key="e.id">
    <a> {{e.name}}</a>
   </li>
   </transition-group>
  </draggable>
  </ur>
  </template>
  </li>
  </transition-group>
  </draggable>
  </ul>
 </div>
 <div class="col-md-3" v-show="one.productTypes.length>0&&showOne">
  <span><h3 style="color: red">--->>>{{one.name}}</h3></span>
  <ul id="main-nav2" class="nav nav-tabs nav-stacked">
  <draggable class="list-group" tag="ul" v-model="one.productTypes" :move="getdata"@update="datadragEnd">
   <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="(element,index) in one.productTypes" :key="element.id">
    <a :href="'#'+forId(element.uuid)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="nav-header collapsed" data-toggle="collapse"><i
     v-show="element.productList.length>0"
     aria-hidden="true"
     :class="{'fa fa-anchor':isActive,'glyphicon glyphicon-pushpin':!isActive}"
     @click="submenu"></i></a>
    {{element.name}}
    <i class="fa fa-align-justify handle" v-show="element.productTypes.length>0"
    @click="showLeve3(index)"></i>
    <template v-if="element.productList.length>0">
    <ur :id="forId(element.uuid)" class="nav nav-list collapse secondmenu">
     <draggable class="list-group" tag="ul":move="getdata" v-model="element.productList"
      @update="datadragEnds">
     <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="e in element.productList" :key="e.id">
    <a> {{e.name}}</a>
   </li>
   </transition-group>
  </draggable>
  </ur>
  </template>
  </li>
  </transition-group>
  </draggable>
  </ul>
 </div>
 <div class="col-md-3" v-show="two.productTypes.length>0&&showTwo">
  <span><h3 style="color: red">--->>>{{two.name}}</h3></span>
  <ul id="main-nav3" class="nav nav-tabs nav-stacked">
  <draggable class="list-group" tag="ul" v-model="two.productTypes":move="getdata" @update="datadragEnd">
   <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="(element,index) in two.productTypes" :key="element.id">
    <a :href="'#'+forId(element.uuid)" rel="external nofollow" rel="external nofollow" rel="external nofollow" class="nav-header collapsed" data-toggle="collapse"><i
     v-show="element.productList.length>0"
     aria-hidden="true"
     :class="{'fa fa-anchor':isActive,'glyphicon glyphicon-pushpin':!isActive}"
     @click="submenu"></i></a>
    {{element.name}}
    <template v-if="element.productList.length>0">
    <ur :id="forId(element.uuid)" class="nav nav-list collapse secondmenu">
     <draggable class="list-group":move="getdata" tag="ul" v-model="element.productList"
      @update="datadragEnds">
     <transition-group type="transition" :name="'flip-list'">
   <li class="list-group-item" v-for="e in element.productList" :key="e.id">
    <a> {{e.name}}</a>
   </li>
   </transition-group>
  </draggable>
  </ur>
  </template>
  </li>
  </transition-group>
  </draggable>
  </ul>
 </div>
 </div>
 <div class="box-footer">
 <button type="button" class="btn btn-darkness pull-right" id="doSearch"
  style="margin-left: 20px;"@click="save">保存
 </button>
 <button type="button" class="btn btn-default pull-right" @click="reset" id="resetSearch">重置</button>
 </div>
</div>
<script type="text/javascript" src="${ctx}/res/js/vue/vue.js"></script>
<!-- CDNJS :: Sortable (https://cdnjs.com/) -->
<script src="${ctx}/res/js/vue/Sortable.min.js"></script>
<!-- CDNJS :: Vue.Draggable (https://cdnjs.com/) -->
<script src="${ctx}/res/js/vue/vuedraggable.umd.min.js"></script>
<script type="text/javascript" src="${ctx}/res/js/sort/combinationSort.js"></script>

接下来是js。

Vue.component('vue-draggable', vuedraggable)
var vm = new Vue({
 el: '#vueSort',
 data: {
 isActive: true,
 queryObject: {},
 listProductType: [],
 showSon: false,
 index: 0,
 one: {productTypes: []},
 two: {productTypes: []},
 showOne: false,
 showTwo: false
 },
 methods: {
 init: function () {
  var _this = this;
  $.ajax({
  url: '../../mt/combinationSort/sortingData',
  data: null,
  type: 'POST',
  contentType: "application/json",
  dataType: 'json',
  success: function (data) {
   if (data.success = true) {
   if (data.dataObject.length == 0) {
    Util.alert('通知', '异常数据', 'info');
    return;
   }
   _this.listProductType = data.dataObject;
   }
   console.log(data)
  }
  })
 },
 reset: function () {
  var _this = this;
  _this.listProductType = _this.listProductType.sort((one, two) => {
  return one.displaySeq - two.displaySeq;
 })
  ;
  for (var i in _this.listProductType) {
  //排序产品类型
  _this.listProductType[i].productTypes = _this.listProductType[i].productTypes.sort((one, two) => {
   return one.displaySeq - two.displaySeq;
  })
  ;
  //排序产品
  _this.listProductType[i].productList = _this.listProductType[i].productList.sort((one, two) => {
   return one.displaySeq - two.displaySeq;
  })
  ;
  for (var a in _this.listProductType[i].productTypes) {
   _this.listProductType[i].productTypes[a].productTypes = _this.listProductType[i].productTypes[a].productTypes.sort((one, two) => {
   return one.displaySeq - two.displaySeq;
  })
   ;
   _this.listProductType[i].productTypes[a].productList = _this.listProductType[i].productTypes[a].productList.sort((one, two) => {
   return one.displaySeq - two.displaySeq;
  })
   ;
   for (var c in _this.listProductType[i].productTypes[a].productTypes) {
   _this.listProductType[i].productTypes[a].productTypes[c].productList = _this.listProductType[i].productTypes[a].productTypes[c].productList.sort((one, two) => {
    return one.displaySeq - two.displaySeq;
   })
   ;
   }
  }
  }
 },
 datadragEnd: function (evt) {
  console.log('拖动前的索引:' + evt.oldIndex);
  console.log('拖动后的索引:' + evt.newIndex);
  var obj = evt.item;
  obj.style.backgroundColor = '#fff';
 },
 submenu: function () {
  var _this = this;
  if (_this.isActive) _this.isActive = false;
  else _this.isActive = true;
  if (_this.showSon) _this.showSon = false;
  else _this.showSon = true;
 },
 datadragEnds: function (evt) {
  console.log('拖动前的索引:' + evt.oldIndex);
  console.log('拖动后的索引:' + evt.newIndex);
  var obj = evt.item;
  obj.style.backgroundColor = '#fff';
 },
 forId: function (index) {
  return "uuid_" + index
 },

 showLeve2: function (index) {
  var _this = this;
  _this.index = index;
  // if (_this.one.productTypes.length > 0) _this.one.productTypes = [];
  // else
  _this.one = _this.listProductType[index];
  console.log(_this.one)
  if (_this.showOne) {
  _this.showOne = false;
  _this.showTwo = false;
  }
  else _this.showOne = true;
 },
 showLeve3: function (index) {
  var _this = this;
  // if (_this.two.productTypes.length > 0) _this.two.productTypes = [];
  // else
  _this.two = _this.listProductType[_this.index].productTypes[index];
  console.log(_this.two.productTypes)
  if (_this.showTwo) _this.showTwo = false;
  else _this.showTwo = true;
 },
 getdata: function (event) {
  console.log("下来了");
  var obj = event.dragged;
  obj.style.backgroundColor = '#11cc17';
 },
 save: function () {
  var _this = this;
  Util.confirm('提示', '您确定要保存排序吗?', function (isOk) {
  if (isOk) {
   console.log(_this.listProductType);
   $.ajax({
   type: "post",
   url: "../../mt/combinationSort/saveSortingData",
   data: {list: JSON.stringify(_this.listProductType)},
   success: function (json) {
    console.log(json);
   }
   });
   Util.alert("提示", '保存成功', 'info');
  }
  }, 'info');

 }
 },
 created: function () {
 var _this = this;
 _this.init();
 // _this.heartbeat();
 }
});

最重要的是这几行代码

然后是使用vue把vuedraggable模块引入,上面图最下面的js是我刚刚发过的代码文件。

Vue.component('vue-draggable', vuedraggable)

这句话显得尤为重要。注册成vue的组件,虽然它本身就是vue的一个组件了。

当然最后我们会进行排序后的顺序的保存。这里就不得不说vue的双向绑定了,你对象只要在页面改变位置,在内存地址里的位置顺序也会被改变的,所有我们只需要再次将整个对象回传就行。后台去解析保存,当然这种方式我觉得会很繁琐。比如:我贴个获取数据的代码

/**
 * 获取排序数据
 * * @param merchantId
 * @return
 */
 public List<SortProductTypeVo> treeSorting(Long merchantId) {
 //获取所有的连接项
 List<ProductTypeRef> typeRefList = productTypeRefService.findAll();
 //获取所有的产品
 Map<Long, ProductVo> productList = productService.sortFindProduct(merchantId).stream().collect(
  Collectors.toMap(w -> w.getId(), w -> w));
 //最上级父级
 List<SortProductTypeVo> parentList = byParentProduct(merchantId, 0);
 //平均未分类
 List<SortProductTypeVo> typeList = byParentProduct(merchantId, 1);
 //
 //获取产品类型和产品关联
 Map<Long, List<ProductTypeRef>> parentIdChildrenMap = typeRefList.stream().filter(productTypeRef -> productTypeRef.getProductTypeId() != null).collect(Collectors.groupingBy(ProductTypeRef::getProductTypeId));
 parentList.forEach(p -> {
  //筛选第二级菜单
  List<SortProductTypeVo> districtsOne = typeList.stream().filter(sortProductTypeVo -> sortProductTypeVo.getParentTypeId().equals(p.getId())).collect(Collectors.toList());
  districtsOne.forEach(a -> {
  //第三层菜单
  List<SortProductTypeVo> districtsTwo = typeList.stream().filter(productType -> productType.getParentTypeId().equals(a.getId())).collect(Collectors.toList());
  districtsTwo.stream().forEach(d -> {
   //获取产品和产品类型之间的连接关系
   List<ProductTypeRef> l = parentIdChildrenMap.getOrDefault(d.getId(), new ArrayList<>());
   //排序产品关联就相当于产品排序
   l.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
   //根据排序产品关联去找到产品
   d.setProductList(l.stream().map(e -> {
   ProductVo products = productList.get(e.getProductId());
   if (null != products) products.setDisplaySeq(e.getDisplaySeq());
   return products;
   }).collect(Collectors.toList()).stream().filter(s -> s != null).collect(Collectors.toList()));//数组中过滤空的产品
//   d.setProductTypeRefs(parentIdChildrenMap.getOrDefault(d.getId(), new ArrayList<>()));
  });
  List<ProductTypeRef> l = parentIdChildrenMap.getOrDefault(a.getId(), new ArrayList<>());
  l.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
  a.setProductList(l.stream().map(c -> {
   ProductVo products = productList.get(c.getProductId());
   if (null != products) products.setDisplaySeq(c.getDisplaySeq());
   return products;
  }).collect(Collectors.toList()).stream().filter(s -> s != null).collect(Collectors.toList()));
  districtsTwo.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
  a.setProductTypes(districtsTwo);
//  a.setProductTypeRefs(parentIdChildrenMap.getOrDefault(a.getId(), new ArrayList<>()));
  });
  List<ProductTypeRef> l = parentIdChildrenMap.getOrDefault(p.getId(), new ArrayList<>());
  l.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
  p.setProductList(l.stream().map(a -> {
  ProductVo products = productList.get(a.getProductId());
  if (null != products) products.setDisplaySeq(a.getDisplaySeq());
  return products;
  }).collect(Collectors.toList()).stream().filter(s -> s != null).collect(Collectors.toList()));
//  p.setProductTypeRefs(parentIdChildrenMap.getOrDefault(p.getId(), new ArrayList<>()));
  districtsOne.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
  p.setProductTypes(districtsOne);
 });
 parentList.sort((q, b) -> Integer.compare(q.getDisplaySeq(), b.getDisplaySeq()));
 return parentList;
 }

jdk8语法,可能还有需要改进的地方。反正目前来说,功能是实现了。

其实本来想代码一点点讲解的,奈何实在是有事。

关于怎么让3级菜单组件相互拖动,你只需要在父级相互拖动这里就能找到答案,

加上这个属性就行,理论上。我没试过,因为我懒,hhhh

总结

以上所述是小编给大家介绍的基于vue-draggable 实现三级拖动排序效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • Vue.Draggable拖拽功能的配置使用方法

    本文实例为大家分享了Vue.Draggable拖拽功能的具体代码,供大家参考,具体内容如下 使用cmd命令在项目根目录下下载安装Vue.Draggable npm install vuedraggable 在组件中需要使用的引入 import draggable from 'vuedraggable' 注册组件 components:{ draggable } vue的template代码如 <draggable v-model="itemlis" //开始移动方法 :move=

  • Vue.Draggable实现拖拽效果

    快速实现Vue.Draggable的拖拽效果,供大家参考,具体内容如下 1.下载包:npm install vuedraggable 配置:package.json "dependencies": { "element-ui": "^1.3.4", "less": "^2.7.2", "less-loader": "^4.0.4", "vue":

  • vue2 拖动排序 vuedraggable组件的实现

    一.安装插件 npm install -D vuedraggable 二.在需要排序的界面中引入组件 <script> import draggable from 'vuedraggable' export default { name: 'HelloWorld', components: { draggable }, 三.在模板中使用 <draggable v-model="groups" @chang="change" @start="

  • vuedraggable+element ui实现页面控件拖拽排序效果

    项目要实现一些控件的拖拽排序.从而找到了这款vuedraggable控件,供大家参考,具体内容如下 如上图要实现这些控件的拖拽排序 这是拖拽后 由于公司网络的原因,项目没有使用npm,都是使用的引入的js <script type="text/javascript" src="lib/sortable/Sortable.min.js"></script> <script type="text/javascript"

  • 基于vue-draggable 实现三级拖动排序效果

    vue-draggable 之前项目中需要用到拖动排序,就去网上找资料,本来最开始是想用jquery-ui里的拖动的,后面发现不符合我的预期也不知道能不能跟vue.js兼容,后面我试过了,单个的可以但是层级太多就不一样了. 废话少说直接上代码 先看数据结构,和页面的呈现,等会再来上代码. 这就是三层结构渲染出来的图.那个海锚一样的东西是可以点击的,点击后会出现当前类型所带的产品.等会会说的 我们现在来看下我实现后的拖动效果,如下 所有父类型里面的产品拖动如下 控制台的打印 好了,放了那么多图,数

  • vue-awesome-swiper 基于vue实现h5滑动翻页效果【推荐】

    说到h5的翻页,很定第一时间想到的是swiper.但是我当时想到的却是,vue里边怎么用swiper?! vue-awesome-swiper就是其中一个前辈们产出的结晶.就看首尾两个单词,就知道他是vue和swiper的爱情之子了. vue-awesome-swiper官网是中文文档,妈妈再也不用担心我读api啦."基于 Swiper4.适用于 Vue 的轮播组件".在产品催着进度的紧张环境下,在四处搜寻解决方案的情况下,这句话简直发着光啊. 具体怎么用,官方文档写的很清楚,但我还是

  • vue实现移动端拖动排序

    本文实例为大家分享了vue实现移动端拖动排序的具体代码,供大家参考,具体内容如下 效果 代码: <template> <div> <div class="mainDiv" id="columns"> <div id="child" class="childDiv" v-for="(option,index) in options" :key="index&

  • jQuery仿360导航页图标拖动排序效果代码分享

    jquery实现360浏览器导航页图标拖动从新排序特效源码是一款模仿360浏览器导航页网站图标拖动排序的代码.本段代码适应于所有网页使用,有兴趣的朋友们可以学习一下. 运行效果图:                                         ----------------------查看效果 下载源码----------------------- 小提示:浏览器中如果不能正常运行,可以尝试切换浏览模式. 为大家分享的360导航页图标拖动排序效果代码如下 <!DOCTYPE

  • 基于Vue实现页面切换左右滑动效果

    基于Vue的页面切换左右滑动效果,具体内容如下 HTML文本页面: <template> <div id="app> <transition :name="direction" mode="out-in"> <!--动态获得transition 的name值--> <router-view class="app-view" wechat-title></router-vi

  • 基于vue.js实现图片轮播效果

    轮播图效果: 1.html <template> <div class="shuffling"> <div class="fouce fl"> <div class="focus"> <ul class="showimg"> <template v-for='sd in shufflingData'> <li v-if='shufflingId==$

  • Vue.js结合bootstrap前端实现分页和排序效果

    写之前先抱怨几句.本来一心一意做.net开发的,渐渐地成了只做前端.最近项目基本都用java做后台,我们这些.net的就成了前端,不是用wpf做界面,就是用html写web页面. 深知自己前端技术不足,以前虽说用asp.net前后台都做,但是,对于前端都是用现成的js库和页面模板,对于vue.js等框架基本没有接触过. 只怪自己不会写java,最近做一个项目,负责前端,后台传来数据不分页,前端收到所有数据后自己分页.我尽是无语. 正好最近在看vue.js.这个页面就用它来实现吧.顺便总结下. 排

  • Vue 基于 vuedraggable 实现选中、拖拽、排序效果

    今天有个朋友说要做个效果:Vue实现拖拽排序,要有 checked,输出结果是排序后的,要全选,未选中的不能拖动. 其实我之前基于 Sortable 做过一个类似的效果.也给他看过了,没看太明白,他就自己基于 vuedraggable 实现了一下. 正好有点问题给他解决了一下.废话不多说,先上最终效果:Vue 拖拽排序效果 测试地址.下面就是最终效果图. 效果一:实现选中 和 全选效果 就下面这样,elementUI 官方 Demo.很简单毫无挑战呀. <el-checkbox :indeter

  • vue.draggable实现表格拖拽排序效果

    本文实例为大家分享了vue.draggable实现表格拖拽排序效果展示的具体代码,供大家参考,具体内容如下 主要使用vuedraggable和sortablejs两个组件. 1.安装组件 npm install vuedraggable npm install sortablejs 2.引入组件 import draggable from 'vuedraggable'; import Sortable from 'sortablejs'; export default { components:

  • vue如何实现拖动图片进行排序Vue.Draggable

    目录 拖动图片进行排序Vue.Draggable 下面是实现过程 项目draggable拖拽移动图片顺序 第一步.导入 第二步.组件引入 第三步.定义组件 第四步.页面中使用 拖动图片进行排序Vue.Draggable 好久没接触vue的项目了,最近接到一个vue图片处理的小项目,有一项需求是要实现拖动图片就行排序. 接到这个需求之后立马想到了Vue.Draggable这款基于Sortable.js实现的vue拖拽插件 下面是实现过程 第一步:安装Vue.Draggable.两种方式npm和ya

随机推荐