vue3+ts+uniapp小程序端自定义日期选择器基于内置组件picker-view + 扩展组件 Popup 实现自定义日期选择及其他选择

news/2024/7/10 3:05:37 标签: uni-app, 小程序, vue

vue3+ts 基于内置组件picker-view + 扩展组件 Popup 实现自定义日期选择及其他选择

vue3+ts+uniapp小程序端自定义日期选择器

  • 1.先上效果图
  • 2.代码展示
    • 2.1 组件
    • 2.2 公共方法处理日期
    • 2.3 使用组件
  • 3.注意事项
    • 3.1`refSelectDialog`
    • 3.1 `backgroundColor="#fff"` 圆角问题

自我记录

1.先上效果图

![在这里插入图片描述](https://img-blog.csdnimg.cn/48ecbb2775794a7cbec358e2c4017a3a.png
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
直接上代码

2.代码展示

2.1 组件

src\components\HbcyPopup.vue

<script setup lang="ts">
import { formatDate, parseDate } from '@/utils'
import { ref } from 'vue'

const props = defineProps<{
  popupTitle: string
  type: 'year' | 'month' | 'day'
  defaultDate: string
}>()
const emit = defineEmits<{
  (e: 'confirm-popup', params: string): void
  (e: 'close-popup'): void
}>()

// 选中的值
const selectDate = ref('')
// 创建选择区间 参考uni文档
const date = new Date()
// 年月日
const TYPEYY_MM_DD = props.type === 'year' || props.type === 'month' || props.type === 'day'
// 月日
const TYPEMM_DD = props.type === 'month' || props.type === 'day'
const TYPEYY = props.type === 'year'
const TYPEMM = props.type === 'month'
const TYPEDD = props.type === 'day'
const years = TYPEYY_MM_DD
  ? Array.from({ length: date.getFullYear() - 1989 }, (_, index) => 1990 + index)
  : []
const months = TYPEMM_DD ? Array.from({ length: 12 }, (_, index) => index + 1) : []
const days = TYPEDD ? Array.from({ length: 31 }, (_, index) => index + 1) : []
// 处理默认展示的时间
const defaultDate = parseDate(props.defaultDate, props.type)
// 确保默认时间
const year = ref<number>(defaultDate[0])
const month = ref<number | undefined>(defaultDate[1])
const day = ref<number | undefined>(defaultDate[2])
// 区分日期展示
let showValueList: any = []
// 展示日期的选中时间
if (TYPEDD) {
  showValueList = [
    years.indexOf(defaultDate[0]),
    months.indexOf(defaultDate[1]!),
    days.indexOf(defaultDate[2]!),
  ]
} else if (TYPEMM) {
  showValueList = [years.indexOf(defaultDate[0]), months.indexOf(defaultDate[1]!)]
} else if (TYPEYY) {
  showValueList = [years.indexOf(defaultDate[0])]
}
const valueList = ref<number[]>(showValueList)

// 切换日期
const bindChange: UniHelper.PickerViewOnChange = (e) => {
  const val = e.detail.value
  year.value = years[val[0]]
  month.value = months[val[1]]
  day.value = days[val[2]]
}
// 确定按钮
const onClickConfirmPopup = (): void => {
  selectDate.value = formatDate(year.value, month.value, day.value)
  emit('confirm-popup', selectDate.value)
  onClosePopup()
}
// 关闭弹出层
const onClosePopup = (): void => {
  emit('close-popup')
}
const { safeAreaInsets } = uni.getSystemInfoSync()
</script>

<template>
  <view class="selectBox">
    <view class="selectTitle">
      <text class="cancel" @click="onClosePopup">取消</text>
      <text class="title">{{ '选择' + popupTitle }}</text>
      <text class="cancel ok" @click="onClickConfirmPopup">确定</text>
    </view>
    <block v-if="TYPEYY_MM_DD">
      <picker-view
        :immediate-change="true"
        indicator-class="indicatorClass"
        :value="valueList"
        @change="bindChange"
        class="picker-view"
      >
        <picker-view-column>
          <view class="item" v-for="(item, index) in years" :key="index">{{ item }}</view>
        </picker-view-column>
        <picker-view-column v-if="TYPEMM_DD">
          <view class="item" v-for="(item, index) in months" :key="index">{{ item }}</view>
        </picker-view-column>
        <picker-view-column v-if="TYPEDD">
          <view class="item" v-for="(item, index) in days" :key="index">{{ item }}</view>
        </picker-view-column>
      </picker-view>
    </block>
    <!-- TODO -->
    <block v-else> <text>我是单列</text> </block>
    <!-- 修复启用:safeArea="true" 时 圆角不好实现问题,现在是自己做的适配-->
    <view :style="{ height: safeAreaInsets?.bottom + 'px' }" style="width: 100%" />
  </view>
</template>

<style lang="scss" scoped>
::v-deep.indicatorClass {
  height: 100rpx;
}
.picker-view {
  width: 750rpx;
  height: 500rpx;
  margin-top: 20rpx;
}
.item {
  line-height: 100rpx;
  text-align: center;
}
.selectBox {
  width: 100%;
  height: fit-content;
  background-color: #fff;
  border-radius: 20rpx 20rpx 0 0;
  .selectTitle {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: 100rpx;
    font-size: 32rpx;
    .title {
      font-size: 32rpx;
    }
    .cancel {
      width: 160rpx;
      text-align: center;
      color: #ff976a;
      font-size: 32rpx;
    }
    .ok {
      font-size: 32rpx;
      color: #07c160;
    }
  }
}
</style>

2.2 公共方法处理日期

src\utils\index.ts

// 将 yyyy-mm-dd 的字符串 2023-08-24 => [2023,8,24] || [2023,8] || [2023]
export function parseDate(dateString: string, type: string): [number, number?, number?] {
  const date = dateString ? new Date(dateString) : new Date()
  const year = date.getFullYear()
  const month = type === 'day' || type === 'month' ? date.getMonth() + 1 : undefined
  const day = type === 'day' ? date.getDate() : undefined
  return [year, month, day]
}

// 将数字格式的年、月、日转换成格式为 yyyy-mm-dd 的字符串 || yyyy-mm || yyyy
export function formatDate(year: number, month?: number, day?: number): string {
  const formattedMonth = month !== undefined ? (month < 10 ? `0${month}` : `${month}`) : ''
  const formattedDay = day !== undefined ? (day < 10 ? `0${day}` : `${day}`) : ''
  return `${year}${formattedMonth ? `-${formattedMonth}` : ''}${
    formattedDay ? `-${formattedDay}` : ''
  }`
}

2.3 使用组件

src\pages\test\index.vue

<script setup lang="ts">
import type { Ref } from 'vue'
import { ref } from 'vue'

// 日期相关
const isShowPopop = ref(false)
// 弹出层实例
const refSelectDialog: Ref<UniHelper.UniPopup | null> = ref(null)
const dateTime = ref('')
// 打开日期弹窗
const onClcikPopup = () => {
  refSelectDialog.value!.open()
  isShowPopop.value = true
  console.log(refSelectDialog, 'refPopup')
}
// 关闭弹窗
const onClosePopup = () => {
  refSelectDialog.value!.close()
  isShowPopop.value = false
}
// 确定日期弹窗
const onConfirmPopup = (params: string) => {
  dateTime.value = params
  console.log(dateTime.value, 'dateTime.value')
}
</script>

<template>
  <view class="test-page">
    <!-- 展示信息 -->
    <view @tap="onClcikPopup" class="item-date">
      <text class="item-date-placeholder" v-show="!dateTime">请选择时间</text>
      <text class="item-date-txt" v-show="dateTime">{{ dateTime }}</text>
    </view>
    <!-- 使用组件 -->
    <uni-popup
      ref="refSelectDialog"
      type="bottom"
      :maskClick="false"
      :isMaskClick="false"
      :safeArea="false"
      :close="onClosePopup"
    >
      <HbcyPopup
        v-if="isShowPopop"
        popupTitle="日期"
        type="day"
        :defaultDate="dateTime"
        @confirm-popup="onConfirmPopup"
        @close-popup="onClosePopup"
      />
    </uni-popup>
  </view>
</template>

<style lang="scss" scoped>
.test-page {
  .item-date {
    width: 300rpx;
    height: 60rpx;
    line-height: 60rpx;
    text-align: center;
    border: 1rpx solid #999;
    font-size: 28rpx;

    &-placeholder {
      color: #999;
    }

    &-txt {
      color: #333;
    }
  }
}
</style>

3.注意事项

3.1refSelectDialog

// 弹出层实例
const refSelectDialog: Ref<UniHelper.UniPopup | null> = ref(null)
  • ts类型有一些问题,找了好久不知道该给什么类型!!! 新手TS,有大佬的话请指出,感谢!

3.1 backgroundColor="#fff" 圆角问题

<uni-popup backgroundColor="#fff" /> 
  • 因为默认是开启适配的,需要加上背景色,否则就是透明的底部区域
  • 示例如下:
  • 在这里插入图片描述
  • 源码查看
  • 在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    整理不易,如有转载请备注原文地址!

http://www.niftyadmin.cn/n/4977408.html

相关文章

vue3跳转统一页面,path一样,传递的参数不一样时页面不刷新

vue3中当路由一样&#xff0c;参数quary不一样的跳转不刷新 当路由的path都是一样的&#xff0c;quary不一样&#xff0c;在跳转的时候&#xff0c;不会执行onMounted等方法&#xff0c;页面也就不会刷新。 方法&#xff1a; 修改router-view&#xff0c;在app.vue页面给标签…

nginx配置keepalive长连接

nginx之keepalive详解与其配置_keepalive_timeout_恒者走天下的博客-CSDN博客 为什么要有keepalive? 因为每次建立tcp都要建立三次握手&#xff0c;消耗时间较长&#xff0c;所以为了减少tcp建立连接需要的时间&#xff0c;就可以设置keep_alive长连接。 nginx中keep_alive对…

Spring Boot 整合 分布式搜索引擎 Elastic Search 实现 数据聚合

文章目录 ⛄引言一、数据聚合⛅简介⚡聚合的分类 二、DSL实现数据聚合⏰Bucket聚合⚡Metric聚合 三、RestAPI实现数据聚合⌚业务需求⏰业务代码实现 ✅效果图⛵小结 ⛄引言 本文参考黑马 分布式Elastic search Elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常…

Viva Workplace Analytics Employee Feedback SU Viva Glint部署方案

目录 一、Viva Workplace Analytics & Employee Feedback SU Viva Glint介绍 二、Viva Glint和Viva Pulse特点和优势 1. 简单易用

4.22 TCP 四次挥手,可以变成三次吗?

目录 为什么 TCP 挥手需要四次呢&#xff1f; 粗暴关闭 vs 优雅关闭 close函数 shotdown函数 什么情况会出现三次挥手&#xff1f; 什么是 TCP 延迟确认机制&#xff1f; TCP 序列号和确认号是如何变化的&#xff1f; 在一些情况下&#xff0c; TCP 四次挥手是可以变成 T…

LeetCode每日一题:56. 合并区间(2023.8.27 C++)

目录 56. 合并区间 题目描述&#xff1a; 实现代码与解析&#xff1a; 排序 贪心 原理思路&#xff1a; 56. 合并区间 题目描述&#xff1a; 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&…

ZZULIOJ 1137: 查找最大元素,Java

ZZULIOJ 1137: 查找最大元素&#xff0c;Java 题目描述 对于输入的字符串&#xff0c;查找其中的ASCII码值最大字母&#xff0c;在该字母后面插入字符串“(max)”。 输入 输入一行长度不超过200的字符串组成&#xff0c;字符串仅由大小写字母构成。 输出 输出的结果是插入…

多个版本python本地调用解决方案

当本机既装了2点几的python又装的3点几的python的时候&#xff0c;在环境变量里面&#xff0c;哪一个的路径在path里面配置的考前&#xff0c;哪个就会被识别到。 如果想使用3点几的python怎么搞呢&#xff1f; 输入指令 where python&#xff0c; 找到你要的python路径&#…