字節(jié)byte-week-picker(修改-反選bug解決)

<template>
    <div class="weektime" id="timecontainer">
        <div v-if="selectBoxDashed" class="select-box-dashed" ref="selectBoxDashed" @mousemove="handleMousemove"></div>
        <div class="weektime-main">
            <div class="weektime-hd">
                <div class="weektime-hd-title font-bold">星期 / 時間</div>
                <div class="weektime-hd-con">
                    <div class="weektime-hd-con-top">
                        <div class="weektime-date-range font-bold">00:00 - 12:00</div>
                        <div class="weektime-date-range font-bold">12:00 - 24:00</div>
                    </div>
                    <div class="weektime-hd-con-bottom">
                        <span class="weektime-date-cell" v-for="hour in 24" :key="hour">{{hour-1}}</span>
                    </div>
                </div>
            </div>
            <div class="weektime-bd" >
                <div class="week-body">
                    <div v-for="week in weekDays" :key="week" class="week-item">{{week}}</div>
                </div>
                <div class="time-body" @mousedown="handleMousedown" @mouseup="handleMouseup" @mousemove="handleMousemove">
                    <el-tooltip
                            v-for="(i,key) in weekTimes"
                            :key="key"
                            :data-index="key"
                            :content="tiptxt(key)"
                            :open-delay="800"
                            placement="top"
                            effect="light"
                    >
                        <div class="time-cell" :class="{'active':list[key]==='1'}"></div>
                    </el-tooltip>
                </div>
            </div>
        </div>
        <div class="weektime-help">
            <div class="weektime-help-tx">
                <div class="weektime-help-bd">
                    可移動鼠標選擇時間段
                </div>
                <div class="weektime-help-ft" @click="initList()">清空</div>
            </div>
            <div class="weektime-help-select">
                <p v-for="(week,key) in weekDays" :key="key" v-show="showTimeText[key]">
                    <span class="weektime-help-week-tx">{{week+":"}}</span>
                    <span>{{showTimeText[key]}}</span>
                </p>
            </div>
        </div>
    </div>
</template>

<script>
import Tooltip from 'element-ui/lib/tooltip.js'
import 'element-ui/lib/theme-chalk/tooltip.css';
import 'element-ui/packages/theme-chalk/src/common/transition.scss';

const DayTimes = 24 * 2;

