基于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 相关文章推荐
js 函数的执行环境和作用域链的深入解析
Nov 01 Javascript
页面按钮禁用与解除禁用的方法
Feb 19 Javascript
JS实现网页背景颜色与select框中颜色同时变化的方法
Feb 27 Javascript
JS实现新浪微博效果带遮罩层的弹出框代码
Oct 12 Javascript
基于jQuery实现交互体验社会化分享代码附源码下载
Jan 04 Javascript
javascript简单实现跟随滚动条漂浮的返回顶部按钮效果
Aug 19 Javascript
js仿支付宝多方框输入支付密码效果
Sep 27 Javascript
搭建Bootstrap离线文档的方法
Dec 02 Javascript
Three.js利用dat.GUI如何简化试验流程详解
Sep 26 Javascript
JS代码实现电脑配置检测功能
Mar 21 Javascript
深入理解令牌认证机制(token)
Aug 22 Javascript
Axios取消重复请求的方法实例详解
Jun 15 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
PHP4实际应用经验篇(6)
2006/10/09 PHP
php switch语句多个值匹配同一代码块的实现
2014/03/03 PHP
php截取视频指定帧为图片
2016/05/16 PHP
一个实用的php验证码类
2017/07/06 PHP
PHP设计模式之组合模式定义与应用示例
2020/02/01 PHP
jQuery右侧选项卡焦点图片轮播特效代码分享
2015/09/05 Javascript
原生JS实现首页进度加载动画
2016/09/14 Javascript
javascript 秒表计时器实现代码
2017/03/09 Javascript
NodeJS测试框架mocha入门教程
2017/03/28 NodeJs
Vue-cli proxyTable 解决开发环境的跨域问题详解
2017/05/18 Javascript
JS图片预加载插件详解
2017/06/21 Javascript
JavaScript使用Ajax上传文件的示例代码
2017/08/10 Javascript
js 开发之autocomplete=&quot;off&quot;在chrom中失效的解决办法
2017/09/28 Javascript
jquery鼠标悬停导航下划线滑出效果
2017/09/29 jQuery
JavaScript生成指定范围的时间列表
2018/03/19 Javascript
Vue文本模糊匹配功能如何实现
2020/07/30 Javascript
Python中用Descriptor实现类级属性(Property)详解
2014/09/18 Python
Python爬取豆瓣视频信息代码实例
2019/11/16 Python
wxPython实现带颜色的进度条
2019/11/19 Python
TensorFlow基本的常量、变量和运算操作详解
2020/02/03 Python
django模型动态修改参数,增加 filter 字段的方式
2020/03/16 Python
Python如何使用正则表达式爬取京东商品信息
2020/06/01 Python
浅谈django框架集成swagger以及自定义参数问题
2020/07/07 Python
pyqt5实现井字棋的示例代码
2020/12/07 Python
什么是JNDI的上下文?如何初始化JNDI上下文
2012/03/10 面试题
Weblogic和WebSphere不同特点
2012/05/09 面试题
校园达人秀策划书
2014/01/12 职场文书
妇女儿童发展规划实施方案
2014/03/16 职场文书
竞聘自述材料
2014/08/25 职场文书
介绍信的格式
2015/01/30 职场文书
西安导游词
2015/02/12 职场文书
2015年助理工程师工作总结
2015/04/03 职场文书
2015社区六五普法工作总结
2015/04/21 职场文书
【HBU】数据库第四周 单表查询
2021/04/05 SQL Server
Python使用永中文档转换服务
2022/05/06 Python
Python可视化神器pyecharts之绘制箱形图
2022/07/07 Python