拖拽时间段选择器

<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>
						<td colspan="49" class="td-table-tip">
							<div class="clearfix flex header-tr">
								<span class="pull-left tip-text">请用鼠标点选时间段</span> <a @click="clear" class="pull-right"> 清空</a>
							</div>
						</td>
					</tr>
          <tr>
					  <th rowspan="2" class="week-td">星期/时间</th>
          </tr>
					<tr>
						<td colspan="2" v-for="index in tableHeader" :key="index">{
   
   {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 class="week">星期一</td>
						<td @mousedown.prevent="handleMouseDown(i,0)" @mouseup.prevent="handleMouseUp(i,0)" class="calendar-atom-time monday" :class="item.class" v-for="(item,i) in rowUnit[0]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期二</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]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期三</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]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期四</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]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期五</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]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期六</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]" :key="i"></td>
					</tr>
					<tr>
						<td class="week">星期日</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]" :key="i"></td>
					</tr>
					<tr>
						<td colspan="49" class="timeContent">
              <div>已选择时间段</div>
							<div v-for="(item,index) in timeStr" v-show="item.length" :key="index" class="selected-time">
								<span>{
   
   {weekDate[index+1]}}: </span>
								<span>{
   
   {item}}</span>
							</div>
						</td>
					</tr>
				</tbody>
			</table>
		</div>
	</div>
</template>

<script>
Array.prototype.remove = function(val){
    //获取当前元素的下标(索引)
    var index = this.indexOf(val);	//this是指使用这个方法的数组对象
    if(index != -1 ){	//值为-1则说明数组中不存在这个值
        this.splice(index,1);	//删除元素
    }
}

export default {
  name: 'timeSelect',
  data(){
  	return{
  		tableHeader:['0','1','2','3','4','5','6','7','8','9','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 lang="scss">
.byted-weektime .calendar{-webkit-user-select:none;position:relative;display:inline-block}
/*.byted-weektime .calendar .schedule{background:#4371FF;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:rgba(67, 113, 255, 0.75)}
.byted-weektime .calendar .calendar-table tr .ui-selected:hover{background:rgba(67, 113, 255, 0.75)}
.byted-weektime .calendar .calendar-table tr,.byted-weektime .calendar .calendar-table td,.byted-weektime .calendar .calendar-table th{border:1px solid #E5E6ED;font-size:12px;text-align:center;min-width:14px;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 .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: #9094A4;}
.byted-weektime .week-td{width:75px;padding:4px 0;color: #0C1733;}
.byted-weektime a{cursor:pointer;color:rgba(67, 113, 255, 0.75);font-size:14px;}
#kuang{position: absolute;background-color: blue;opacity: 0.3;}
.week {
  width: 78px;
  height: 30px;
  min-width: 78px !important;
}
.header-tr {
  height: 34px !important;
  justify-content: space-between;
  .pull-right {
    color: #4371FF;
  }
}

.timeContent {
  text-align: left !important;
  padding-left: 10px;
  font-size: 12px;
  .selected-time {
    color: #0C1733;
    font-weight: 300;
  }
}

.monday {
  border-top: 0px !important;
}
</style>

选自 https://blog.csdn.net/qq_34415621/article/details/102831130

猜你喜欢

转载自blog.csdn.net/dyx001007/article/details/130220509