export default {
    name: "byte-weektime-picker",
    components: {
        "el-tooltip": Tooltip
    },
    props: {
        value: String
    },
    watch: {
        value(n) {
          if (n.split('') === this.list.join('')) return;
            this.initList(n);
        }
    },
    data() {
        return {
            isMove: false,
            list: [],
            weekTimes: 7 * DayTimes,
            weekDays: ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'],
            timeTextList: [], //顯示的時間數(shù)組 ["00:00","00:30","01:00",...]
            startIndex: 0,
            axis: {},
            preViewIndex: [],
            showTimeText: [],
            selectBoxDashed: false,
            startX: null,
            startY: null,
            initx: null,
            scrollX:null,
            scrollY:null,
            inity: null
        }
    },
    methods: {
        /**
         * 鼠標停留時提示當前時間段
         */
        tiptxt(index) {
            let timeIndex = index % DayTimes;
            let weekIndex = ~~(index / DayTimes);
            return `${this.weekDays[weekIndex]} ${this.timeTextList[timeIndex]}~${this.timeTextList[timeIndex + 1]}`
        },
        /**
         * 初始化顯示的時間數(shù)組
         * @return {Array} ["00:00","00:30","01:00",...]
         */
        initTimeText() {
            let timeTextList = [], hours = [], minutes = ['00', '30'];
            for (let i = 0; i <= 24; i++) {
                i < 10 ? hours.push('0' + i) : hours.push(i.toString())
            }
            for (const hour of hours) {
                for (const minute of minutes) {
                    timeTextList.push(`${hour}:${minute}`)
                }
            }
            return timeTextList
        },
        handleMousedown(event) {
            this.isMove = true;
            this.startIndex = event.target.getAttribute('data-index');
            this.axis.startx = this.startIndex % DayTimes;
            this.axis.starty = ~~(this.startIndex / DayTimes);

            this.selectBoxDashed = true
            //  設(shè)置選框的初始位置
            this.startX = event.x + this.scrollX || event.clientX + this.scrollX
            this.startY = event.y + this.scrollY || event.clientY + this.scrollY
        },
        handleMouseup(event) {
            this.handleMousemove(event);
            this.resetMousemove()
            this.selectBoxDashed = false
        },
        handleMousemove(event) {
            if (this.selectBoxDashed) {
                //  根據(jù)鼠標移動于樟,設(shè)置選框的位置、寬高
                this.initx = event.x + this.scrollX || event.clientX + this.scrollX
                this.inity = event.y + this.scrollY || event.clientY + this.scrollY

                //  暫存選框的位置及寬高拇囊,用于將 select-item 選中
                this.left = Math.min(this.initx, this.startX)
                this.top = Math.min(this.inity, this.startY)
                this.width = Math.abs(this.initx - this.startX)
                this.height = Math.abs(this.inity - this.startY)

                this.$refs.selectBoxDashed.style.left = `${this.left}px`
                this.$refs.selectBoxDashed.style.top = `${this.top}px`
                this.$refs.selectBoxDashed.style.width = `${this.width}px`
                this.$refs.selectBoxDashed.style.height = `${this.height}px`
            }



            if (!this.isMove) return;
            let index = event.target.getAttribute('data-index');
            if (index !== null) {
              this.axis.endx = index % DayTimes;
              this.axis.endy = ~~(index / DayTimes);
              this.preViewIndex = this.getSelectIndex()
            }
        },
        resetMousemove() {
            if (!this.isMove) return;
            this.setSelectIndex(this.preViewIndex);
            this.isMove = false;
            this.axis = {};
            this.preViewIndex = [];
            this.selectBoxDashed = false
        },
        /**
         * 獲取拖動鼠標選擇的index數(shù)組
         */
        getSelectIndex() {
            let indexList = [],
                newAxis = {
                    startx: Math.min(this.axis.startx, this.axis.endx),
                    starty: Math.min(this.axis.starty, this.axis.endy),
                    endx: Math.max(this.axis.startx, this.axis.endx),
                    endy: Math.max(this.axis.starty, this.axis.endy)
                }
            for (let y = newAxis.starty; y <= newAxis.endy; y++) {
                for (let x = newAxis.startx; x <= newAxis.endx; x++) {
                    indexList.push(x + y * DayTimes)
                }
            }
            return indexList
        },
        /**
         * 設(shè)置選擇的時間段并賦給綁定的值
         * @param {Array} indexList 選擇的index數(shù)組
         */
        setSelectIndex(indexList) {
            if (!Array.isArray(indexList)) return;
            let listLength = indexList.length;
            let newData = this.list[this.startIndex] === '1' ? '0' : '1';
            for (let i = 0; i < listLength; i++) {
                this.list.splice(indexList[i], 1, newData);
            }

            this.$emit('input', this.list.join(''));
            this.showSelectTime(this.list);
        },
        /**
         * 展示選擇的時間段
         * @param {Array} list 已選擇的list數(shù)組
         */
        showSelectTime(list) {
            if (!Array.isArray(list)) return;
            let weeksSelect = [], listlength = list.length;
            this.showTimeText = [];
            if (listlength === 0) return;
            // 把 336長度的 list 分成 7 組迂曲,每組 48 個
            for (var i = 0; i < listlength; i += DayTimes) {
                weeksSelect.push(list.slice(i, i + DayTimes));
            }
            weeksSelect.forEach(item => {
                this.showTimeText.push(this.getTimeText(item))
            });
        },
        getTimeText(arrIndex) {
            if (!Array.isArray(arrIndex)) return "";

            /*方法一 matchAll 正則匹配 (速度較慢) */
            // let strIndex = arrIndex.join('');
            // let arrMatches = Array.from(strIndex.matchAll(/1+/g));
            // let timeText = "";
            // arrMatches.forEach(value => {
            //   timeText += this.timeTextList[value.index];
            //   timeText += '~' + this.timeTextList[value.index + value[0].length] + '、';
            // })
            /*方法一 end */

            /**方法二 循環(huán) (速度是方法一的十倍+)*/
            let timeLength = arrIndex.length,
                isSelect = false,
                timeText = "";
            arrIndex.forEach((value, index) => {
                if (value === '1') {
                    if (!isSelect) {
                        timeText += this.timeTextList[index]
                        isSelect = true;
                    }
                    if (index === timeLength - 1) timeText += '~' + this.timeTextList[index + 1] + '寥袭、';
                } else {
                    if (isSelect) {
                        timeText += '~' + this.timeTextList[index] + '路捧、'
                        isSelect = false;
                    }
                }
            })
            /*方法二 end */

            return timeText.slice(0, -1)
        },
        initList(value) {
            let reg = new RegExp("^[01]{" + this.weekTimes + "}$");
            if (value && reg.test(value)) {
                this.list = value.split('');
                this.showSelectTime(this.list);
                return
            }
            this.list = new Array(this.weekTimes).fill('0');
            this.$emit('input', this.list.join(''));
            this.showSelectTime(this.list);
        },
    },
    destroyed() {
        document.removeEventListener('mouseup', this.resetMousemove)
    },
    created() {
        this.timeTextList = this.initTimeText();
        document.addEventListener('mouseup', this.resetMousemove);
        this.initList(this.value);
    }
}
</script>

