uniapp仿支付宝账单日期选择组件

        自己女朋友有记账的习惯,就想着开发一个记账app给她用,想起来支付宝的账单页面日期选择组件不错,本想偷个懒到网上找一些资源直接使用的,翻了一下代码都不是很全,索性就自己封装了一个,对应的uview依赖全局注册一下,代码就可以直接使用了。

效果图如下,完美复刻:

                ​​​​​​​    

代码如下:

<template>
    <view>
        <u-popup :show="isShow" mode="bottom" @close="close" @open="open" :closeOnClickOverlay="true">
            <view class="popup-container">
                <u-tabs :list="tabList" @click="clickTab" class="tabs" :scrollable="false"></u-tabs>

                <!-- 交易時間 -->
                <view v-if="currentTab === 'tab2'">
                    <text class="heading">交 易 時 間</text>
                    <view class="buttons-group">
                        <button class="button button--primary" :class="{ selected: tradeDate === '3m' }"
                            @click="setDateRange('3m')">近三月</button>
                        <button class="button button--primary" :class="{ selected: tradeDate === '6m' }"
                            @click="setDateRange('6m')">近半年</button>
                        <button class="button button--primary" :class="{ selected: tradeDate === '1y' }"
                            @click="setDateRange('1y')">近一年</button>
                    </view>
                </view>

                <!-- 自定義清除時間按鈕 -->
                <view v-if="currentTab === 'tab2'" class="custom-time-container">
                    <text class="custom-time">自 定 義</text>
                    <uni-icons type="trash" size="18" @click="clearCustomTime"></uni-icons>
                </view>

                <view v-if="currentTab === 'tab2'" class="custom-time-container-text">
                    <text class="custom-time-text">最長可查找時間跨度一年的數據</text>
                </view>

                <!-- 月份选择内容 -->
                <view class=" content" v-if="currentTab === 'tab1'">
                    <picker-view :value="dateValue" indicator-style="height: 50px;" style="width: 100%; height: 300px;">
                        <picker-view-column>
                            <view v-for="(year, index) in years" :key="index" class="picker-item">{{ year }}</view>
                        </picker-view-column>
                        <picker-view-column>
                            <view v-for="(month, index) in months" :key="index" class="picker-item">{{ month }}
                            </view>
                        </picker-view-column>
                    </picker-view>
                </view>

                <!-- 自定义时间内容 -->
                <view class="date-range-container" v-if="currentTab === 'tab2'">
                    <view class="date-input" :class="{ selected: currentSelect === 'start' }"
                        @click="selectDate('start')">
                        <text>{{ startDateText }}</text>
                    </view>
                    <text class="date-separator">至</text>
                    <view class="date-input" :class="{ selected: currentSelect === 'end' }" @click="selectDate('end')">
                        <text>{{ endDateText }}</text>
                    </view>
                </view>

                <view class="content-range" v-if="currentTab === 'tab2'">
                    <picker-view :value="pickerValue" indicator-style="height: 50px;"
                        style="width: 100%; height: 150px;" @change="pickerChange">
                        <picker-view-column>
                            <view v-for="(year, index) in years" :key="index" class="picker-item">{{ year }}</view>
                        </picker-view-column>
                        <picker-view-column>
                            <view v-for="(month, index) in months" :key="index" class="picker-item">{{ month }}</view>
                        </picker-view-column>
                        <picker-view-column>
                            <view v-for="(day, index) in days" :key="index" class="picker-item">{{ day }}</view>
                        </picker-view-column>
                    </picker-view>
                </view>
            </view>

            <!-- 确认按钮 -->
            <view class="header-buttons">
                <button @click="confirm" class="button button--confirm">確 認</button>
            </view>
        </u-popup>
    </view>
</template>

