最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue可ctrl,shift多選,可添加標(biāo)記日歷組件詳細(xì)

 更新時(shí)間:2022年09月26日 08:33:57   作者:江渚清沨  
這篇文章主要介紹了vue可ctrl,shift多選,可添加標(biāo)記日歷組件詳細(xì),文章通過圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下

需要寫一個(gè)日歷組件有以下功能,element無法滿足,自己造一個(gè)

只顯示當(dāng)前月日期,前后月日期不顯示也不可選擇;周六、周日顏色與工作日區(qū)分日期可以打標(biāo)記(左上角標(biāo)記)可ctrl+shift+鼠標(biāo)左鍵多選

一、 按照 "日", "一", "二", "三", "四", "五", "六" 把一個(gè)月的日期排列

頁面:

<template>
    <div class="calendar">
        <div class="calendar_header">{{currentMonth}}月</div>
        <table cellspacing="0" cellpadding="0" class="calendar_table">
            <thead>
                <th v-for="day in WEEK_DAYS" :key="day" :class="['thead_th',day=='六'||day=='日'?'thead_th_red':'']">
                    {{day}}</th>
            </thead>
            <tbody>
                <tr v-for="(row,index) in rows" :key="index">
                    <td v-for="(cell,key) in row" :key="key" class="td" @click="handlePickDay(cell)">
                        <div :class="getCellClass(cell,key)">
                            <div v-if="cell.type=='current'" class="triangle" :style="getCelltriangleStyle(cell)"></div>
                            <span class="cell_text">{{cell.text==0?'':cell.text}}</span>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

組件定義props、emits

const props = defineProps({
    markList: {//標(biāo)記
        type: Array<any>,
        default: (): any[] => {
            return [];
        },
    },
    month: {
        type: Date,
        required: true,
    },
    disabled: {
        type: Boolean,
        default: false,
    },
    disableBefore: {//禁用今天之前的日期
        type: Boolean,
        default: true,
    },
});
const emits = defineEmits(['change']);

當(dāng)前月的日期數(shù)組:

type CalendarDateCellType = 'next' | 'prev' | 'current'
type CalendarDateCell = {
    text: number,
    type: CalendarDateCellType
}
const WEEK_DAYS = ref(["日", "一", "二", "三", "四", "五", "六"]);
const currentMonth = computed(() => {
    return moment(props.month).format('M');
})
onMounted(() => {
    onKeyEvent();
})
const rows = computed(() => {
    let days: CalendarDateCell[] = []
    const firstDay = moment(props.month).startOf("month").date();
    // const endDay = moment(props.month).endOf('month').date();//當(dāng)前月的最后一天
    const firstDayOfWeek = moment(props.month).startOf("month").day();
    // const daysInMonth = moment(props.month).daysInMonth();//當(dāng)前月的天數(shù)
 
    const prevMonthDays: CalendarDateCell[] = getPrevMonthLastDays(
        firstDay,
        firstDayOfWeek - firstDay
    ).map((day) => ({
        text: 0,//上月補(bǔ)0
        type: 'prev',
    }))
    const currentMonthDays: CalendarDateCell[] = getMonthDays(moment(props.month).daysInMonth()).map(
        (day) => ({
            text: day,
            type: 'current',
        })
    )
    days = [...prevMonthDays, ...currentMonthDays]
    const remaining = 7 - (days.length % 7 || 7)
    const nextMonthDays: CalendarDateCell[] = rangeArr(remaining).map(
        (_, index) => ({
            text: 0,//下月補(bǔ)0
            type: 'next',
        })
    )
    days = days.concat(nextMonthDays)
    // console.log(currentMonth.value, firstDay, endDay, moment(props.month).startOf("month").day());
    return toNestedArr(days)
})

二、單元格樣式處理

  • 禁用
  • 選中
  • 周六、周日紅色字體
const getCellClass = (cell: CalendarDateCell, key: number) => {
    let date = getCellDate(cell);
    if (props.disableBefore && date.getTime() < new Date().getTime()) {
        return ['cell', 'cell_disabled'];//禁用
    }
    let classes: string[] = ['cell', 'cell_enabled'];
    if (key == 0 || key == 6) {//周六、周日
        classes.push('cell_red');
    }
    let index = selectList.value.indexOf(moment(date).format('YYYY-MM-DD'));
    if (index != -1) {
        classes.push('cell_active');//選中
    }
    return classes;
}

