基于vue实现一个禅道主页拖拽效果


Posted in Javascript onMay 27, 2019

效果图如下所示:

基于vue实现一个禅道主页拖拽效果

源码地址

bb两句

最近在做一个基于vue的后台管理项目。平时项目进度统计就在上禅道上进行。so~ 然后领导就感觉这个拖拽效果还行,能不能加到咱们项目里面。 既然领导发话,那就开干。。

所有技术:vue + vuedraggable

拖动的实现基于 vuedraggable 的插件开发。

主页为两栏流式布局,每一个组件可以在上下拖动,也可以左右拖动。

基于vue实现一个禅道主页拖拽效果

基本步骤

布局

这块布局为最为普通的两栏布局,这里采用flex布局。左边自适应,右边为固定宽。

.layout-container {
 display: flex;
 .left {
 flex: 1;
 margin-right: 40px;
 }
 .right {
 width: 550px;
 }
}

拖拽实现

这里使用 vuedraggable 插件。需要在组件里面引入使用。 draggable 相当于拖拽容器,这块很明显需要两个拖拽的容器。所以分别在 .left .right 中添加两个拖拽容器。在默认情况下,这里已经可以进行拖拽了。插件的效果还是很强大。

<div class="layout-container">
  <!--左栏-->
 <div class="left">
  <draggable
   v-bind="dragOptions"
   class="list-group"
   :list="item"
  >
   // ... 拖拽元素或组件
  </draggable>
  </div>
  <!--右栏-->
 <div class="right">
  <draggable
   v-bind="dragOptions"
   class="list-group"
   :list="item"
  >
   // ... 拖拽元素或组件
  </draggable>
 </div>
</div>
<script>
import draggable from "vuedraggable";
export default {
 components: {draggable},
 computed: {
 dragOptions() {
  return {
  animation: 30,
  handle: ".drag-handle",
  group: "description",
  ghostClass: "ghost",
  chosenClass: "sortable",
  forceFallback: true
  };
 }
 }
};
</script>

但是, 和我想要的效果还是相差一点。

左右拖动 与 仅标题栏拖动

这块只需要配置相关的配置项就可以比较简单。 左右拖动需要给拖拽容器指定相同的 group 属性。指定标题元素拖动需要配置 handle 为可拖动元素的选择器名称。

下面简单介绍下常用的配置项:

  • disabled :boolean 定义是否此sortable对象是否可用,为true时sortable对象不能拖放排序等功能,为false时为可以进行排序,相当于一个开关;
  • group : 用处是为了设置可以拖放容器时使用,若两个容器该配置项相同,则可以相互拖动;
  • animation :number 单位:ms,定义排序动画的时间;
  • handle :selector 格式为简单css选择器的字符串,使列表单元中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表单元进行拖动;
  • filter :selector 格式为简单css选择器的字符串,定义哪些列表单元不能进行拖放,可设置为多个选择器,中间用“,”分隔;
  • draggable :selector 格式为简单css选择器的字符串,定义哪些列表单元可以进行拖放
  • ghostClass :selector 格式为简单css选择器的字符串,当拖动列表单元时会生成一个副本作为影子单元来模拟被拖动单元排序的情况,此配置项就是来给这个影子单元添加一个class,我们可以通过这种方式来给影子元素进行编辑样式;
  • chosenClass :selector 格式为简单css选择器的字符串,当选中列表单元时会给该单元增加一个class;
  • forceFallback :boolean 如果设置为true时,将不使用原生的html5的拖放,可以修改一些拖放中元素的样式等;
  • fallbackClass :string 当forceFallback设置为true时,拖放过程中鼠标附着单元的样式;

采用相关配置如下:

computed: {
 dragOptions() {
  return {
  animation: 30,
  handle: ".drag-handle",
  group: "description",
  ghostClass: "ghost",
  chosenClass: "sortable",
  forceFallback: true
  };
 }
 }

拖动时样式调整

在拖动的时候,我们需要做三个事情。拖动时,拖动元素只显示标题栏,两栏内列表只显示标题元素以及将要移动的位置变灰。

1.拖动元素只显示标题栏: 在默认情况下,会开启 html5 元素的拖动效果。这里明显不需要。 forceFallback 改为 false 则可以关闭 html5 的默认效果。顺便通过 chosenClass: "sortable" 修改拖动元素class 类名。直接用css进行隐藏

.sortable {
 .component-box {
 display: none;
 height: 0;
 }
}

2.两栏内列表只显示标题元素 这里我借助两个事件实现。

  • onStart:function 列表单元拖动开始的回调函数
  • onEnd:function 列表单元拖放结束后的回调函数
<div class="layout-container" :class="{drag:dragging}">
 //...
</div>
data() {
 return {
  dragging: false
 };
},
methods: {
 onStart() {
  this.dragging = true;
 },
 onEnd() {
  this.dragging = false;
 }
 }
.drag {
 .component-box {
 display: none;
 }
}

在开始拖动的时候给 .layout-container 添加 .drag 的 class 名。拖动结束时,移除class名。