<style scoped>
    div,
    span,
    p {
        margin: 0;
        padding: 0;
        border: 0;
        font-weight: normal;
        vertical-align: baseline;
        -webkit-tap-highlight-color: transparent;
        -ms-tap-highlight-color: transparent;
        -moz-box-sizing: border-box;
        -webkit-box-sizing: border-box;
        box-sizing: border-box;
    }
    .weektime {
        width: 658px;
        font-size: 14px;
        line-height: 32px;
        color: #515a6e;
        user-select: none;
        margin: 100px auto;
        background: white;
        border-radius: 5px;
    }
    .weektime .weektime-main {
        border: 1px solid #dcdee2;
        position: relative;
        border-radius: 5px 5px 0 0;
        overflow: hidden;
    }
    .weektime .weektime-hd {
        display: flex;
        background: white;
    }
    .weektime .weektime-hd-title {
        display: flex;
        align-items: center;
        padding: 0 6px;
        width: 80px;
        height: 65px;
    }
    .font-bold {
        font-weight: bold;
        font-size: 12px;
        color: black;
    }
    .weektime .weektime-hd-con {
        flex: 1;
        display: flex;
        -webkit-box-orient: vertical;
        flex-direction: column;
    }
    .weektime .weektime-hd-con-top {
        display: flex;
        border-bottom: 1px solid #dcdee2;
    }
    .weektime .weektime-date-range {
        width: 288px;
        height: 42px;
        line-height: 42px;
        text-align: center;
        border-left: 1px solid #dcdee2;
    }
    .weektime .weektime-hd-con-bottom {
        display: flex;
    }
    .weektime .weektime-date-cell {
        width: 24px;
        height: 32px;
        line-height: 32px;
        text-align: center;
        border-left: 1px solid #dcdee2;
    }
    .weektime .weektime-bd {
        display: flex;
    }
    .weektime .week-body {
        width: 80px;
        flex-shrink: 0;
        background: white;
    }
    .weektime .week-item {
        border-top: 1px solid #dcdee2;
        text-align: center;
        height: 30px;
        line-height: 30px;
    }
    .weektime .time-body {
        width: 576px;
        height: 210px;
        display: flex;
        flex-wrap: wrap;
        align-items: flex-start;
        position: relative;
    }
    .weektime .time-cell {
        position: relative;
        width: 12px;
        height: 30px;
        border-left: 1px solid #efefef;
        border-top: 1px solid #efefef;
        overflow: hidden;
        transition: background 0.3s ease;
        outline-width: 0;
    }
    .time-cell:hover {
        background: #ebebeb;
    }
    .weektime .time-cell.active {
        background: #2d8cf0;
    }
    .weektime .time-cell::after {
        content: "";
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        background: transparent;
        opacity: 0.5;
        transition: background 888ms ease;
        z-index: 9000;
    }
    .weektime .pre-active::after {
        background: #113860;
    }
    .time-area {
        width: 576px;
        height: 210px;
        position: absolute;
        top: 0;
        left: 0;
        z-index: 100;
        background: transparent;
    }
    .weektime .weektime-help {
        width: 658px;
        border: 1px solid #dcdee2;
        border-top: none;
        padding: 5px 15px;
        border-radius: 0 0 5px 5px;
    }
    .weektime .weektime-help-tx {
        display: flex;
        align-items: center;
        justify-content: space-between;
    }

    .weektime .weektime-help-week-tx {
        color: #999;
    }

    .weektime .weektime-help-bd {
        display: flex;
        align-items: center;
        -webkit-box-pack: start;
        -ms-flex-pack: start;
        justify-content: flex-start;
        padding: 4px 0;
    }
    .weektime .weektime-help .color-box {
        width: 14px;
        height: 20px;
        background: #fff;
        border: 1px solid #dddddd;
        display: block;
        margin-right: 6px;
    }
    .weektime .weektime-help-bd .color-box.color-active {
        background: #2d8cf0;
    }
    .weektime .weektime-help .text-box {
        margin-right: 15px;
    }
    .weektime .weektime-help .weektime-help-ft {
        color: #2d8cf0;
        cursor: pointer;
    }
    .select-box-dashed{
        position: absolute;
        width: 0;
        height: 0;
        padding: 0px;
        margin: 0px;
        border: 1px dashed #0099ff;
        background-color: #c3d5ed;
        opacity: 0.5;
        filter: alpha(opacity=50);
        font-size: 0px;
        z-index: 99999;
    }