左上角三角形標(biāo)記

.triangle {
            position: absolute;
            left: 0;
            top: 0;
            width: 0;
            height: 0;
            // border-top: 30px solid #e6e911;
            border-right: 30px solid transparent;
        }
const getCelltriangleStyle = (cell: CalendarDateCell) => {
    let date = getCellDate(cell);
    let day = props.markList.find(item => item.date == moment(date).format('YYYY-MM-DD'));
    return day ? {
        borderTop: '30px solid #e6e911',
    } : {};
}

三、單機(jī)、按住ctrl點(diǎn)擊、按住shift點(diǎn)擊事件處理

1.記錄鍵盤按下ctrl、shift事件

const isCtrl = ref(false)
const isShift = ref(false)
const onKeyEvent = () => {
    window.addEventListener('keydown', e => {
        e.preventDefault();//取消默認(rèn)事件
        let e1 = e || window.event
        switch (e1.keyCode) {
            case 16:
                isShift.value = true;
                break;
            case 17:
                isCtrl.value = true;
                break;
        }
    })
    window.addEventListener('keyup', e => {
        e.preventDefault();
        let e1 = e || window.event
        switch (e1.keyCode) {
            case 16:
                isShift.value = false;
                break;
            case 17:
                isCtrl.value = false;
                break;
        }
    })
}

2.點(diǎn)擊事件處理

const selectList = ref<any[]>([]);//已選擇的
const shiftNum = ref(0);//shift復(fù)制的起始位置
const lastSelect = ref<any[]>([]);//按住shift倒數(shù)第二次復(fù)制的
//遵循excel點(diǎn)擊、ctrl、shift組合操作規(guī)范
const handlePickDay = (cell: CalendarDateCell) => {
    let date = getCellDate(cell);
    if (cell.type != 'current') {
        return;
    }
    if (props.disableBefore && date.getTime() < new Date().getTime()) {
        return
    }
    // console.log(isCtrl.value, isShift.value);
    let dateStr = moment(date).format('YYYY-MM-DD');
    let currentSelect: string[] = [];
    //按住ctrl
    if (isCtrl.value) {
        if (selectList.value.includes(dateStr)) {
            selectList.value.splice(selectList.value.indexOf(dateStr), 1);
        } else {
            selectList.value.push(dateStr);
        }
        lastSelect.value = [];
    } else if (isShift.value) {//按住shift
        if (shiftNum.value == 0) {//無上次點(diǎn)擊
            shiftNum.value = cell.text;
            if (selectList.value.includes(dateStr)) {
                selectList.value.splice(selectList.value.indexOf(dateStr), 1);
            } else {
                selectList.value.push(dateStr);
            }
        } else {
            if (shiftNum.value < cell.text) {
                currentSelect = getDatesInRange(shiftNum.value, cell.text);
            } else if (shiftNum.value > cell.text) {
                currentSelect = getDatesInRange(cell.text, shiftNum.value);
            } else {
                currentSelect = [dateStr];
            }
            selectList.value = selectList.value.filter(item => !lastSelect.value.includes(item));//移除上次按shift復(fù)制的
            selectList.value = selectList.value.concat(currentSelect);//添加本次按shift復(fù)制的
            lastSelect.value = currentSelect;
        }
    } else {
        selectList.value = [dateStr];
    }
    if (!isShift.value) {
        shiftNum.value = cell.text;
    }
    selectList.value = [...new Set(selectList.value)].sort();//去重、排序
    console.log(shiftNum.value, selectList.value);
    emits('change', selectList.value);
}

3.遵循excel點(diǎn)擊的操作方式:

  • 未按ctrl、shift點(diǎn)擊=>只選擇當(dāng)前點(diǎn)擊的;
  • 按ctrl點(diǎn)擊=>未選中則選中,已選中則取消選中;
  • 按住shift點(diǎn)擊=>記錄shift按下時(shí)點(diǎn)擊位置-->再次點(diǎn)擊時(shí)把期間內(nèi)的選中,并移除倒數(shù)第二次的選中(否則都會選中,并在按下ctrl時(shí)釋放上次選中)

四、組件代碼:

<template>
    <div class="calendar">
        <div class="calendar_header">{{currentMonth}}月</div>
        <table cellspacing="0" cellpadding="0" class="calendar_table">
            <thead>
                <th v-for="day in WEEK_DAYS" :key="day" :class="['thead_th',day=='六'||day=='日'?'thead_th_red':'']">
                    {{day}}</th>
            </thead>
            <tbody>
                <tr v-for="(row,index) in rows" :key="index">
                    <td v-for="(cell,key) in row" :key="key" class="td" @click="handlePickDay(cell)">
                        <div :class="getCellClass(cell,key)">
                            <div v-if="cell.type=='current'" class="triangle" :style="getCelltriangleStyle(cell)"></div>
                            <span class="cell_text">{{cell.text==0?'':cell.text}}</span>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from "vue";
import moment from "moment";
const props = defineProps({
    markList: {//標(biāo)記
        type: Array<any>,
        default: (): any[] => {
            return [];
        },
    },
    month: {
        type: Date,
        required: true,
    },
    disabled: {
        type: Boolean,
        default: false,
    },
    disableBefore: {//禁用今天之前的日期
        type: Boolean,
        default: true,
    },
});
const emits = defineEmits(['change']);
 
type CalendarDateCellType = 'next' | 'prev' | 'current'
type CalendarDateCell = {
    text: number,
    type: CalendarDateCellType
}
const WEEK_DAYS = ref(["日", "一", "二", "三", "四", "五", "六"]);
const currentMonth = computed(() => {
    return moment(props.month).format('M');
})
onMounted(() => {
    onKeyEvent();
})
 
const rows = computed(() => {
    let days: CalendarDateCell[] = []
    const firstDay = moment(props.month).startOf("month").date();
    // const endDay = moment(props.month).endOf('month').date();//當(dāng)前月的最后一天
    const firstDayOfWeek = moment(props.month).startOf("month").day();
    // const daysInMonth = moment(props.month).daysInMonth();//當(dāng)前月的天數(shù)
 
    const prevMonthDays: CalendarDateCell[] = getPrevMonthLastDays(
        firstDay,
        firstDayOfWeek - firstDay
    ).map((day) => ({
        text: 0,//上月補(bǔ)0
        type: 'prev',
    }))
    const currentMonthDays: CalendarDateCell[] = getMonthDays(moment(props.month).daysInMonth()).map(
        (day) => ({
            text: day,
            type: 'current',
        })
    )
    days = [...prevMonthDays, ...currentMonthDays]
    const remaining = 7 - (days.length % 7 || 7)
    const nextMonthDays: CalendarDateCell[] = rangeArr(remaining).map(
        (_, index) => ({
            text: 0,//下月補(bǔ)0
            type: 'next',
        })
    )
    days = days.concat(nextMonthDays)
    // console.log(currentMonth.value, firstDay, endDay, moment(props.month).startOf("month").day());
    return toNestedArr(days)
})
 
const rangeArr = (n: number) => {
    return Array.from(Array.from({ length: n }).keys())
}
 
const toNestedArr = (days: CalendarDateCell[]) =>
    rangeArr(days.length / 7).map((index) => {
        const start = index * 7
        return days.slice(start, start + 7)
    });
const getPrevMonthLastDays = (lastDay: number, count: number) => {
    return rangeArr(count).map((_, index) => lastDay - (count - index - 1))
}
 
const getMonthDays = (days: number) => {
    return rangeArr(days).map((_, index) => index + 1)
}
/**
 * 獲取范圍期間所有日期
 * @ return array['YYYY-MM-DD']
 */