将要移动的位置变灰

这里需要用到上面 ghostClass: "ghost" 配置项。并添加相应的css。

.ghost {
 .drag-handle {
 background: rgb(129, 168, 187);
 }
}

好了基本已经实现了。。。

基于vue实现一个禅道主页拖拽效果

展示动态组件

接下来就是数据的动态展示了。 这里需要vue中的动态组件了。。附上官方文档连接点击查看。

然后里面每个拖动的元素的内容都写成组件,搭配动态组件实现自由拖动。

// 将所用组件引入
import {
 timeline,
 calendar,
 welcome,
 carousel,
 imgs,
 KonList
} from "@/components/DragComponents";

components: {
 draggable,
 timeline,
 calendar,
 welcome,
 carousel,
 imgs,
 KonList
}

配合 v-for 对数据进行循环,然后进行动态展示。

<component :is="element.name"/>

这块涉及到数据格式相关的,可以直接看文末的代码。。。 这里就就不展开说了。。

数据保持

在拖动结束后,我们需要将拖动的顺序缓存在前端,当下次进入后,可以继续使用拖动后的数据。

// 获取新的布局
 getLayout() {
  let myLayout = JSON.parse(window.localStorage.getItem("kon"));
  if (!myLayout || Object.keys(myLayout).length === 0)
  myLayout = this.layout;
  const newLayout = {};
  for (const side in myLayout) {
  newLayout[side] = myLayout[side].map(i => {
   return this.componentList.find(c => c.id === i);
  });
  }
  this.mainData = newLayout;
},
// 设置新的布局
setLayout() {
 const res = {};
 for (const side in this.mainData) {
  const item = this.mainData[side].map(i => i.id);
  res[side]=item;
 }
 window.localStorage.setItem("kon", JSON.stringify(res));
}

这样我只需要在 mounted 中获取新的布局。。

mounted() {
 this.getLayout();
 }

在拖动结束后,设置新的布局

onEnd() {
  this.dragging = false;
  this.setLayout();
}

在项目中,还是建议配合后端进行用户布局的数据存储,每次拖动后将新的布局数据请求接口保存在数据库,同时存入缓存中。当再次进入页面的时候,读取缓存中的数据,没有的话请求后端的接口拿到用户的布局,然后再次存入缓存中。有的话直接读取缓存中的数据。

最后说两句

其实上面的效果也不是特别难,简单花点时间,看看相关文档,就能做出来,,记录在掘金上面,只是想和大家分享我的思路。同时希望和大家一起交流,一起进步。

基于vue实现一个禅道主页拖拽效果

生活不易,大家加油

附上源码: 项目地址

<template>
 <div :class="{drag:dragging}">
  <div class="layout-container">
   <div :class="key" v-for="(item, key) in mainData" :key="key">
    <draggable
     v-bind="dragOptions"
     class="list-group"
     :list="item"
     @end="onEnd"
     @start="onStart"
    >
     <transition-group name="list">
      <div class="list-group-item" v-for="(element, index) in item" :key="index">
       <div class="drag-handle">{{ element.title }}</div>
       <div class="component-box">
        <component :is="element.name"/>
       </div>
      </div>
     </transition-group>
    </draggable>
   </div>
  </div>
 </div>
</template>
<script>
import draggable from "vuedraggable";
import {
 timeline,
 calendar,
 welcome,
 carousel,
 imgs,
 KonList
} from "@/components/DragComponents";

export default {
 components: {
  draggable,
  timeline,
  calendar,
  welcome,
  carousel,
  imgs,
  KonList
 },
 data() {
  return {
   dragging: false,
   componentList: [
    { name: "KonList", title: "追番地址", id: "5" },
    { name: "imgs", title: "五月最强新番", id: "4" },
    { name: "timeline", title: "日程组件", id: "2" },
    { name: "carousel", title: "走马灯组件", id: "1" },
    { name: "calendar", title: "日历组件", id: "3" }
   ],
   layout: {
    left: ["5", "4"],
    right: ["2", "1", "3"]
   },
   mainData: {}
  };
 },
 computed: {
  dragOptions() {
   return {
    animation: 30,
    handle: ".drag-handle",
    group: "description",
    ghostClass: "ghost",
    chosenClass: "sortable",
    forceFallback: true
   };
  }
 },
 mounted() {
  this.getLayout();
 },
 methods: {
  onStart() {
   this.dragging = true;
  },
  onEnd() {
   this.dragging = false;
   this.setLayout();
  },
  getLayout() {
   let myLayout = JSON.parse(window.localStorage.getItem("kon"));
   if (!myLayout || Object.keys(myLayout).length === 0)
    myLayout = this.layout;
   const newLayout = {};
   for (const side in myLayout) {
    newLayout[side] = myLayout[side].map(i => {
     return this.componentList.find(c => c.id === i);
    });
   }
   this.mainData = newLayout;
  },
  setLayout() {
   const res = {};
   for (const side in this.mainData) {
    const item = this.mainData[side].map(i => i.id);
    res[side]=item;
   }
   window.localStorage.setItem("kon", JSON.stringify(res));
  }
 }
};
</script>
<style lang="scss" scoped>
.layout-container {
 height: 100%;
 display: flex;
 .left {
  flex: 1;
  margin-right: 40px;
 }
 .right {
  width: 550px;
 }
 .list-group-item {
  margin-bottom: 20px;
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
 }
 .component-box {
  padding: 20px;
 }
 .drag-handle {
  cursor: move;
  height: 40px;
  line-height: 40px;
  color: #fff;
  font-weight: 700;
  font-size: 16px;
  padding: 0 20px;
  background: #6cf;
 }
}
.drag {
 .component-box {
  display: none;
 }
}