<script>
    export default {
        data() {
            const currentDate = new Date();
            const currentYear = currentDate.getFullYear();
            const currentMonth = currentDate.getMonth();

            return {
                isShow: false,
                dateValue: [currentYear - 2020, currentMonth], // 默认选中当前年份和月份
                startDateValue: [currentYear - 2020, currentMonth, currentDate.getDate() - 1], // 默认选中当前日期
                startDateText: this.$moment().format('YYYY-MM-DD'), // 新增 startDateText

                endDateValue: [currentYear - 2020, currentMonth, currentDate.getDate() - 1], // 默认选中当前日期
                endDateText: '',

                pickerValue: [currentYear - 2020, currentMonth, currentDate.getDate() - 1], // 当前选择器的值
                currentSelect: 'start', // 用于标记当前选择的是开始日期还是结束日期

                tradeDate: '',

                years: Array.from({
                    length: 180
                }, (v, i) => 2020 + i), // 生成2020到2200年
                months: Array.from({
                    length: 12
                }, (v, i) => i + 1), // 生成1到12月
                days: Array.from({
                    length: 31
                }, (v, i) => i + 1), // 生成1到31日
                tabList: [{
                        name: '月份选择',
                        value: 'tab1'
                    },
                    {
                        name: '自定义时间',
                        value: 'tab2'
                    }
                ],
                currentTab: 'tab1'
            };
        },

        methods: {
            open() {
                this.isShow = true;
                this.currentTab = 'tab1';
                this.tradeDate = ''; // 确保打开组件时,tradeDate 被重置
            },

            close() {
                this.isShow = false;
            },

            clickTab(item) {
                this.currentTab = item.value;
            },

            confirm() {
                if (this.currentTab === 'tab1') {
                    const year = this.years[this.dateValue[0]];
                    const month = this.months[this.dateValue[1]];
                    this.$emit('dateSelected', {
                        year,
                        month
                    });
                } else if (this.currentTab === 'tab2') {
                    const startYear = this.years[this.startDateValue[0]];
                    const startMonth = this.months[this.startDateValue[1]];
                    const startDay = this.days[this.startDateValue[2]];
                    const endYear = this.years[this.endDateValue[0]];
                    const endMonth = this.months[this.endDateValue[1]];
                    const endDay = this.days[this.endDateValue[2]];
                    this.$emit('dateRangeSelected', {
                        startYear,
                        startMonth,
                        startDay,
                        endYear,
                        endMonth,
                        endDay
                    });
                }
                this.close();
            },

            setDateRange(range) {
                let now = new Date();
                let start = new Date(now); // 复制当前日期用于计算起始日期

                if (range === '3m') {
                    start.setMonth(now.getMonth() - 3);
                } else if (range === '6m') {
                    start.setMonth(now.getMonth() - 6);
                } else if (range === '1y') {
                    start.setFullYear(now.getFullYear() - 1);
                }

                // 更新开始时间
                this.startDateText = start.toISOString().split('T')[0];
                this.startDateValue = [
                    this.years.indexOf(start.getFullYear()),
                    this.months.indexOf(start.getMonth() + 1),
                    this.days.indexOf(start.getDate())
                ];

                // 检查并更新结束时间为当前日期
                const todayText = now.toISOString().split('T')[0];
                if (this.endDateText !== todayText) {
                    this.endDateText = todayText;
                    this.endDateValue = [
                        this.years.indexOf(now.getFullYear()),
                        this.months.indexOf(now.getMonth() + 1),
                        this.days.indexOf(now.getDate())
                    ];
                }

                this.tradeDate = range;
                if (this.currentSelect === 'start') {
                    this.pickerValue = [...this.startDateValue];
                } else if (this.currentSelect === 'end') {
                    this.pickerValue = [...this.endDateValue];
                }
            },

            clearCustomTime() {
                // 清空选中状态
                this.tradeDate = '';
                // 清空开始和结束时间
                this.startDateText = '';
                this.endDateText = '';

                const now = new Date();
                this.startDateValue = [
                    this.years.indexOf(now.getFullYear()),
                    this.months.indexOf(now.getMonth() + 1),
                    this.days.indexOf(now.getDate())
                ];
                this.endDateValue = [...this.startDateValue];
                this.pickerValue = [...this.startDateValue];
            },

            selectDate(type) {
                this.currentSelect = type;
                if (type === 'start' && this.startDateText === '') {
                    const now = new Date();
                    this.startDateValue = [
                        this.years.indexOf(now.getFullYear()),
                        this.months.indexOf(now.getMonth() + 1),
                        this.days.indexOf(now.getDate())
                    ];
                    this.startDateText = now.toISOString().split('T')[0];
                } else if (type === 'end' && this.endDateText === '') {
                    const now = new Date();
                    this.endDateValue = [
                        this.years.indexOf(now.getFullYear()),
                        this.months.indexOf(now.getMonth() + 1),
                        this.days.indexOf(now.getDate())
                    ];
                    this.endDateText = now.toISOString().split('T')[0];
                }

                if (type === 'start') {
                    this.pickerValue = [...this.startDateValue];
                } else if (type === 'end') {
                    this.pickerValue = [...this.endDateValue];
                }
            },

            pickerChange(e) {
                const value = e.target.value;
                if (this.currentSelect === 'start') {
                    this.startDateValue = value;
                    this.startDateText =
                        `${this.years[value[0]]}-${this.months[value[1]].toString().padStart(2, '0')}-${this.days[value[2]].toString().padStart(2, '0')}`;
                } else if (this.currentSelect === 'end') {
                    this.endDateValue = value;
                    this.endDateText =
                        `${this.years[value[0]]}-${this.months[value[1]].toString().padStart(2, '0')}-${this.days[value[2]].toString().padStart(2, '0')}`;
                }
            }
        }
    };