const getDatesInRange = (start: number, end: number): string[] => {
    let list = [];
    for (let i = start; i <= end; i++) {
        let dateStr = moment(getCellDate({ text: i, type: 'current' })).format('YYYY-MM-DD');
        list.push(dateStr);
    }
    return list;
}
const isCtrl = ref(false)
const isShift = ref(false)
const onKeyEvent = () => {
    window.addEventListener('keydown', e => {
        e.preventDefault();//取消默認(rèn)事件
        let e1 = e || window.event
        switch (e1.keyCode) {
            case 16:
                isShift.value = true;
                break;
            case 17:
                isCtrl.value = true;
                break;
        }
    })
    window.addEventListener('keyup', e => {
        e.preventDefault();
        let e1 = e || window.event
        switch (e1.keyCode) {
            case 16:
                isShift.value = false;
                break;
            case 17:
                isCtrl.value = false;
                break;
        }
    })
}
const getCellClass = (cell: CalendarDateCell, key: number) => {
    let date = getCellDate(cell);
    if (props.disableBefore && date.getTime() < new Date().getTime()) {
        return ['cell', 'cell_disabled'];//禁用
    }
    let classes: string[] = ['cell', 'cell_enabled'];
    if (key == 0 || key == 6) {//周六、周日
        classes.push('cell_red');
    }
    let index = selectList.value.indexOf(moment(date).format('YYYY-MM-DD'));
    if (index != -1) {
        classes.push('cell_active');//選中
    }
    return classes;
}
const getCelltriangleStyle = (cell: CalendarDateCell) => {
    let date = getCellDate(cell);
    let day = props.markList.find(item => item.date == moment(date).format('YYYY-MM-DD'));
    return day ? {
        borderTop: '30px solid #e6e911',
    } : {};
}
const getCellDate = (cell: CalendarDateCell) => new Date(props.month.getFullYear(), props.month.getMonth(), cell.text)
 
const selectList = ref<any[]>([]);//已選擇的
const shiftNum = ref(0);//shift復(fù)制的起始位置
const lastSelect = ref<any[]>([]);//按住shift倒數(shù)第二次復(fù)制的
//遵循excel點(diǎn)擊、ctrl、shift組合操作規(guī)范
const handlePickDay = (cell: CalendarDateCell) => {
    let date = getCellDate(cell);
    if (cell.type != 'current') {
        return;
    }
    if (props.disableBefore && date.getTime() < new Date().getTime()) {
        return
    }
    // console.log(isCtrl.value, isShift.value);
    let dateStr = moment(date).format('YYYY-MM-DD');
    let currentSelect: string[] = [];
    //按住ctrl
    if (isCtrl.value) {
        if (selectList.value.includes(dateStr)) {
            selectList.value.splice(selectList.value.indexOf(dateStr), 1);
        } else {
            selectList.value.push(dateStr);
        }
        lastSelect.value = [];
    } else if (isShift.value) {//按住shift
        if (shiftNum.value == 0) {//無上次點(diǎn)擊
            shiftNum.value = cell.text;
            if (selectList.value.includes(dateStr)) {
                selectList.value.splice(selectList.value.indexOf(dateStr), 1);
            } else {
                selectList.value.push(dateStr);
            }
        } else {
            if (shiftNum.value < cell.text) {
                currentSelect = getDatesInRange(shiftNum.value, cell.text);
            } else if (shiftNum.value > cell.text) {
                currentSelect = getDatesInRange(cell.text, shiftNum.value);
            } else {
                currentSelect = [dateStr];
            }
            selectList.value = selectList.value.filter(item => !lastSelect.value.includes(item));//移除上次按shift復(fù)制的
            selectList.value = selectList.value.concat(currentSelect);//添加本次按shift復(fù)制的
            lastSelect.value = currentSelect;
        }
    } else {
        selectList.value = [dateStr];
    }
    if (!isShift.value) {
        shiftNum.value = cell.text;
    }
    selectList.value = [...new Set(selectList.value)].sort();//去重、排序
    console.log(shiftNum.value, selectList.value);
    emits('change', selectList.value);
}
</script>
<style lang="scss" scoped>
.calendar {
    width: 100%;
    padding: 12px 20px 35px;
 
    &_header {
        display: flex;
        justify-content: center;
        border: 1px solid var(--el-border-color-lighter);
        padding: 12px 20px;
    }
 
    &_table {
        width: 100%;
 
        .thead_th {
            padding: 12px 0;
            color: var(--el-text-color-regular);
            font-weight: 400;
 
            &_red {
                color: red;
            }
        }
    }
 
    .td {
        border: 1px solid var(--el-border-color-lighter);
        -moz-user-select: none;
        /*火狐*/
        -webkit-user-select: none;
        /*webkit瀏覽器*/
        -ms-user-select: none;
        /*IE10*/
        -khtml-user-select: none;
        /*早期瀏覽器*/
        user-select: none;
    }
 
 
    .cell {
        // background-color: #409eff;
        position: relative;
        text-align: center;
        min-height: 50px;
        display: flex;
        justify-content: center;
 
        &_enabled {
            cursor: pointer;
            color: #373737
        }
 
        &_disabled {
            cursor: not-allowed;
            color: #9b9da1;
        }
 
        &_red {
            color: red;
        }
 
        &_active {
            background-color: #409eff;
        }
 
        .triangle {
            position: absolute;
            left: 0;
            top: 0;
            width: 0;
            height: 0;
            // border-top: 30px solid #e6e911;
            border-right: 30px solid transparent;
        }
 
        &_text {
            margin: auto;
        }
    }
 
}
</style>

