1.0.2 • Published 2 years ago

vue3-time-quantum v1.0.2

Weekly downloads
-
License
ISC
Repository
-
Last release
2 years ago

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>

示例

image

源码

<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>
1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago