可以添加和取消时间段,需要把选中的时间段数组再转成适合人看的格式.
没有整理和优化,但保证可用,还差画方框的程序需要调整
<template> <div class="byted-weektime"> <div class="calendar"> <!-- <div class="schedule"></div> --> <!-- <div class="schedule" style="opacity: 0; display: none; left: 680px; top: 294px; width: 11px; height: 30px;"></div> --> <table class="calendar-table" style="width:610px"> <thead class="calendar-head"><tr> <th rowspan="6" class="week-td">星期/时间</th> <th colspan="24">00:00 - 12:00</th> <th colspan="24">12:00 - 24:00</th></tr> <tr> <td colspan="2" v-for="index in tableHeader">{{index}}</td> </tr> </thead> <!-- <tbody @mousemove.prevent.stop="kuangMove" @mouseleave.prevent.stop="kuangLeave" @mousedown.prevent.stop="kuangDown" @mouseup.prevent.stop="kuangUp"> --> <!-- 不画框,没bug --> <tbody id="tableBody"> <div id="kuang" :style="{width:kuangObj.width+'px',height:kuangObj.height+'px',top:kuangObj.top+'px',left:kuangObj.left+'px',bottom:kuangObj.bottom+'px',right:kuangObj.right+'px'}"></div> <tr> <td>星期一</td> <td @mousedown.prevent="handleMouseDown(i,0)" @mouseup.prevent="handleMouseUp(i,0)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[0]"></td> </tr> <tr> <td>星期二</td> <td @mousedown.prevent="handleMouseDown(i,1)" @mouseup.prevent="handleMouseUp(i,1)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[1]"></td> </tr> <tr> <td>星期三</td> <td @mousedown.prevent="handleMouseDown(i,2)" @mouseup.prevent="handleMouseUp(i,2)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[2]"></td> </tr> <tr> <td>星期四</td> <td @mousedown.prevent="handleMouseDown(i,3)" @mouseup.prevent="handleMouseUp(i,3)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[3]"></td> </tr> <tr> <td>星期五</td> <td @mousedown.prevent="handleMouseDown(i,4)" @mouseup.prevent="handleMouseUp(i,4)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[4]"></td> </tr> <tr> <td>星期六</td> <td @mousedown.prevent="handleMouseDown(i,5)" @mouseup.prevent="handleMouseUp(i,5)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[5]"></td> </tr> <tr> <td>星期日</td> <td @mousedown.prevent="handleMouseDown(i,6)" @mouseup.prevent="handleMouseUp(i,6)" class="calendar-atom-time" :class="item.class" v-for="(item,i) in rowUnit[6]"></td> </tr> <tr> <td colspan="49" class="td-table-tip"> <div class="clearfix"> <span class="pull-left tip-text">请用鼠标点选时间段</span> <a @click="clear" class="pull-right"> 清空</a> </div> </td> </tr> <tr> <td colspan="49" class="timeContent"> <div v-for="(item,index) in timeStr" v-show="item.length"> <span>{{weekDate[index+1]}}: </span> <strong><span>{{item}}</span></strong> </div> </td> </tr> </tbody> </table> </div> </div> </template> <script> export default { name: 'timeSelect', data(){ return{ tableHeader:['00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23'], weekDate:{'1':'星期一','2':'星期二','3':'星期三','4':'星期四','5':'星期五','6':'星期六','7':'星期日'}, rowUnit:[ //每一个单元格 //[{class:null,timeData:0},{class:null,timeData:1}...] 星期一 ], timeContent:[ //选中的时间段原始数据 //{arr:[]},{arr:[]}... ], timeSection:[ //时间段,可以返回给后端的数据 // [ // [0,1,2,3],[7,8] => [0,2],[3.5,4.5] // ], // [ // [4,5,6],[10] => [2,3.5],[5,5.5] // ] ], timeStr: [ //时间段,前端显示的数据 // '00:00~02:00 | 03:30~04:30', // '02:00~03:30 | 05:00~05:30', // '', // '', // '', // '', // '' ], beginDay:0, beginTime:0, downEvent:false, kuangObj:{ width:0, height:0, top:0, left:0, bottom:0, right:0, oldLeft:0, oldTop:0, flag:false } } }, created() { this.init() }, mounted(){ //画框程序 // let oBox = document.getElementById("tableBody") // let oDiv = document.getElementById("kuang") // //鼠标按下,获取初始点 // oBox.onmousedown = function (ev) { // var x1 = ev.clientX - oBox.offsetLeft; // var y1 = ev.clientY - oBox.offsetTop; // oBox.onmousemove = function (ev) { // var x2 = ev.clientX - oBox.offsetLeft; // var y2 = ev.clientY - oBox.offsetTop; // //3.设置div的样式 // oDiv.style.left = (x2 > x1 ? x1 : x2) +"px"; // oDiv.style.top = (y2 > y1 ? y1 : y2) +"px"; // oDiv.style.width = Math.abs(x2-x1)+"px"; // oDiv.style.height =Math.abs(y2-y1)+"px"; // } // return false; //解除在划动过程中鼠标样式改变的BUG // } // //在鼠标抬起后终止onmousemove事件 // document.onmouseup = function () { // oBox.onmousemove = null; // oDiv.style.left = 0 +"px"; // oDiv.style.top = 0 +"px"; // oDiv.style.width = 0+"px"; // oDiv.style.height =0+"px"; // } }, methods:{ init(){ for (let i = 0; i < 7; i++) { let arr = [] for (let j = 0; j < 48; j++) { arr.push({class:null,timeData:j}) } this.rowUnit.push(arr) this.timeContent.push({arr:[]}) this.timeSection.push([]) this.timeStr.push('') } }, handleMouseDown(i,day){ this.downEvent = true //按下时鼠标不在范围内则不算 this.beginDay = day this.beginTime = i }, handleMouseUp(i,day){ //当点击事件是在table内才触发选取数据操作 if (this.downEvent) { //选时间段 let _this = this let begin = this.beginTime let start = begin <= i ? begin : i //x轴 起点 let length = Math.abs(begin - i) let end = start + length //x轴 终点 let dayStart = this.beginDay <= day ? this.beginDay : day //y轴 起点 let dayLength = Math.abs(this.beginDay - day) let dayEnd = dayStart + dayLength //y轴 终点 //当框选范围内所有块都是选中状态时,执行反选 function isAdd() { for (let x = dayStart; x < dayEnd+1; x++) { for (let y = start; y < end+1; y++) { if(_this.rowUnit[x][y].class == null) return true } } return false } if (isAdd()) { //没选中的全都选上 for (let x = dayStart; x < dayEnd+1; x++) { for (let y = start; y < end+1; y++) { if(this.rowUnit[x][y].class == null) { this.rowUnit[x][y].class = 'ui-selected' this.timeContent[x].arr.push(this.rowUnit[x][y].timeData) } } } }else{ //反选 for (let x = dayStart; x < dayEnd+1; x++) { for (let y = start; y < end+1; y++) { this.rowUnit[x][y].class = null this.timeContent[x].arr.remove(this.rowUnit[x][y].timeData) } } } //过滤时间段,将临近的时间段合并 this.filterTime(dayStart,dayEnd) } this.downEvent = false }, filterTime(start,end) { //选中的x,y坐标信息 x:0-47 y:0-6 function sortCut(arr) { //提取连续的数字 var result = [] arr.forEach(function (v, i) { var temp = result[result.length - 1]; if (!i) { result.push([v]); } else if (v % 1 === 0 && v - temp[temp.length - 1] == 1) { temp.push(v) } else { result.push([v]) } }); return result } function toStr(num) { if (Number.isInteger(num)) { let str = num<10 ? ('0'+num) : num.toString() return str+':00' }else{ let str =Math.floor(num)<10 ? ('0'+Math.floor(num)) : Math.floor(num).toString() return str+':30' } } function timeToStr(arr) { //把数组转成方便人看到字符串 let str = '' arr.forEach((arr,index)=>{ let str1 = '' if (index == 0) { str1 = toStr(arr[0]) + '~' + toStr(arr[1]) }else{ str1 = ' , ' + toStr(arr[0]) + '~' + toStr(arr[1]) } str += str1 }) return str } //排序,分割成 for (let i = start; i < end+1; i++) { let arr1 = sortCut(this.timeContent[i].arr.sort((a, b) => a - b)) let arr2 = [] arr1.forEach((arr)=>{ //转成带小数点的时间段,以及供前端显示的字符串 let arr3 = [] arr3.push(arr[0]/2) arr3.push(arr[arr.length-1]/2+0.5) arr2.push(arr3) }) //console.log(arr2) this.timeStr[i] = timeToStr(arr2) this.timeSection[i] = arr2 } }, clear(){ this.rowUnit.forEach((item)=>{ item.forEach((item1)=>{ item1.class=null }) }) this.timeContent.forEach((item)=>{ item.arr = [] }) this.timeSection.forEach((item)=>{ //赋值成空数组[]出问题 item.length = 0 }) //遍历赋值成'',不管用 this.timeStr.length = 0 for (let i = 0; i < 7; i++) { this.timeStr.push('') } //this.initState = true }, //画框操作 kuangMove(){ if(!this.kuangObj.flag) return if (this.downEvent) { let x1 = this.kuangObj.oldLeft let y1 = this.kuangObj.oldTop let x2 = event.layerX let y2 = event.layerY this.kuangObj.left = (x2 > x1 ? x1 : x2) this.kuangObj.top = (y2 > y1 ? y1 : y2) this.kuangObj.width = Math.abs(x2-x1) this.kuangObj.height =Math.abs(y2-y1) } }, kuangDown(){ this.kuangObj.flag = true this.kuangObj.oldLeft = event.layerX this.kuangObj.oldTop = event.layerY }, kuangUp(){ this.kuangObj.flag = false this.clearDragData() }, kuangLeave(){ this.kuangObj.flag = false this.clearDragData() }, clearDragData(){ for(let prop in this.kuangObj){ this.kuangObj[prop] = 0 } } } } planTimeIntervals: [ { "planTimes": [ { "beginTime": 0, "endTime": 0 } ], "week": 0 } ] </script> <style scoped> .byted-weektime .calendar{-webkit-user-select:none;position:relative;display:inline-block} /*.byted-weektime .calendar .schedule{background:#2F88FF;width:0;height:0;position:fixed;display:none;top:0;left:0;pointer-events:none;-webkit-transition:all 400ms ease;-moz-transition:all 400ms ease;-ms-transition:all 400ms ease;transition:all 400ms ease}*/ .byted-weektime .calendar .calendar-table{border-collapse:collapse;border-radius:4px} .byted-weektime .calendar .calendar-table tr .calendar-atom-time:hover{background:#ccc} .byted-weektime .calendar .calendar-table tr .ui-selected{background:#2F88FF} .byted-weektime .calendar .calendar-table tr .ui-selected:hover{background:#2F88FF} .byted-weektime .calendar .calendar-table tr,.byted-weektime .calendar .calendar-table td,.byted-weektime .calendar .calendar-table th{border:1px solid #ccc;font-size:12px;text-align:center;min-width:11px;line-height:1.8em;-webkit-transition:background 200ms ease;-moz-transition:background 200ms ease;-ms-transition:background 200ms ease;transition:background 200ms ease} .byted-weektime .calendar .calendar-table tbody tr{height:30px} .byted-weektime .calendar .calendar-table tbody tr td:first-child{background:#F8F9FA} .byted-weektime .calendar .calendar-table thead th,.byted-weektime .calendar .calendar-table thead td{background:#F8F9FA} .byted-weektime .calendar .calendar-table .td-table-tip{line-height:2.4em;padding:0 12px 0 19px;background:#fff !important} .byted-weektime .calendar .calendar-table .td-table-tip .clearfix{height:46px;line-height:46px} .byted-weektime .calendar .calendar-table .td-table-tip .pull-left{font-size:14px;color:#333333} .byted-weektime .week-td{width:75px;padding:20px 0} .byted-weektime a{cursor:pointer;color:#2F88FF;font-size:14px} #kuang{position: absolute;background-color: blue;opacity: 0.3;} </style>样式是仿头条的 通过记录鼠标down和up事件单元格所在的坐标信息去处理数据与添加样式,实现起来要比计算宽高简单多了,而且不会因为组件放的位置不同出现bug. vue是数据驱动的,开发程序时一定要想好实现原理和数据结构,围绕数据结构去开发其他的程序,会少走很多弯路,代码写的比较烂,凑合看吧.
!!!温馨提示: 203行的remove方法是加在Array原型上的,此代码里没有写,网上搜一下有很多,不然运行不了.