使用:

<Calendar :month="month" :markList="list" @change="onChange"></Calendar>

到此這篇關(guān)于vue可ctrl,shift多選,可添加標(biāo)記的日歷組件的文章就介紹到這了,更多相關(guān)vue ctrl shift內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • element-ui封裝一個(gè)Table模板組件的示例

    element-ui封裝一個(gè)Table模板組件的示例

    這篇文章主要介紹了element-ui封裝一個(gè)Table模板組件的示例,幫助大家更好的理解和學(xué)習(xí)vue框架的使用,感興趣的朋友可以了解下
    2021-01-01
  • 淺談vue.watch的觸發(fā)條件是什么

    淺談vue.watch的觸發(fā)條件是什么

    這篇文章主要介紹了淺談vue.watch的觸發(fā)條件是什么?具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 一個(gè)基于vue3+ts+vite項(xiàng)目搭建初探

    一個(gè)基于vue3+ts+vite項(xiàng)目搭建初探

    當(dāng)市面上主流的組件庫不能滿足我們業(yè)務(wù)需求的時(shí)候,那么我們就有必要開發(fā)一套屬于自己團(tuán)隊(duì)的組件庫,下面這篇文章主要給大家介紹了一個(gè)基于vue3+ts+vite項(xiàng)目搭建的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • Element中el-table動態(tài)合并單元格(span-method方法)

    Element中el-table動態(tài)合并單元格(span-method方法)

    本文主要介紹了Element中el-table動態(tài)合并單元格(span-method方法),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Vue.js特性Scoped Slots的淺析

    Vue.js特性Scoped Slots的淺析

    這篇文章主要介紹了Vue.js特性Scoped Slots的淺析,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-02-02
  • 詳解Vue的watch中的immediate與watch是什么意思

    詳解Vue的watch中的immediate與watch是什么意思

    這篇文章主要介紹了詳解Vue的watch中的immediate與watch是什么意思,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • 復(fù)刻畫龍產(chǎn)品vue實(shí)現(xiàn)新春氣泡兔

    復(fù)刻畫龍產(chǎn)品vue實(shí)現(xiàn)新春氣泡兔

    這篇文章主要為大家介紹了復(fù)刻畫龍產(chǎn)品之使用vue實(shí)現(xiàn)新春氣泡兔示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • vue-router-link選擇樣式設(shè)置方式

    vue-router-link選擇樣式設(shè)置方式

    這篇文章主要介紹了vue-router-link選擇樣式設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • element-vue實(shí)現(xiàn)網(wǎng)頁鎖屏功能(示例代碼)

    element-vue實(shí)現(xiàn)網(wǎng)頁鎖屏功能(示例代碼)

    這篇文章主要介紹了element-vue實(shí)現(xiàn)網(wǎng)頁鎖屏功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-11-11
  • vue實(shí)現(xiàn)商品詳情頁放大鏡功能

    vue實(shí)現(xiàn)商品詳情頁放大鏡功能

    這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)商品詳情頁放大鏡功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08

最新評論

甘谷县| 新巴尔虎左旗| 麟游县| 长沙县| 新河县| 静安区| 禹城市| 滁州市| 木里| 策勒县| 弥勒县| 任丘市| 靖西县| 翁源县| 长子县| 同心县| 凤凰县| 海宁市| 科技| 清镇市| 牙克石市| 庆城县| 舟山市| 三河市| 寻甸| 肥西县| 鄱阳县| 越西县| 广饶县| 来凤县| 始兴县| 厦门市| 关岭| 淳化县| 乳山市| 黄浦区| 卓尼县| 吕梁市| 大安市| 长乐市| 德江县|