</style>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市传黄,隨后出現(xiàn)的幾起案子杰扫,更是在濱河造成了極大的恐慌,老刑警劉巖膘掰,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件章姓,死亡現(xiàn)場離奇詭異,居然都是意外死亡识埋,警方通過查閱死者的電腦和手機凡伊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來窒舟,“玉大人系忙,你說我怎么就攤上這事』莶颍” “怎么了银还?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洁墙。 經(jīng)常有香客問我蛹疯,道長,這世上最難降的妖魔是什么热监? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任弧械,我火速辦了婚禮剧蹂,結(jié)果婚禮上划咐,老公的妹妹穿的比我還像新娘舞肆。我一直安慰自己或衡,他們只是感情好速兔,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布雁竞。 她就那樣靜靜地躺著秒咐,像睡著了一般歉铝。 火紅的嫁衣襯著肌膚如雪盈简。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音柠贤,去河邊找鬼香浩。 笑死,一個胖子當著我的面吹牛臼勉,可吹牛的內(nèi)容都是我干的邻吭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼宴霸,長吁一口氣:“原來是場噩夢啊……” “哼囱晴!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瓢谢,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤畸写,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后氓扛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體枯芬,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年采郎,在試婚紗的時候發(fā)現(xiàn)自己被綠了千所。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡尉剩,死狀恐怖真慢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情理茎,我是刑警寧澤黑界,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站皂林,受9級特大地震影響朗鸠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜础倍,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一烛占、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沟启,春花似錦忆家、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至胳搞,卻和暖如春卸例,著一層夾襖步出監(jiān)牢的瞬間称杨,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工筷转, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留姑原,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓呜舒,卻偏偏與公主長得像锭汛,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子阴绢,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容