先看效果
1.ohpm install dayjs
2.在目录ets/components/TimeDateDialog下创建index.ets
//弹窗具体内容
@CustomDialog
struct CustomDialogDate {
controller?: CustomDialogController
@Prop defaultTime: string; //默认值
@State allYears:string[]=[] // 前后六十年
@State allMonth:string[]=['01月','02月','03月','04月','05月','06月','07月','08月','09月','10月','11月','12月'] //只存储小时
@State allDay:string[]=[] //当月多少天
@State isHaveDay: boolean = false;
@State loadingData: boolean = false;
@State YearSelectValue: string = "0";
@State YearSelect: number=0;
@State MonthSelectValue: string= "00";
@State MonthSelect: number=0;
@State DaySelectValue: string= "00";
@State DaySelect: number=0;
cancel: () => void = () => {
}
confirm: (data:string) => void = () => {
}
// 提交数据
onSubmit(){
let dateTime = this.YearSelectValue + "-" + this.MonthSelectValue
if (this.isHaveDay){
dateTime = dateTime + "-" + this.DaySelectValue
}
this.confirm(this.DeleteChina(dateTime)) //回传日期到父组件
this.controller?.close()
}
aboutToAppear(): void {
this.initYearList(); //获取年
this.initDefaultTime() // 获取选中时间
if (this.isHaveDay) {
this.initDayList(); //初始化日
this.getDay()
}
}
initYearList(){
// 获取当前年份
const currentYear:number = new Date().getFullYear();
for (let i = -30; i <= 30; i++) {
this.allYears.push((currentYear + i ).toString()+'年')
}
}
initDayList(){
this.loadingData = true
this.allDay = []
const numbersDay: number = this.getDaysInMonth(Number(this.DeleteChina(this.YearSelectValue)) ,Number(this.DeleteChina(this.MonthSelectValue)))
for (let i = 1; i <= numbersDay; i++) {
this.allDay.push(i.toString()+'日')
}
this.loadingData = false
}
DeleteChina(data:string) :string{
return data.replace(/[年月日]/g, '')
}
getDay(){
this.DaySelectValue = new Date().getDate().toString();
this.DaySelect = this.allDay.indexOf((new Date().getDate()) > 9 ? (new Date().getDate()).toString() +'日' : '0' + (new Date().getDate()).toString() +"日");
}
getDaysInMonth(year: number, month: number): number {
// 注意:JavaScript 的月份是从 0 开始计数的(0 表示 1 月,11 表示 12 月)
// 所以需要将传入的月份减 1
return new Date(year, month, 0).getDate();
}
// 初始化默认选中
initDefaultTime(){
this.YearSelect = this.allYears.indexOf(new Date().getFullYear().toString()+'年');
this.YearSelectValue = new Date().getFullYear().toString()
this.MonthSelect = this.allMonth.indexOf( (new Date().getMonth()+1) > 9 ? (new Date().getMonth()+1).toString() +'月' : '0' + (new Date().getMonth()+1).toString() +'月' ) ;
this.MonthSelectValue = (new Date().getMonth()+1) > 9 ? (new Date().getMonth()+1).toString() : '0' + (new Date().getMonth()+1).toString()
}
build() {
Column() {
Row(){
Button('取消', { type: ButtonType.Normal, stateEffect: true })
.margin(0)
.borderRadius(6)
.backgroundColor('#fff')
.fontColor('#aaa')
.fontSize(14)
.onClick(()=>{
this.controller?.close()
})
Button('确定', { type: ButtonType.Normal, stateEffect: true })
.margin(0)
.backgroundColor('#fff')
.fontColor('#3C7FFF')
.fontSize(14)
.onClick(()=>{
this.onSubmit()
this.controller?.close()
})
}.width('100%').justifyContent(FlexAlign.SpaceBetween)
Divider().color('#EEE').strokeWidth(1)
// 滚动选中区域
Flex(){
// 年
TextPicker({ range: this.allYears, selected: this.YearSelect})
.width(this.isHaveDay ? '50%' : '60%')
.canLoop(false)//不循环
.divider({
strokeWidth: 1,
startMargin: 0,
endMargin: 0,
color:'#eee'
})
.onChange((value: string | string[], index: number | number[]) => {
this.YearSelect= index as number
this.YearSelectValue = value as string
this.initDayList()
})
.defaultPickerItemHeight(40)
.textStyle({color:'#cccccc', font: {size: 15, weight: 400}})
.selectedTextStyle({color: '#555555', font: {size: 15}})
//月
TextPicker({ range: this.allMonth, selected: this.MonthSelect }).width(this.isHaveDay ? '25%' : '40%')
.canLoop(false)//不循环
.divider({
strokeWidth: 1,
startMargin: 0,
endMargin: 0,
color:'#eee'
})
.defaultPickerItemHeight(40)
.textStyle({color:'#cccccc', font: {size: 15, weight: 400}})
.selectedTextStyle({color: '#555555', font: {size: 15}})
.onChange((value: string | string[], index: number | number[]) => {
this.MonthSelect= index as number
this.MonthSelectValue = value as string
this.initDayList()
})
//日
if(!this.loadingData && this.isHaveDay){
TextPicker({ range: this.allDay, selected: this.DaySelect }).width('25%').canLoop(false)//不循环
.divider({
strokeWidth: 1,
startMargin: 0,
endMargin: 0,
color:'#eee'
})
.defaultPickerItemHeight(40)
.textStyle({color:'#cccccc', font: {size:15, weight: 400}})
.selectedTextStyle({color: '#555555', font: {size: 15}})
.onChange((value: string | string[], index: number | number[]) => {
this.DaySelect= index as number
this.DaySelectValue = value as string
})
}
}
}.width('100%')
.padding({bottom:40,top:5})
.backgroundColor('#fff')
}
}
//定义controller对象 主要作用父子通信 父组件调用子组件方法 唤醒弹窗
export class DialogDateController {
ShowDialog = (value?: string) => {
}
}
//弹窗控制逻辑
@Component
export struct TimeDateDialog { //修改命名 注意前面加了 export 需要暴露组件
private controller: DialogDateController = new DialogDateController();
CustomDialogController: CustomDialogController | null =null ;
@Prop defaultTime: string;
@State isHaveDay: boolean = false;
cancel?: () => void
confirm?: (data:string) => void = () => {
}
// 打开显示弹窗
private async ShowDialog(value?: string){
this.CustomDialogController?.open()
}
aboutToAppear(): void {
if (this.controller) {
//给controller对应的方法赋值
this.controller.ShowDialog = this.ShowDialog.bind(this); //这里需要注意 用了 bind改变 this 指向
}
this.CustomDialogController= new CustomDialogController({
builder: CustomDialogDate({
isHaveDay :this.isHaveDay,
cancel: this.cancel,
confirm: this.confirm,
}),
autoCancel: true,
onWillDismiss:(dismissDialogAction: DismissDialogAction)=> {
if (dismissDialogAction.reason == DismissReason.PRESS_BACK) {
dismissDialogAction.dismiss()
}
if (dismissDialogAction.reason == DismissReason.TOUCH_OUTSIDE) {
dismissDialogAction.dismiss()
}
},
alignment: DialogAlignment.Bottom,
offset: { dx: 0, dy: 0},
customStyle: true,//这里为true 样式才可以完全自定义
})
}
aboutToDisappear() {
this.CustomDialogController = null // 将dialogController置空
}
build() { //因为用的 自定义弹窗功能,所以这下面可以为空
}
}
3.在页面调用
import dayjs from 'dayjs'
import { DialogDateController, TimeDateDialog } from '../../component/TimeDateDialog'
@Component
export struct Home {
@State DateDialogRef: DialogDateController = new DialogDateController(); //用于调用子组件的方法 唤醒弹窗
@State DateDialogRefTrue: DialogDateController = new DialogDateController(); //用于调用子组件的方法 唤醒弹窗
@State times: string = dayjs().format('YYYY-MM')
@State timesR: string = dayjs().format('YYYY-MM-DD')
build() {
Column() {
Column() {
Button(dayjs(this.times).format('YYYY年M月'), { type: ButtonType.Normal, stateEffect: true })
.fontSize(12)
.fontWeight(400)
.fontColor('#000')
.onClick(() => {
this.DateDialogRef.ShowDialog()
})
Button(dayjs(this.timesR).format('YYYY年M月D日'), { type: ButtonType.Normal, stateEffect: true })
.fontSize(12)
.fontWeight(400)
.fontColor('#000')
.onClick(() => {
this.DateDialogRefTrue.ShowDialog()
})
TimeDateDialog({
isHaveDay: false,
controller: this.DateDialogRef,
confirm: (data) => {
this.times = data
}
})
TimeDateDialog({
isHaveDay: true,
controller: this.DateDialogRefTrue,
confirm: (data) => {
this.timesR = data
}
})
}
}
}
}