vue时间段选择器
vue时间段选择器实现的功能![在这里插入图片描述](https://img-blog.csdnimg.cn/20191031084355506.gif)代码心得实现的功能可以添加和取消时间段,需要把选中的时间段数组再转成适合人看的格式.代码没有整理和优化,但保证可用,还差画方框的程序需要调整<template><div class="byted-weektime"...
·
vue时间段选择器
实现的功能
可以添加和取消时间段,需要把选中的时间段数组再转成适合人看的格式.
2022年1月11日更新
基于echarts又搞了一版canvas的,兼容echarts4或5,通用性更好,可以点击我的博文列表查看。
代码
没有整理和优化,但保证可用,还差画方框的程序需要调整
<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原型上的,此代码里没有写,网上搜一下有很多,不然运行不了.
更多推荐
已为社区贡献2条内容
所有评论(0)