最近手写了一个框选时间的组件,可以按半个小时为单位选择时间
代码部分
<template><div><div class="byted-schedule"><table :key="itemKey" class="byted-schedule-calendar-table"><thead><tr><th rowspan="8" class="byted-schedule-week-td">星期/事件</th><th colspan="24">00:00 - 12:00</th><th colspan="24">12:00 - 24:00</th></tr><tr><td v-for="index of 24" :key="index" colspan="2">{{ index - 1 }}</td></tr></thead><tbody @mouseleave="handelMouseLeave"><div v-show="is_show_mask" class="mask" :style="'width:' + mask_width + 'left:' + mask_left + 'height:' + mask_height + 'top:' + mask_top" /><tr v-for="(item, weekIndex) in week" :key="item"><td @mouseenter="handelMouseEnter">{{ item }}</td><tdv-for="timeIndex of timeLength":ref="`td${weekIndex * timeLength + timeIndex - 1}`":key="timeIndex":colspan="48 / timeLength":data-week="weekIndex":data-time="timeIndex":class="timeArray[weekIndex * timeLength + timeIndex - 1] === '1'? 'selected': ''"class="byted-schedule-calendar-atom-time"@mousedown="handelMouseDown(weekIndex, timeIndex - 1,$event)"@mousemove="handelMouseMove(weekIndex, timeIndex - 1,$event)"@mouseup="handelMouseUp(weekIndex, timeIndex - 1,$event)"/></tr><tr @mouseenter="handelMouseEnter"><td colspan="49"><div style="display: flex; justify-content: space-between"><span style="margin-left: 10px">已选择时间段</span><a:underline="false"style="margin-right: 10px;color: #1890FF;cursor:pointer"@click="clearAllTime">清空</a></div><div style="text-align: start; padding: 0 10px"><p v-for="(item, key) in timeObject" :key="key"><span v-if="item.length" style="margin-right: 10px">{{key}}</span><span v-if="item.length">{{ item.join("、") }}</span></p></div></td></tr></tbody></table></div></div></template><script>export default {name:'time-choice-range',props: {value: {type: String,default: ''},timeWidth: {type: Number,default: 7},timeLength: {type: Number,default: 48}},data() {return {is_show_mask: false,startWeekIndex: null,startTimeIndex: null,endWeekIndex: null,endTimeIndex: null,week: ['星期一','星期二','星期三','星期四','星期五','星期六','星期日'],cellStyle: {// color: 'red'},timeArray: [],itemKey: '',timeObject: {星期一: [],星期二: [],星期三: [],星期四: [],星期五: [],星期六: [],星期日: []},box_screen_left: 0, // 定位td的left位置box_screen_top: 0, // 定位td的top位置start_x: 0,start_y: 0,end_x: 0,end_y: 0}},created() {if (this.value) {this.timeArray = this.value.split('')for (var weekIndex = 0; weekIndex < this.timeWidth; weekIndex++) {this.handelClick(weekIndex)}} else {this.timeArray = []for (var i = 0; i < this.timeWidth * this.timeLength; i++) {this.timeArray[i] = '0'}}},computed: {mask_width() {return `${Math.abs(this.end_x - this.start_x)}px;`},mask_height() {return `${Math.abs(this.end_y - this.start_y)}px;`},mask_left() {return `${Math.min(this.start_x, this.end_x) - this.box_screen_left}px;`},mask_top() {return `${Math.min(this.start_y, this.end_y) - this.box_screen_top}px;`}},mounted() {window.addEventListener('scroll', this.handleScroll)},methods: {handleScroll() {const dom_box = document.querySelector('.byted-schedule-calendar-atom-time')this.box_screen_left = dom_box.getBoundingClientRect().left - 76this.box_screen_top = dom_box.getBoundingClientRect().top},handelClick(weekIndex, timeIndex) {var rowStartIndex = weekIndex * this.timeLengthvar i = 0var startAndEndTimeList = [] // 记录开始和结束时间while (i < this.timeLength) {if (this.timeArray[rowStartIndex + i] === '1') {var item = {startTime: null,endTime: null}item.startTime = i * (24 / this.timeLength)var obj = this.findEndTime(weekIndex, i)i = obj.indexitem.endTime = obj.endTimestartAndEndTimeList.push(item)}i++}var checkedTimeList = []for (let k = 0; k < startAndEndTimeList.length; k++) {var start = this.numToTime(startAndEndTimeList[k].startTime)var end = this.numToTime(startAndEndTimeList[k].endTime)var str = start + '~' + endcheckedTimeList.push(str)}this.timeObject[this.week[weekIndex]] = JSON.parse(JSON.stringify(checkedTimeList))},findEndTime(weekIndex, timeIndex) {var index = weekIndex * this.timeLength + timeIndexvar obj = {}obj.index = timeIndexif (this.timeArray[index] === '0') {obj.endTime = timeIndex * (24 / this.timeLength)return obj}// 如果选择了当天最后时段if (timeIndex === this.timeLength - 1 && this.timeArray[index] === '1') {obj.endTime = this.timeLength * (24 / this.timeLength)return obj}return this.findEndTime(weekIndex, timeIndex + 1)},numToTime(num) {var hour = parseInt(num)var minute = num % 1hour = hour < 10 ? '0' + hour : hour + ''minute = minute === 0 ? '00' : minute * 60 + ''return hour + ':' + minute},findStartAndEndTime(weekIndex, timeIndex) {var startXvar startYvar endXvar endYstartX =this.startWeekIndex < weekIndex ? this.startWeekIndex : weekIndexstartY =this.startTimeIndex < timeIndex ? this.startTimeIndex : timeIndexendX = this.startWeekIndex < weekIndex ? weekIndex : this.startWeekIndexendY = this.startTimeIndex < timeIndex ? timeIndex : this.startTimeIndexreturn {startX,startY,endX,endY}},handelMouseDown(weekIndex, timeIndex, event) {this.handleScroll()// 获取一下组件在视窗的位置this.startWeekIndex = weekIndexthis.startTimeIndex = timeIndex// 选择框this.is_show_mask = truethis.start_x = event.clientXthis.start_y = event.clientYthis.end_x = event.clientXthis.end_y = event.clientY},handelMouseMove(weekIndex, timeIndex, event) {this.endWeekIndex = weekIndexthis.endTimeIndex = timeIndexif (this.startWeekIndex !== null) {// event.path[0].style.background='#7594ef'const { startX, endX, startY, endY } = this.findStartAndEndTime(weekIndex,timeIndex)for (var i = startX; i <= endX; i++) {for (var j = startY; j <= endY; j++) {this.$refs[`td${i * this.timeLength + j}`][0].style.background ='#7594ef'}}}this.end_x = event.clientXthis.end_y = event.clientY},handelMouseLeave(event) {if (this.startWeekIndex !== null) {this.handelMouseUp(this.endWeekIndex, this.endTimeIndex)}},handelMouseEnter(event) {if (this.startWeekIndex !== null) {this.handelMouseUp(this.endWeekIndex, this.endTimeIndex)}},handelMouseUp(weekIndex, timeIndex) {if (this.startWeekIndex !== null) {const { startX, endX, startY, endY } = this.findStartAndEndTime(weekIndex,timeIndex)var value =this.timeArray[this.startWeekIndex * this.timeLength + this.startTimeIndex]for (var i = startX; i <= endX; i++) {for (var j = startY; j <= endY; j++) {this.timeArray[i * this.timeLength + j] = value === '1' ? '0' : '1'this.itemKey = Math.random()this.handelClick(i, j)}}}this.startWeekIndex = nullthis.startTimeIndex = nullthis.endWeekIndex = nullthis.endTimeIndex = nullthis.$emit('input', this.timeArray.join(''))this.is_show_mask = falsethis.resSetXY()},resSetXY() {this.start_x = 0this.start_y = 0this.end_x = 0this.end_y = 0},clearAllTime() {for (var i = 0; i < this.timeWidth * this.timeLength; i++) {this.timeArray[i] = '0'}this.timeObject = {星期一: [],星期二: [],星期三: [],星期四: [],星期五: [],星期六: [],星期日: []}this.$emit('input', '')}}}</script><style scoped src="../assets/index.css"></style>
css
.byted-schedule {user-select: none;}.byted-schedule table {border: 1px solid #ebebeb;border-collapse: collapse;table-layout: fixed;width: 100%;font-size: 12px;}.byted-schedule-calendar-table {border-collapse: separate;border-radius: 4px;}.byted-schedule-calendar-table tr td,.byted-schedule-calendar-table tr th {border-left: none;border-top: none;border-bottom: 1px solid;border-bottom-color: #ebebeb;border-right: 1px solid;border-right-color: #ebebeb;font-size: 14px;text-align: center;min-width: 11px;line-height: 1.8em;/* transition: background 200ms ease; */color: #333333;background: transparent;padding: 0;}.byted-schedule-week-td {width: 75px;padding: 20px 0;}.byted-schedule-calendar-table .selected {background: #1890ff !important;}.byted-schedule-calendar-atom-time:hover {background: #edf1fd;}tbody{position: relative;overflow: hidden;}.mask {position: absolute;background: red;opacity: 0.4;z-index: 999;}
npm
1、npm install time-choice-range
2、main.js:引入import time-choice-range from 'time-choice-range'
Vue.use(time-choice-range)
3. <time-choice-range></time-choice-range>