</script>

<style lang="scss" scoped>
    .popup-container {
        position: relative;
        width: auto;
        height: auto;
        padding: 20px 20px;
        background-color: #fff;
    }

    .header-buttons {
        display: flex;
        justify-content: space-between;
        padding: 0 20px;
        margin-bottom: 10px;
    }

    .button {
        background-color: transparent;
        border: none;
        color: #007bff;
        border-radius: 5px;
        padding: 5px 15px;
        font-size: 16px;
        text-align: center;
    }

    .button--confirm {
        align-self: flex-end;
        background-color: #007bff;
        color: #fff;
        width: 100%;
    }

    .tabs {
        width: 100%;
        margin-bottom: 20px;
    }

    .content {
        margin-top: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 300px;
    }

    .content-range {
        margin-top: 20px;
        display: flex;
        justify-content: center;
        align-items: center;
        height: 200px;
    }

    .picker-item {
        text-align: center;
        line-height: 50px;
        /* 确保与 indicator-style 的高度匹配 */
        display: flex;
        justify-content: center;
        align-items: center;
        height: 50px;
        /* 确保与 indicator-style 的高度匹配 */
    }

    .heading {
        text-align: center;
        font-size: 15px;
        margin-bottom: 10px;
    }

    .buttons-group {
        display: flex;
        margin-bottom: 20px;
        width: 100%;
    }

    .button--primary {
        background-color: white;
        /* 未选中状态背景色为白色 */
        color: #000000;
        border-radius: 5px;
        padding: 0;
        border: 1px solid rgba(0, 0, 0, 0.2);
        /* 淡淡的黑色边框 */
        height: 25px;
        width: 60px;
        margin-right: 10px;
        margin-left: 0px;
        margin-top: 25px;
        display: flex;
        justify-content: center;
        /* 文字居中 */
        align-items: center;
        /* 文字居中 */
    }

    .button--primary.selected {
        border: 1px solid #5555ff;
        /* 选中状态边框为淡蓝色 */
        color: white;
        /* 选中状态文字颜色为白色 */
        background-color: #5555ff;
        /* 选中状态背景色为淡蓝色 */
    }

    .custom-time-container {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 20px;
    }

    .custom-time-container-text {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-bottom: 20px;
    }

    .custom-time {
        font-size: 15px;
        margin-left: 0px;
    }

    .custom-time-text {
        font-size: 15px;
        margin-left: 0px;
        color: #ffaa00;
    }

    .date-range-container {
        display: flex;
        justify-content: center;
        align-items: center;
        margin-bottom: 20px;
        margin-top: 20px;
    }

    .date-input {
        border-bottom: 2px solid #ccc;
        padding: 5px 10px;
        margin: 0 10px;
        cursor: pointer;
        text-align: center;
        width: 150px;
        /* 固定宽度确保开始时间和结束时间一致 */
        height: 30px;
        /* 设置高度以确保一致 */
        line-height: 30px;
        /* 设置行高以居中内容 */
    }

    .date-input.selected {
        border-bottom: 2px solid #007bff;
        color: #007bff;
    }

    .date-separator {
        margin: 0 10px;
    }

    .picker-view-container {
        margin-top: 10px;
    }
</style>

  • 13
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值