位置: IT常识 - 正文

vue2实现可拖拽甘特图(结合element-ui的gantt图)(vue 可拖拽)

编辑:rootadmin
vue2实现可拖拽甘特图(结合element-ui的gantt图) 一、前言

推荐整理分享vue2实现可拖拽甘特图(结合element-ui的gantt图)(vue 可拖拽),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:vue 拖拽到目标区域,vue 拖拽div,vue 拖拽div,vue3 拖拽,vuejs拖拽,vue实现拖拽生成新的页面,vue3 拖拽,vue 可拖拽,内容如对您有帮助,希望把文章链接给更多的朋友!

  接到公司需求,要做一个可拖拽的甘特图来实现排期需求,官方的插件要付费还没有中文的官方文档可以看,就去找了各种开源的demo来看,功能上都不是很齐全,于是总结了很多demo,合在一起组成了一版较为完整的满足需求的甘特图。

二、主要功能

1.拖拽  拖拽功能是甘特图的主要功能,该demo实现了甘特图时间块上、下、左、右拖拽功能。

2.排序 拖拽后时间块进行排序,计算重叠区域大小确定插入位置。

3.时间选择 结合element-ui的日期时间选择器来确定时间轴。

4.搜索  搜索已存在的时间块,并定位到相应位置。

vue2实现可拖拽甘特图(结合element-ui的gantt图)(vue 可拖拽)

5.新建排期任务  使用element-ui的弹框以及表单 新建成功的排期列表添加到排期任务中。

6.右键菜单 右击时间块,可以进行查看、删除、修改等操作。

7.撤回 每删除或移动时间块后,增加一条操作记录,点击撤回可撤回当前操作。

8.批量操作 在批量操作后点击保存,才向后端存储数据。

三、功能实现

1.默认时间轴线今天的前三后四

// 设置默认时间 当前日期前三后四defaultDate() {const beg = new Date(new Date().getTime() - 3600 * 1000 * 24 * 3).toISOString().replace('T', ' ').split('.')[0] //默认开始时间3天前const end = new Date(new Date().getTime() + 3600 * 1000 * 24 * 4).toISOString().replace('T', ' ').split('.')[0]//默认结束时间4天后this.choiceTime = [beg, end] //将值设置给插件绑定的数据// console.log(this.value1);},

 2.拖拽事件实现