.list-enter-active {
 transition: all .3s linear;

}
.list-enter,
.list-leave-to {
 opacity: .5;
}

.sortable {
 .component-box {
  display: none;
  height: 0;
 }
}
.list-group {
 > span {
  display: block;
  min-height: 20px;
 }
}

.ghost {
 .drag-handle {
  background: rgb(129, 168, 187);
 }
}
</style>

总结

以上所述是小编给大家介绍的基于vue实现一个禅道主页拖拽效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
Javascript 模式实例 观察者模式
Oct 24 Javascript
使用jquery中height()方法获取各种高度大全
Apr 02 Javascript
对 jQuery 中 data 方法的误解分析
Jun 18 Javascript
gridview生成时如何去掉style属性中的border-collapse
Sep 30 Javascript
JsRender for object语法简介
Oct 31 Javascript
jQuery Ajax 加载数据时异步显示加载动画
Aug 01 Javascript
Canvas 绘制粒子动画背景
Feb 15 Javascript
Bootstrap笔记—折叠实例代码
Mar 13 Javascript
Angular实现搜索框及价格上下限功能
Jan 19 Javascript
vuejs实现ready函数加载完之后执行某个函数的方法
Aug 31 Javascript
微信小程序实现搜索功能并跳转搜索结果页面
May 18 Javascript
react+antd 递归实现树状目录操作
Nov 02 Javascript
jQuery实现input输入框获取焦点与失去焦点时提示的消失与显示功能示例
May 27 #jQuery
初学node.js中实现删除用户路由
May 27 #Javascript
jquery实现动态创建form并提交的方法示例
May 27 #jQuery
jquery实现动态改变css样式的方法分析
May 27 #jQuery
Vue scrollBehavior 滚动行为实现后退页面显示在上次浏览的位置
May 27 #Javascript
通过jQuery学习js类型判断的技巧
May 27 #jQuery
实现高性能javascript的注意事项
May 27 #Javascript
You might like
php生成EAN_13标准条形码实例
2013/11/13 PHP
编译PHP报错configure error Cannot find libmysqlclient under usr的解决方法
2014/06/27 PHP
PHPMailer发送HTML内容、带附件的邮件实例
2014/07/01 PHP
微信公众号点击菜单即可打开并登录微站的实现方法
2014/11/14 PHP
Javascript实现的分页函数
2006/12/22 Javascript
动态为事件添加js代码示例
2009/02/15 Javascript
用js小类库获取浏览器的高度和宽度信息
2012/01/15 Javascript
jquery load事件(callback/data)使用方法及注意事项
2013/02/06 Javascript
JQuery操作单选按钮以及复选按钮示例
2013/09/23 Javascript
jquery右下角弹出提示框示例代码
2013/10/08 Javascript
原生js ActiveXObject获取execl里面的值
2013/11/01 Javascript
常见的原始JS选择器使用方法总结
2014/04/09 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
nodejs教程之入门
2014/11/21 NodeJs
javascript自定义滚动条实现代码
2020/04/20 Javascript
MUI 上拉刷新/下拉加载功能实例代码
2017/04/13 Javascript
详解vee-validate的使用个人小结
2017/06/07 Javascript
深入理解React高阶组件
2017/09/28 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
echarts整合多个类似option的方法实例
2018/07/10 Javascript
原生js实现日历效果
2020/03/02 Javascript
在树莓派2或树莓派B+上安装Python和OpenCV的教程
2015/03/30 Python
Python实现豆瓣图片下载的方法
2015/05/25 Python
详解Python爬虫的基本写法
2016/01/08 Python
名片管理系统python版
2018/01/11 Python
python交互模式下输入换行/输入多行命令的方法
2019/07/02 Python
Python爬虫使用浏览器cookies:browsercookie过程解析
2019/10/22 Python
没编程基础可以学python吗
2020/06/17 Python
css3 边框、背景、文本效果的实现代码
2018/03/21 HTML / CSS
采用专利算法搜索最廉价的机票:CheapAir
2016/09/10 全球购物
铁路工务反思材料
2014/02/07 职场文书
环境监测与治理技术专业求职信
2014/07/06 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
2014年政协工作总结
2014/12/09 职场文书
赞美教师的句子
2019/09/02 职场文书
Python绘制散乱的点构成的图的方法
2022/04/21 Python