vue3-time-quantum
v1.0.2
Published
vue3时间颗粒度选择器
Downloads
9
Readme
vue3-time-quantum
vue3 实现时间颗粒度选择
Install via NPM/Yarn
npm install vue3-time-quantum
yarn add vue3-time-quantum
Example - basic
<template>
<select-time-quantum :timmer="timmer" @getTimmer="getTimmer"></select-time-quantum>
</template>
<script setup>
import SelectTimeQuantum from 'vue3-time-quantum'
const timmer = ref([{"arr":[]},{"arr":[]},{"arr":[]},{"arr":[]},{"arr":[]},{"arr":[]},{"arr":[]}])
function getTimmer(data) {
let da = JSON.parse(JSON.stringify(data))
let time = da.map(item => item.arr)
console.log(da)
console.log(time)
}
</style>
示例
源码
<template>
<div class='select-time-page' id="time-box">
<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>
<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="index in tableHeader">{{ index }}</td>
</tr>
</thead>
<tbody id="tableBody">
<tr>
<td>星期一</td>
<td @mousedown.prevent="handleMouseDown(i, 0)" :title="`星期一 ${timeTips[item.timeData]}`"
@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)" :title="`星期二 ${timeTips[item.timeData]}`"
@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)" :title="`星期三 ${timeTips[item.timeData]}`"
@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)" :title="`星期四 ${timeTips[item.timeData]}`"
@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)" :title="`星期五 ${timeTips[item.timeData]}`"
@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)" :title="`星期六 ${timeTips[item.timeData]}`"
@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)" :title="`星期日 ${timeTips[item.timeData]}`"
@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">
<a @click="clear" class="clear-btn">清空</a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script setup>
import $ from 'jquery'
import { ref, reactive, onMounted, defineProps, defineEmits } from 'vue'
const emit = defineEmits(["getTimmer"])
const props = defineProps({
timmer: Array
})
Array.prototype.remove = function (varElement) {
var numDeleteIndex = -1;
for (var i = 0; i < this.length; i++) {
// 严格比较,即类型与数值必须同时相等。
if (this[i] === varElement) {
this.splice(i, 1);
numDeleteIndex = i;
break;
}
}
return numDeleteIndex;
}
onMounted(async () => {
await init()
})
const tableHeader = ref(['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'])
const rowUnit = ref([])
const timeContent = ref([])
const timeSection = ref([])
const timeStr = ref([])
const downEvent = ref(false)
const beginDay = ref(0)
const beginTime = ref(0)
const kuangObj = reactive({
width: 0,
height: 0,
top: 0,
left: 0,
bottom: 0,
right: 0,
oldLeft: 0,
oldTop: 0,
flag: false
})
const timeTips = {
0: '00:00 - 00:30',
1: '00:30 - 01:00',
2: '01:00 - 01:30',
3: '01:30 - 02:00',
4: '02:00 - 02:30',
5: '02:30 - 03:00',
6: '03:00 - 03:30',
7: '03:30 - 04:00',
8: '04:00 - 04:30',
9: '04:30 - 05:00',
10: '05:00 - 05:30',
11: '05:30 - 06:00',
12: '06:00 - 06:30',
13: '06:30 - 07:00',
14: '07:00 - 07:30',
15: '07:30 - 08:00',
16: '08:00 - 08: 30',
17: '08:30 - 09:00',
18: '09:00 - 09:30',
19: '09:30 - 10:00',
20: '10:00 - 10:30',
21: '10:30 - 11:00',
22: '11:00 - 11:30',
23: '11:30 - 12:00',
24: '12:00 - 12:30',
25: '12:30 - 13:00',
26: '13:00 - 13:30',
27: '13:30 - 14:00',
28: '14:00 - 14:30',
29: '14:30 - 15:00',
30: '15:00 - 15:30',
31: '15:30 - 16:00',
32: '16:00 - 16:30',
33: '16:30 - 17:00',
34: '17:00 - 17:30',
35: '17:30 - 18:00',
36: '18:00 - 18:30',
37: '18:30 - 19:00',
38: '19:00 - 19:30',
39: '19:30 - 20:00',
40: '20:00 - 20:30',
41: '20:30 - 21:00',
42: '21:00 - 21:30',
43: '21:30 - 22:00',
44: '22:00 - 22:30',
45: '22:30 - 23:00',
46: '23:00 - 23:30',
47: '23:30 - 24:00'
}
function init() {
for (let i = 0; i < 7; i++) {
let arr = []
for (let j = 0; j < 48; j++) {
arr.push({ class: null, timeData: j })
}
rowUnit.value.push(arr)
timeContent.value.push({ arr: [] })
timeSection.value.push([])
timeStr.value.push('')
}
timeContent.value = props.timmer
viewData()
var oBox = document.getElementById("time-box");
var oDiv = document.getElementById("kuang");
// 鼠标按下,获取初始点
oBox.onmousedown = function (ev) {
ev = window.event || ev;
//1.获取按下的点
var x1 = ev.pageX - $("#time-box").offset().left;
var y1 = ev.pageY - $("#time-box").offset().top;
oBox.onmousemove = function (ev) {
ev = window.event || ev;
var x2 = ev.pageX - $("#time-box").offset().left;
var y2 = ev.pageY - $("#time-box").offset().top;
// 3.设置div的样式
oDiv.style.left = ((x2 > x1 ? x1 : x2) - 0) + "px";
oDiv.style.top = ((y2 > y1 ? y1 : y2) - 0) + "px";
oDiv.style.width = (Math.abs(x2 - x1)) + "px";
oDiv.style.height = (Math.abs(y2 - y1)) + "px";
}
oBox.onmouseup = function (ev) {
oBox.onmousemove = null;
oDiv.style.left = 0 + "px";
oDiv.style.top = 0 + "px";
oDiv.style.width = 0 + "px";
oDiv.style.height = 0 + "px";
}
return false; // 解除在划动过程中鼠标样式改变的BUG
}
}
function handleMouseDown(i, day) {
downEvent.value = true // 按下时鼠标不在范围内则不算
beginDay.value = day
beginTime.value = i
}
function handleMouseUp(i, day) {
// 当点击事件是在table内才触发选取数据操作
if (downEvent.value) {
// 选时间段
let begin = beginTime.value
let start = begin <= i ? begin : i // x轴 起点
let length = Math.abs(begin - i)
let end = start + length // x轴 终点
let dayStart = beginDay.value <= day ? beginDay.value : day // y轴 起点
let dayLength = Math.abs(beginDay.value - day)
let dayEnd = dayStart + dayLength // y轴 终点
// console.log('dayStart' + dayStart + "\\dayEnd" + dayEnd)
// 当框选范围内所有块都是选中状态时,执行反选
function isAdd() {
for (let x = dayStart; x < dayEnd + 1; x++) {
for (let y = start; y < end + 1; y++) {
if (rowUnit.value[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 (rowUnit.value[x][y].class == null) {
rowUnit.value[x][y].class = 'ui-selected'
timeContent.value[x].arr.push(rowUnit.value[x][y].timeData)
}
}
}
} else { //反选
for (let x = dayStart; x < dayEnd + 1; x++) {
for (let y = start; y < end + 1; y++) {
rowUnit.value[x][y].class = null
timeContent.value[x].arr.remove(rowUnit.value[x][y].timeData)
}
}
}
// 过滤时间段,将临近的时间段合并
filterTime(dayStart, dayEnd)
emit('getTimmer', timeContent.value)
}
downEvent.value = false
}
function 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(timeContent.value[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)
})
timeStr.value[i] = timeToStr(arr2)
timeSection.value[i] = arr2
}
}
// 回显数据
function viewData() {
for (let i = 0; i < timeContent.value.length; i++) {
if (timeContent.value[i].arr.length > 0) {
let temp = timeContent.value[i].arr;
for (let j = 0; j < temp.length; j++) {
for (let z = 0; z <= 48; z++) {
if (z == temp[j]) {
rowUnit.value[i][z].class = 'ui-selected';
break;
}
}
}
}
}
}
function clear() {
rowUnit.value.forEach((item) => {
item.forEach((item1) => {
item1.class = null
})
})
timeContent.value.forEach((item) => {
item.arr = []
})
timeSection.value.forEach((item) => {
// 赋值成空数组[]出问题
item.length = 0
})
// 遍历赋值成'',不管用
timeStr.value.length = 0
for (let i = 0; i < 7; i++) {
timeStr.value.push('')
}
}
</script>
<style lang='less' scoped>
.select-time-page {
position: relative;
.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
}
.calendar-table {
border-collapse: collapse;
border-radius: 4px
}
.calendar-table tr .calendar-atom-time:hover {
background: #ccc
}
.calendar-table tr .ui-selected {
background: #2F88FF
}
.calendar-table tr .ui-selected:hover {
background: #2F88FF
}
.calendar-table tr,
.calendar-table td,
.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;
}
.calendar-table tbody tr {
height: 30px
}
.calendar-table tbody tr td:first-child {
background: #F8F9FA
}
.calendar-table thead th,
.calendar .calendar-table thead td {
background: #F8F9FA
}
.calendar-table .td-table-tip {
line-height: 2.4em;
padding: 0 12px 0 19px;
background: #fff !important
}
.calendar-table .td-table-tip .clearfix {
height: 46px;
line-height: 46px
}
.calendar-table .td-table-tip .pull-left {
font-size: 14px;
color: #333333
}
.week-td {
width: 75px;
padding: 20px 0
}
#kuang {
position: absolute;
background-color: blue;
opacity: 0.3;
}
.clear-btn {
cursor: pointer;
color: #409eff;
}
}</style>