onMouseDown(e, blockId, rowIndex) {// 删除模式下不处理拖动事件if (this.isDeleteMode) {return;}this.moveX = 0;this.moveY = 0;// 用box 移动,不采用 Doucmentconst box = this.$refs.box;const dom = e.target;// 算出鼠标相对元素的位置const disX = e.clientX - dom.offsetLeft;const disY = e.clientY - dom.offsetTop;console.log('鼠标正在拖动',e.clientX,dom.offsetLeft);// 当点击下来的时候 nowSuck 其实等于的就是当前indexthis.nowSuck = rowIndex;// 让本来拥有手掌样式的class取消dom.classList.remove('gantt-grab');// 让整个box 鼠标都是抓住box.classList.add('gantt-grabbing');// 如果事件绑定在 dom上,那么一旦鼠标移动过快就会脱离掌控box.onmousemove = ee => {// 获得当前受到拖拽的div 用于计算suck 所谓拖引的行数const top = parseInt(dom.style.top);// 四舍五入 获得磁性吸附激活的值 (索引值) 60是block的height 10是时间块距离block的top suck 可以当作row的索引let suck = Math.round((top - 10) / 60) + rowIndex;// suck的边界值设置if (suck < 0) {suck = 0;} else if (suck > this.ganttData.length - 1) {suck = this.ganttData.length - 1;}// suck 行样式变化this.nowSuck = suck;// 移动事件this.onMouseMove(ee, disX, disY, dom);// dom.style.left=this.moveX;};// 不管在哪里,鼠标松开的时候,清空事件 所以对于这个 “不管在哪里,使用了window”window.onmouseup = () => {// 鼠标松开了,让时间块恢复手掌样式dom.classList.add('gantt-grab');// 整个box 不在抓住了,变成箭头鼠标box.classList.remove('gantt-grabbing');// 当移动距离小于5时,不做移动处理//console.log('移动距离:', this.moveX, this.moveY);if (this.moveX < 1 && this.moveY < 1 && this.moveX > -1 && this.moveY > -1) {console.log('无效移动');box.onmousemove = null;window.onmouseup = null;this.nowSuck = -1;return;}// 保存操作日志this._addHisList(this.ganttData);const index = this.ganttData[rowIndex][this.listKey].findIndex(item => {return item.id === blockId;});const oldTimeBlock = this.ganttData[rowIndex][this.listKey][index];// let timeId = oldTimeBlock.id;// startTime 与 endTime 用于数据重新替换 上面css已经经过计算 15px为1小时const startTime = new Date(Date.parse(this.choiceTime[0]) + (parseInt(dom.style.left) * 3600000) / 15);const endTime = new Date(this._getTime(startTime) + (parseInt(dom.style.width) * 3600000) / 15);// console.log(startTime, endTime, dom.style.width, parseInt(dom.style.left) * 60 * 1000);const suck = this.nowSuck;// 加入新数据const data = oldTimeBlock;// 更新开始时间和结束时间this.$set(data, 'startTime', startTime);this.$set(data, 'endTime', endTime);// 修改时间块的equipmentIdthis.$set(data, 'equipmentId', this.ganttData[suck].id);/** * 本来dom元素磁性吸附是打算用document.appendChild() 方式来做的,但是对于vue来说 for出来的子元素就算变了位置,其index也不属于新的row */// 老数据 删除this.ganttData[rowIndex][this.listKey].splice(index, 1);// 新数据加入this.ganttData[suck][this.listKey].push(data);// 坐标定位 磁性吸附 永远的10px 不知道为啥动态绑定的元素也会受到以前元素的影响,可能是 for 中 index带来的影响dom.style.top = this.defaultTop + 'px';// 松开鼠标的时候 清空box.onmousemove = null;window.onmouseup = null;// 需要重新计算吸附位置,以及整行重新排列this.$nextTick(() => {this._recalcRowTimes(data, this.ganttData[suck][this.listKey]);});// 将当前row 清空this.nowSuck = -1;// 改变位置后回调事件this.afterChangePosition(data, this.ganttData[rowIndex].id, this.ganttData[suck].id);};},/** * 鼠标移动的时候,前置条件鼠标按下 * @param e 时间块的 event 事件 * @param disX x轴 * @param disY y轴 * @param targetDom 时间块的dom 其实可以直接 e.target 获取 */onMouseMove(e, disX, disY, targetDom) {// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置let left = e.clientX - disX;const top = e.clientY - disY;console.log('x轴移动距离',left);this.moveX = left;this.moveY = top;// 移动位置不能小于零(开始时间)if (left < 0) {left = 0;}//拖动时间块关闭右键菜单this.menuVisible = false;targetDom.style.left = left + 'px';targetDom.style.top = top + 'px';},/** * 时间块位置变化后回调事件 * @param data 时间块的值 包括时间块id startTime endTime * @param rowOId 时间块原来所在的那个飞机id (一条横线) * @param rowNId 时间块新的所在的那个飞机id */afterChangePosition(data, rowOId, rowNId) {console.log('时间块位置变化后回调事件', rowOId, rowNId);},save() {console.log(JSON.stringify(this.ganttData));},

3. 右击设置自定义右键菜单

onRightClick(MouseEvent, row, block) {//编辑需要把时间长度先计算好MouseEvent.preventDefault(); //关闭浏览器右键默认事件block.timeDiff = (block.endTime - block.startTime) / 3600000;this.editRow = row;this.editBlock = block;// this.menuVisible = false; // 先把模态框关死,目的是 第二次或者第n次右键鼠标的时候 它默认的是truethis.menuVisible = true; // 显示模态窗口,跳出自定义菜单栏console.log('唤醒点击事件', this.menuVisible, this.editBlock, MouseEvent.clientX);this.CurrentRow = row;var menu = document.querySelector('.menu');if (MouseEvent.clientX > 1800) {menu.style.left = MouseEvent.clientX - 100 + 'px';} else {menu.style.left = MouseEvent.clientX + 1 + 'px';}document.addEventListener('click', this.cancelMouse); // 给整个document新增监听鼠标事件,点击任何位置执行foo方法if (MouseEvent.clientY > 700) {menu.style.top = MouseEvent.clientY - 30 + 'px';} else {menu.style.top = MouseEvent.clientY - 10 + 'px';}console.log('位置問題', MouseEvent.clientY - 30 + 'px', MouseEvent.clientY - 10 + 'px');// this.styleMenu(menu);},cancelMouse() {// document.oncontextmenu=false;// 取消鼠标监听事件 菜单栏this.menuVisible = false;document.removeEventListener('click', this.foo); // 关掉监听,},

4.计算时间选择器相差天数以渲染时间轴

choiceTimeArr() {const timeArr = [];// 时间戳毫秒为单位// 尾时间-首时间 算出头尾的时间戳差 再换算成天单位 毫秒->分->时->天// const diffDays = (this.choiceTime[1].getTime() - this.choiceTime[0].getTime()) / 1000 / 60 / 60 / 24;const diffDays = Math.abs(Date.parse(this.choiceTime[1])- Date.parse(this.choiceTime[0])) / 1000 / 60 / 60 / 24console.log('我是时间差啊', diffDays);// 一天的时间戳)const oneDayMs = 24 * 60 * 60 * 1000;// 差了多少天就便利多少天 首时间+当前便利的天数的毫秒数for (let i = 0; i < diffDays + 1; i++) {// 时间戳来一个相加,得到的就是时间数组timeArr.push(new Date(Date.parse(this.choiceTime[0]) + i * oneDayMs));}// console.log(diffDays, oneDayMs, timeArr);return timeArr;},

 5.搜索功能(使用element-ui的示例)

// 搜索数据数组loadAll() {return [{ "value": "三全鲜食(北新泾店)", "address": "长宁区新渔路144号" },{ "value": "Hot honey 首尔炸鸡(仙霞路)", "address": "上海市长宁区淞虹路661号" },{ "value": "新旺角茶餐厅", "address": "上海市普陀区真北路988号创邑金沙谷6号楼113" },{ "value": "泷千家(天山西路店)", "address": "天山西路438号" },{ "value": "胖仙女纸杯蛋糕(上海凌空店)", "address": "上海市长宁区金钟路968号1幢18号楼一层商铺18-101" },{ "value": "贡茶", "address": "上海市长宁区金钟路633号" },{ "value": "豪大大香鸡排超级奶爸", "address": "上海市嘉定区曹安公路曹安路1685号" },{ "value": "茶芝兰(奶茶,手抓饼)", "address": "上海市普陀区同普路1435号" },{ "value": "十二泷町", "address": "上海市北翟路1444弄81号B幢-107" },{ "value": "星移浓缩咖啡", "address": "上海市嘉定区新郁路817号" },{ "value": "阿姨奶茶/豪大大", "address": "嘉定区曹安路1611号" },{ "value": "新麦甜四季甜品炸鸡", "address": "嘉定区曹安公路2383弄55号" }];},querySearchAsync(queryString, cb) {var restaurants = this.restaurants;var results = queryString ? restaurants.filter(this.createStateFilter(queryString)) : restaurants;clearTimeout(this.timeout);this.timeout = setTimeout(() => {cb(results);}, 3000 * Math.random());},createStateFilter(queryString) {return (state) => {return (state.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);};},handleSelect(item) {console.log(item);}, 四、实现效果 

      由于需求是以弹框形式实现,没有做全屏显示,具体效果如下:

甘特图实现
本文链接地址:https://www.jiuchutong.com/zhishi/298913.html 转载请保留说明!

上一篇:Ep_操作系统面试题-什么是协程(erp面试题目100及最佳答案)

下一篇:为什么说网络安全行业是 IT 行业最后的红利?(为什么说网络安全靠人民)

  • 地铁广告流量就像笑话网站的流量 海量却未必有用(地铁广告收益)

    地铁广告流量就像笑话网站的流量 海量却未必有用(地铁广告收益)

  • b站怎么设置退出后台继续播放(b站怎么设置退出后仍播放)

    b站怎么设置退出后台继续播放(b站怎么设置退出后仍播放)

  • 手机补丁包需要更新吗(手机补丁包是什么)

    手机补丁包需要更新吗(手机补丁包是什么)

  • 微信群聊最多40人怎么办(微信群聊最多40人怎么弄)

    微信群聊最多40人怎么办(微信群聊最多40人怎么弄)

  • 抖音火苗有什么用(抖音火苗什么情况下会消失)

    抖音火苗有什么用(抖音火苗什么情况下会消失)

  • 微信好友不删 怎么隐藏(微信好友不删除怎么拒收消息)

    微信好友不删 怎么隐藏(微信好友不删除怎么拒收消息)

  • 推特机器人验证怎么过(推特机器人验证手机号)

    推特机器人验证怎么过(推特机器人验证手机号)

  • 微信语音会议最多几人(微信语音会议最多15人)

    微信语音会议最多几人(微信语音会议最多15人)

  • 解析安装包出现问题怎么解决(解析安装包出现错误无法安装怎么办)

    解析安装包出现问题怎么解决(解析安装包出现错误无法安装怎么办)

  • 笔记本声音大嗡嗡响是怎么回事(笔记本声音大嗡嗡响需要清灰吗)

    笔记本声音大嗡嗡响是怎么回事(笔记本声音大嗡嗡响需要清灰吗)

  • 有锁机黑解是什么意思(有锁机黑解完就没事了吗)

    有锁机黑解是什么意思(有锁机黑解完就没事了吗)

  • 剪映可以视频抠图吗(剪映视频抠成透明背景怎么弄)

    剪映可以视频抠图吗(剪映视频抠成透明背景怎么弄)

  • 苹果手机显示网络不可用怎么办(苹果手机显示网络不稳定是什么意思)

    苹果手机显示网络不可用怎么办(苹果手机显示网络不稳定是什么意思)

  • 键盘上刷新键是什么(键盘上那个是刷新键)

    键盘上刷新键是什么(键盘上那个是刷新键)

  • ie图标不见了怎么恢复(ie图标不见了怎么办)

    ie图标不见了怎么恢复(ie图标不见了怎么办)

  • 手机剪映素材丢失怎么办(手机剪映素材丢失怎么恢复)

    手机剪映素材丢失怎么办(手机剪映素材丢失怎么恢复)

  • 华为3e怎么恢复出厂设置(华为3e恢复出厂设置怎么打开)

    华为3e怎么恢复出厂设置(华为3e恢复出厂设置怎么打开)

  • 如何退出亲情号码(怎么退出亲情号成员并且不再加入)

    如何退出亲情号码(怎么退出亲情号成员并且不再加入)

  • airbnb怎么删除房源(airbnb怎么删除已完成的订单)

    airbnb怎么删除房源(airbnb怎么删除已完成的订单)

  • 微信怎样批量删除好友(微信怎样批量删除公众号)

    微信怎样批量删除好友(微信怎样批量删除公众号)

  • 云电脑有免费的吗(云电脑免费的有哪些)

    云电脑有免费的吗(云电脑免费的有哪些)

  • 顶格怎么设置(word左顶格怎么设置)

    顶格怎么设置(word左顶格怎么设置)

  • ps填充颜色快捷键(照片填充颜色怎么弄)

    ps填充颜色快捷键(照片填充颜色怎么弄)

  • 苹果耳机不响(苹果耳机不响了能修吗)

    苹果耳机不响(苹果耳机不响了能修吗)

  • 执行企业会计准则第21号租赁的企业
  • 一季度计提的所得税分录
  • 个体户逾期申报罚款多少
  • 利润表季报本月金额是本季度余额吗
  • 已过期增值税专票怎么开
  • 房地产企业汇缴清算条件
  • 因小数点造成的误差称为
  • 税费改革是什么
  • 个人转到公司账上的钱能开发票吗
  • 以物易物方式销售货物例题
  • 单位自有车辆
  • 应付职工薪酬月末结转到哪里
  • 增值税一般纳税人税率
  • 房产税计税依据房产原值怎么算
  • 销售退回怎么开票
  • 销售净利润率是综合反映企业成本效益的重要指标
  • 利息支出应计入
  • 超过三年的坏帐损失税前扣除怎样规定?
  • 白银及其制品出自哪里
  • 民间非盈利组织会计要素组成
  • 税收返还的账务处理
  • 公司估值一般不超过市值多少
  • 个税抵扣申报截止时间
  • 增值税专票和普票的区别税率
  • 银行提取备用金会计分录
  • 如何处理库存差异问题
  • 企业存款利息收入增值税
  • 命令行查看ip地址
  • 加载分页
  • 幼儿园会计需要什么条件
  • 电子税务局已申报信息查询
  • php扫二维码
  • 公司向法人借款的借条怎么写
  • 没有实收资本可以投资吗
  • 科目余额表怎么导出
  • 员工保险个人部分交多少
  • vue的slice
  • 帝国cms手机端点击加载不动怎么弄
  • 工业企业采购流程
  • python连接网络
  • day29--Java泛型02
  • 错账的类型及对应的更正方法
  • 帝国cms中英
  • 暂估入库成本处理
  • python索引值-1和位置-1
  • 规划设计费会计分录
  • 增值税发票如何作废流程
  • 金蝶专业版仓库管理怎么结账
  • mysql配置文件my.ini如何配置
  • 支付其它与经营活动有关的现金对不上
  • 权益法股权投资收益纳税调减
  • 股东向公司借款多久必须归还
  • 一般纳税人购货取得普通发票
  • 手写账目表格怎么做
  • 关联公司之间的借款
  • 餐饮服务属于什么职业
  • 总分类账封面封地和启用页的区别
  • 本单位职工可以在本单位兼职吗
  • 外账会计做什么
  • sql入门课程
  • mysql 左链接 右链接
  • windows许可证即将过期怎么办知乎
  • Win10怎么显示我的电脑
  • server.exe是什么
  • win7系统控制面板在哪里打开
  • hp是什么代码
  • 安装完xp系统直接黑屏怎么办
  • linux命令tee
  • linux中vi编辑器怎么使用
  • win7 host文件路径
  • 文件夹windows
  • perl怎么读取文件
  • jquery 字符串以什么开头
  • unity 3d教程
  • 在Android EditText中实现日期时间选择器(DatePicker和TimePicker)
  • UNITY gameobject代码中setacvtive(false)与面板中直接去掉勾 效果不一样
  • jquery解析json对象
  • android开发教程视频 好少
  • 盐城市地税局稽查大队长
  • 山东省工会经费收支管理办法
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设