在工作中遇到老板要求实现时间段日期区间选择器,本来不想惯他毛病的,但是巧就巧咱弄出来了,下面就共享出来
演示图
注意下面的内容我是以在线引入Vue.js文件的形式开发的
html代码
<div class="weektimes" id="app">
<div class="byted-weektime" @mousedown="dian" @mousemove="yi" @mouseup="li">
<div class="calendar">
<table class="calendar-table" style="width:800px;">
<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="(item,index) in tableHeader" :key="index">{{item}}</td>
</tr>
</thead>
<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)"
@mousemove.prevent="handleMouseMove(i,0)" class="calendar-atom-time" :class="item.class"
v-for="(item,i) in rowUnit[0]" :key="i"></td>
</tr>
<tr>
<td>星期二</td>
<td @mousedown.prevent="handleMouseDown(i,1)" @mousemove.prevent="handleMouseMove(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>星期三</td>
<td @mousedown.prevent="handleMouseDown(i,2)" @mousemove.prevent="handleMouseMove(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>星期四</td>
<td @mousedown.prevent="handleMouseDown(i,3)" @mouseup.prevent="handleMouseUp(i,3)"
@mousemove.prevent="handleMouseMove(i,3)" class="calendar-atom-time" :class="item.class"
v-for="(item,i) in rowUnit[3]" :key="i"></td>
</tr>
<tr>
<td>星期五</td>
<td @mousedown.prevent="handleMouseDown(i,4)" @mouseup.prevent="handleMouseUp(i,4)"
@mousemove.prevent="handleMouseMove(i,4)" class="calendar-atom-time" :class="item.class"
v-for="(item,i) in rowUnit[4]" :key="i"></td>
</tr>
<tr>
<td>星期六</td>
<td @mousedown.prevent="handleMouseDown(i,5)" @mouseup.prevent="handleMouseUp(i,5)"
@mousemove.prevent="handleMouseMove(i,5)" class="calendar-atom-time" :class="item.class"
v-for="(item,i) in rowUnit[5]" :key="i"></td>
</tr>
<tr>
<td>星期日</td>
<td @mousedown.prevent="handleMouseDown(i,6)" @mouseup.prevent="handleMouseUp(i,6)"
@mousemove.prevent="handleMouseMove(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="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" :key="index" v-show="item.length">
<span>{{weekDate[index+1]}}:</span>
<strong>
<span>{{item}}</span>
</strong>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<!-- 鼠标的画框的效果 -->
<div id="container" v-bind:style="{backgroundColor:back,
height:h+'px',
width:w+'px',
position:'absolute',
left:left+'px',
top:top+'px',
opacity:0.2,
border:len+'px dashed #000',
zIndex:-1}"></div>
</div>
</div>
js代码
let app = new Vue({
//vue对象挂载到id='app'的元素上
el: "#app",
//data是vue数据属性, 定义的数据统一放到data中
data: {
formtitle : "添加项目",
isset: false, //已存在项目
project_state: false,
form: {
name: "",
budget: "300",
times: [],
apps: [],
yhmb: "AD_CONVERT_TYPE_MULTIPLE",
gender: "NONE",
age: ['NONE'],
ad_type: 'ALL'
},
data:[],
listQuery: {
'page': 1,
'limit': 20
},
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: [], //每一个单元格
timeContent: [], //选中的时间段原始数据
timeSection: [], //时间段,可以返回给后台的数据
timeStr: [], //时间段,前端显示的数据
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
},
py: "",
px: "",
back: "#31676f",
h: "",
w: "",
top: "",
left: "",
len: 0,
up: true, //未被按下
activeName: 'first',
},
created() {
this.init()
},
methods: {
sub() {
// timeContent: [], //选中的时间段原始数据
// timeSection: [], //时间段,可以返回给后台的数据
// timeStr: [], //时间段,前端显示的数据
},
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.up = false // 鼠标按下
this.downEvent = true; //按下时鼠标不在范围内则不算
this.beginDay = day;
this.beginTime = i;
},
dian(event) {
// console.log(event);
this.px = event.pageX; //获取x坐标
this.py = event.pageY;
},
yi(event) {
if (this.px == "" || this.py == "") {
return;
}
var px1 = this.px;
var px2 = this.py;
this.left = event.pageX;
this.top = event.pageY;
this.h = this.top - this.py;
this.w = this.left - this.px;
var hc = -this.h;
var wc = -this.w;
this.len = 1;
this.back = "#31676f";
if (this.h < 0 && this.w >= 0) {
this.h = hc;
this.left = px1;
} else if (this.h >= 0 && this.w < 0) {
this.w = wc;
this.top = px2;
} else if (this.h < 0 && this.w < 0) {
this.h = hc;
this.w = wc;
} else {
this.left = this.px;
this.top = this.py;
}
if (this.w < 0) {
this.w = 0 - this.w;
}
if (this.h < 0) {
this.h = 0 - this.h;
}
},
li() {
this.px = "";
this.py = "";
this.h = "";
this.w = "";
this.top = "";
this.left = "";
this.len = 0;
this.back = "";
},
handleMouseMove(i, day) {
if (!this.up) {
// this.up = true
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轴 终点
//当框选范围内所有块都是选中状态时,执行反选
//当点击事件是在table内才触发选取数据操作
//选时间段
//没选中的全都选上
for (let x = dayStart; x < dayEnd + 1; x++) {
for (let y = start; y < end + 1; y++) {
if (this.rowUnit[x][y].class == "ui-selected" || this.rowUnit[x][y].class == "ui-selected-move") {
this.rowUnit[x][y].class = "ui-selected-move";
} else {
this.rowUnit[x][y].class = "ui-selected-move-1";
}
}
}
}
},
handleMouseUp(i, day) {
this.up = true
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 || _this.rowUnit[x][y].class == "ui-selected-move-1") return true;
}
}
return false;
}
//当点击事件是在table内才触发选取数据操作
if (this.downEvent) {
//选时间段
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-move-1" || this.rowUnit[x][y].class == "ui-selected-move") {
this.rowUnit[x][y].class = "ui-selected";
let push = true
for (let k in this.timeContent[x].arr) {
let v = this.timeContent[x].arr[k]
if (v == this.rowUnit[x][y].timeData) {
push = false
}
}
if (push) {
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++) {
if (this.rowUnit[x][y].class == "ui-selected" || this.rowUnit[x][y].class == "ui-selected-move") {
this.rowUnit[x][y].class = null;
var c = this.rowUnit[x][y].timeData;
var kong = "";
for (let i = 0; i < this.timeContent[x].arr.length; i++) {
if (c == this.timeContent[x].arr[i]) {
kong = i;
}
}
let n = this.timeContent[x].arr[kong]
for (let k in this.timeContent[x].arr) {
let v = this.timeContent[x].arr[k]
if (v == n) {
this.timeContent[x].arr.splice(k, 1);
}
}
}
}
}
}
//过滤时间段,将临近的时间段合并
this.filterTime(dayStart, dayEnd);
}
this.downEvent = false;
},
filterTime(start, end) {
//选中的x,y坐标信息 x:0-47 y:0-6
// console.log(this.timeContent)
// console.log(this.timeSection)
// console.log(this.timeStr)
// console.log(this.rowUnit)
//排序,分割成
// console.log(start, end + 1)
for (let i = start; i < end + 1; i++) {
let arr1 = this.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);
});
this.timeStr[i] = this.timeToStr(arr2);
this.timeSection[i] = arr2;
}
// console.log(this.timeSection)
},
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
},
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;
},
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";
}
},
timeToStr(arr) {
//把数组转成方便人看到字符串
let str = "";
arr.forEach((arr, index) => {
let str1 = "";
if (index == 0) {
str1 = this.toStr(arr[0]) + "~" + this.toStr(arr[1]);
} else {
str1 = " , " + this.toStr(arr[0]) + "~" + this.toStr(arr[1]);
}
str += str1;
});
return str;
},
}
});
Css
<style scoped>
.byted-weektime .calendar {
-webkit-user-select: none;
position: relative;
display: inline-block;
}
#tableBody {
/* position: relative; */
}
/*.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;
}
.ui-selected-move {
background: rgba(64, 158, 255, 0.1);
}
.ui-selected-move-1 {
background: rgba(64, 158, 255, 0.1);
}
.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;
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>