Vue2自定义时间选择器

问题:

在使用element-ui(vue2)时,发现

<el-time-select>支持选择固定的时间点但不支持传入可选时间端

<el-time-picker>支持传入可选时间段但不支持选择固定的时间点

自定义时间选择组件:
<template>
    <el-select 
        class="custom-time-select" 
        v-model="innerValue" 
        :placeholder="placeholder" 
        filterable
        @change="selectChange"
    >
        <el-option 
            v-for="(time, index) in filteredTimeList" 
            :key="index" 
            :label="time" 
            :value="time" 
        />
    </el-select>
</template>

<script>
export default {
    name: 'CustomTimeSelect',
    props: {
        value: String,
        start: {
            type: String,
            default: '08:00'
        },
        end: {
            type: String,
            default: '18:00'
        },
        step: {
            type: String,
            default: '00:30'
        },
        disabledRanges: {
            // [{start: '14:00:00', end: '16:00:00'}]
            type: Array,
            default: () => []
        },
        placeholder: String
    },
    data() {
        return {
            timeList: [],
            innerValue: this.value
        };
    },
    computed: {
        filteredTimeList() {
            return this.timeList.filter(time => {
                return !this.disabledRanges.some(range => {
                    return time >= range.start && time <= range.end;
                });
            });
        }
    },
    watch: {
        value(val) {
            this.innerValue = val;
        },
        innerValue(val) {
            this.$emit('input', val);
        },
        start: 'initTimeList',
        end: 'initTimeList',
        step: 'initTimeList',
        disabledRanges: 'initTimeList'
    },
    mounted() {
        this.initTimeList();
    },
    methods: {
        initTimeList() {
            this.timeList = [];

            const [startH, startM] = this.start.split(':').map(Number);
            const [endH, endM] = this.end.split(':').map(Number);
            const [stepH, stepM] = this.step.split(':').map(Number);
            let h = startH, m = startM;

            while (h < endH || (h === endH && m <= endM)) {
                const time = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
                this.timeList.push(time);

                m += stepM;
                h += stepH + Math.floor(m / 60);
                m %= 60;
            }
        },
        selectChange(val) {
            this.$emit('change', val);
        }
    }
};
</script>

<style scoped>
.custom-time-select {
    width: 120px;
}
</style>
<el-form-item prop="time">
     <CustomTimeSelect 
        v-model="Form.time" 
            :start="'08:00'" 
            :end="'22:00'" 
            :step="'00:30'"
            :disabled-ranges="disabledRanges" 
            placeholder="请选择时间" 
    />
</el-form-item>
其中,  disabledRanges([{start: '14:00:00', end: '16:00:00'},...])就是需要禁用的时间段列表

如何需要实现的是时间段选择,还需要过滤非法的时间段,以下方式仅供参考:

<template>
    <el-select 
        class="custom-time-select" 
        v-model="innerValue" 
        :placeholder="placeholder" 
        filterable
        @change="selectChange"
    >
        <el-option 
            v-for="(time, index) in filteredTimeList" 
            :key="index" :label="time" 
            :value="time" 
        />
    </el-select>
</template>

<script>
export default {
    name: 'CustomTimeSelect',
    props: {
        value: String,
        start: { type: String, default: '08:00' },
        end: { type: String, default: '18:00' },
        step: { type: String, default: '00:30' },
        disabledRanges: {
            // [{start: '14:00:00', end: '16:00:00'}]
            type: Array,
            default: () => []
        },
        placeholder: String,
        startTime: String
    },
    data() {
        return {
            timeList: [],
            innerValue: this.value
        };
    },
    computed: {
        filteredTimeList() {
            if (!this.startTime || !this.timeList.includes(this.startTime)) {
                return this.timeList.filter(time => {
                    return !this.disabledRanges.some(range => {
                        return time >= range.start && time <= range.end;
                    });
                });
            }
            const startIndex = this.timeList.indexOf(this.startTime);
            let endIndex = this.timeList.length;
            for (let range of this.disabledRanges) {
                const rangeStartIndex = this.timeList.indexOf(range.start);
                if (rangeStartIndex > startIndex) {
                    endIndex = rangeStartIndex;
                    break;
                }
            }
            const filtered = this.timeList.slice(startIndex, endIndex);
            if (!filtered.includes(this.innerValue)) {
                this.$nextTick(() => {
                    this.innerValue = filtered[0];
                    this.$emit('input', filtered[0]);
                    this.$emit('change', filtered[0]);
                });
            }

            return filtered;
        }
    },
    watch: {
        value(val) {
            this.innerValue = val;
        },
        innerValue(val) {
            this.$emit('input', val);
        },
        start: 'initTimeList',
        end: 'initTimeList',
        step: 'initTimeList',
        disabledRanges: 'initTimeList',
        startTime: 'initTimeList'
    },
    mounted() {
        this.initTimeList();
    },
    methods: {
        initTimeList() {
            this.timeList = [];

            const [startH, startM] = this.start.split(':').map(Number);
            const [endH, endM] = this.end.split(':').map(Number);
            const [stepH, stepM] = this.step.split(':').map(Number);
            let h = startH, m = startM;

            while (h < endH || (h === endH && m <= endM)) {
                const time = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
                this.timeList.push(time);

                m += stepM;
                h += stepH + Math.floor(m / 60);
                m %= 60;
            }
        },
        selectChange(val) {
            this.$emit('change', val);
        }
    }
};
</script>

<style scoped>
.custom-time-select {
    width: 120px;
}
</style>
<!-- 开始时间 -->
<el-form-item prop="startTime">
     <CustomTimeSelect 
        v-model="Form.startTime" 
            :start="'08:00'" 
            :end="'22:00'" 
            :step="'00:30'"
            :disabled-ranges="disabledRanges" 
            placeholder="开始时间" 
    />
</el-form-item>

<span>至</span>

<!-- 结束时间 -->
<el-form-item prop="endTime">
    <CustomTimeSelect 
        v-model="Form.endTime" 
        :start="Form.startTime || '08:00'"
        :end="'22:00'" 
        :step="'00:30'" 
        :disabled-ranges="disabledRanges" 
        placeholder="请选择时间" 
        :start-time="Form.startTime"
    />
</el-form-item>

在结束时间组件中添加:start-time="Form.startTime"防止跨时间段选择

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值