目录
前言
一.界说变量
二.编辑日历页面
1.框架
2.编写页面标题
3.搜索栏及跳转按钮
1)搜索框
2)搜索按钮
3)设置跳转按钮
4.日历主体布局
5.日历空格函数
6.日历布局函数
三.源代码
前言
本文是记录笔者举行鸿蒙北向学习时,用ArkTs编写一个可以自顺应屏幕的简易日历的开辟过程。(真的非常简易!没有太高技能含量hhhh)源代码附在文章末尾,如有不敷之处接待一起讨论~
制品就是如许啦->
右上角输入年月,按下“go”按钮即可跳转至指定年月;按‘<’或‘>’即可切换至上个月或下个月。
下面是相关代码及开辟过程 ^~^
一.界说变量
- 使用riqi数组储存页面表现的日期,没有日期的几天使用空格占位。
- 用week数组存储星期,用于后续设置星期栏
- 界说动态变量年year月month日day(以2024.12作为初始页面)
- @Entry
- @Component
- struct DataPage {
- @State riqi:Array<string>=["1","2","3","4","5","6","7","8",
- "9","10","11","12","13","14","15",
- "16","17","18","19","20","21","22",
- "23","24","25","26","27","28","29","30","31"," "," "," "," "];
- @State week:Array<string>=["日","一","二","三","四","五","六"]
- @State year:number=2024;
- @State month:number=12;
- @State day:number=0;
- //以2024.12的日历作为初始页面
- //对各个变量进行初始化
复制代码 二.编辑日历页面
主页面主要是使用Grid组件举行页面布局,使用GridItem组件对页面举行分块。(留意build下只能有一个Grid,GridItem下也只能有一个子组件,但是Grid下可以有多个GridItem,并且Grid的子组件必须是GridItem组件)
1.框架
- build() {
- Grid() {
- ...............
- }
- .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr')
- .rowsTemplate(this.riqi.length>35?'1fr 1fr 2fr 2fr 2fr 2fr 2fr 2fr 2fr 1fr':'1fr 1fr 2fr 2fr 2fr 2fr 2fr 2fr 1fr' )
- //根据月份天数判断需要几行
- }
复制代码 (接下来的代码均在Grid()下编写)
columntemplate及rowstemplate为设置页面分块及占比的相关属性,官方文档见下方
Grid组件https://docs.openharmony.cn/pages/v4.1/zh-cn/application-dev/ui/arkts-layout-development-create-grid.md
2.编写页面标题
标题要随着年月的改变相应的改变,因此我们需要在text中引用变量,使其表现的年月能随着变量的改变而改变。
(columnstart,columnend以及之后用到的rowstart,rowend均为设置GridItem容器大小的相关属性。有需要的可以去看这个GridItem组件官方文档)
- GridItem(){
- Text(`${this.year}年${this.month}月`)
- .fontSize(25)
- .fontWeight(700)
- //根据用户输入的年月更改页面标题
- }.columnStart(1)
- .columnEnd(3)
复制代码 3.搜索栏及跳转按钮
1)搜索框
接下来,我们需要使用TextInput组件设置输入框,并使用onChange事件将状态变量与文本实时绑定,以便更新日历标题
- GridItem(){
- TextInput({placeholder:'年'})
- .onChange((value: string) => {
- this.year=Number(value);
- })
- .fontColor("#ff034980")
- }.columnStart(4)
- .columnEnd(5)
- GridItem(){
- TextInput({placeholder:'月'})
- .onChange((value: string) => {
- this.month=Number(value);
- })
- .fontColor("#ff034980")
- }.columnStart(6)
- .columnEnd(6)
- //记录用户输入的年月
复制代码 2)搜索按钮
使用button的onclick事件调用我们编写的查找日期的函数,foreach会根据riqi数组的变化重新渲染页面
- GridItem(){
- Button({type:ButtonType.Circle}) {
- Text("go")
- }.height("30")
- .width("70")
- .backgroundColor("#a3ff8c8c")
- .onClick((event: ClickEvent) => {
- this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day))
- })
- //点击事件调用findday()函数找到2000.1.1与用户输入的日期相差几天,将其作为参数传入tian()函数中
- //调用tian()函数对该月份的日期进行排版,并以数组形式传给riqi数组,以便后续foreach循环渲染
- }.columnStart(7)
复制代码 3)设置跳转按钮
使用跳转按钮直接前去上一月或下一月的日历,记得将1月以及12月这种特殊环境考虑在内,通过onclick事件更新相关变量后调用相关函数更新riqi数组,foreach重新渲染页面
- GridItem() {
- Column() {
- Blank()
- }
- }.columnStart(1)
- .columnEnd(5)
- //使用blank进行空白占位
- GridItem(){
- Button({type:ButtonType.Capsule}) {
- Text("<")
- }.height("30")
- .width("50")
- .backgroundColor("#bcf5d7ff")
- .onClick((event: ClickEvent) => {
- if(this.month==1){
- this.month=12;
- this.year--;
- }else{
- this.month--;
- }
- this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day))
- })
- }.columnStart(6)
- .columnEnd(6)
-
- GridItem(){
- Button({type:ButtonType.Capsule}) {
- Text(">")
- }.height("30")
- .width("50")
- .backgroundColor("#bcf5d7ff")
- .onClick((event: ClickEvent) => {
- if(this.month==12){
- this.month=1;
- this.year++;
- }else{
- this.month++;
- }
- this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day))
- })
- }.columnStart(6)
- .columnEnd(7)
- //跳转前一个或下一个月
复制代码 4.日历主体布局
使用foreach循环渲染以减少重复代码
- ForEach(this.week,(item:string)=>{
- GridItem() {
- Button({ type: ButtonType.Circle }) {
- Text(`${item}`) //引用变量
- .fontSize(20)
- .fontColor("#ff808080")
- }.width('90%')
- .height('90%')
- .borderRadius(50)
- .backgroundColor("#fffff2c0")
- }
- })//循环渲染星期导航栏
- ForEach(this.riqi, (item:string)=> {
- GridItem() {
- Button( {type: ButtonType.Circle}) {
- Text(`${item}`)
- .fontSize(20)
- }.width('90%')
- .height('90%')
- .borderRadius(50)
- .backgroundColor(item === " " ? "#6ac8f4f8" : "#9faff8f8")
- //根据这个button有无日期填充不一样的背景颜色
- }
- })//渲染日期
复制代码 5.日历空格函数
由于日历并不是全被日期占满,会有空出来的地方,就像下面那样
因此我们需要找到日历的开头需要几个空格子,这里我们以2000.1.1为参照,盘算当前年月的1号间隔2000.1.1几天,然后除7取余,余数即为当前月份的日历前空格子的个数,然后返回这个余数。(留意闰年)
- function findday(y:number,m:number,d:number) {
- let run: Array<number> = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let feirun: Array<number> = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let sum: number = 0;
- let nian: number = 2000;
- let yue: number = 1;
- let ri: number = 1;
- let jujin: number = 0;
- for (let j = nian; j < y; j++) {
- //计算前几年有多少天,需区分是否为闰年
- sum = 0;
- if ((j % 400 == 0) || (j % 4 == 0 && j % 100 != 0)) {
- sum += 366;
- } else {
- sum += 365;
- }
- jujin += sum;
- }
- sum = 0; //计算当年有多少天
- if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0)) {
- for (let i = 0; i < m-1; i++) {
- sum += run[i];
- }
- } else {
- for (let i = 0; i < m-1; i++) {
- sum += feirun[i];
- }
- }
- jujin += sum;
- jujin = (jujin+6) % 7;
- //计算出要显示的日历前面需要空几格
- return jujin;
- }
复制代码 6.日历布局函数
知道日历前空格数后,我们现在来对日历的日期举行排版,为了雅观我们需要将没有日期的几天填充空格让其可以表现,就像如许
因此我们使用3个循环对数组举行填充,然后返回数组(同样的,留意闰年)
- function tian(y:number,m:number,kong:number) {
- let day:Array<string>=new Array (35);
- for(let i=0;i<kong;i++){
- day[i]=" ";
- }//对没有日期的格子填空格
- let d:number;
- let run: Array<number> = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let feirun: Array<number> = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let sum: number = 0;
- if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0)) {
- d=run[m-1];
- } else {
- d = feirun[m-1];
- }//填充有日期的格子
- let a=0;
- for(let i=kong;i<d+kong;i++){
- a++;
- day[i]=a.toString();
- }
- if(day.length<=35) {
- for (let i = d + kong; i < 35; i++) {
- day[i] = " ";
- }
- }
- else {
- for (let i = d + kong; i < 42; i++) {
- day[i] = " ";
- }
- }//补全剩余空格
- return day;
- //返回day数组给foreach以便进行循环渲染
- }
复制代码 如许,我们的日历就制作完成啦 !
三.源代码
- @Entry
- @Component
- struct DataPage {
- @State riqi:Array<string>=["1","2","3","4","5","6","7","8",
- "9","10","11","12","13","14","15",
- "16","17","18","19","20","21","22",
- "23","24","25","26","27","28","29","30","31"," "," "," "," "];
- @State week:Array<string>=["日","一","二","三","四","五","六"]
- @State year:number=2024;
- @State month:number=12;
- @State day:number=0;
- //以2024.12的日历作为初始页面
- //对各个变量进行初始化 build() { Grid() { GridItem(){
- Text(`${this.year}年${this.month}月`)
- .fontSize(25)
- .fontWeight(700)
- //根据用户输入的年月更改页面标题
- }.columnStart(1)
- .columnEnd(3)
- GridItem(){
- TextInput({placeholder:'年'})
- .onChange((value: string) => {
- this.year=Number(value);
- })
- .fontColor("#ff034980")
- }.columnStart(4)
- .columnEnd(5)
- GridItem(){
- TextInput({placeholder:'月'})
- .onChange((value: string) => {
- this.month=Number(value);
- })
- .fontColor("#ff034980")
- }.columnStart(6)
- .columnEnd(6)
- //记录用户输入的年月 GridItem(){
- Button({type:ButtonType.Circle}) {
- Text("go")
- }.height("30")
- .width("70")
- .backgroundColor("#a3ff8c8c")
- .onClick((event: ClickEvent) => {
- this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day))
- })
- //点击事件调用findday()函数找到2000.1.1与用户输入的日期相差几天,将其作为参数传入tian()函数中
- //调用tian()函数对该月份的日期进行排版,并以数组形式传给riqi数组,以便后续foreach循环渲染
- }.columnStart(7) GridItem() { Column() { Blank() } }.columnStart(1) .columnEnd(5) GridItem(){ Button({type:ButtonType.Capsule}) { Text("<") }.height("30") .width("50") .backgroundColor("#bcf5d7ff") .onClick((event: ClickEvent) => { if(this.month==1){ this.month=12; this.year--; }else{ this.month--; } this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day)) }) }.columnStart(6) .columnEnd(6) GridItem(){ Button({type:ButtonType.Capsule}) { Text(">") }.height("30") .width("50") .backgroundColor("#bcf5d7ff") .onClick((event: ClickEvent) => { if(this.month==12){ this.month=1; this.year++; }else{ this.month++; } this.riqi=tian(this.year,this.month, findday(this.year,this.month,this.day)) }) }.columnStart(6) .columnEnd(7) //跳转前一个或下一个月 ForEach(this.week,(item:string)=>{ GridItem() { Button({ type: ButtonType.Circle }) { Text(`${item}`) .fontSize(20) .fontColor("#ff808080") }.width('90%') .height('90%') .borderRadius(50) .backgroundColor("#fffff2c0") } })//循环渲染星期导航栏 ForEach(this.riqi, (item:string)=> { GridItem() { Button( {type: ButtonType.Circle}) { Text(`${item}`) .fontSize(20) }.width('90%') .height('90%') .borderRadius(50) .backgroundColor(item === " " ? "#6ac8f4f8" : "#9faff8f8") //根据这个button有无日期填充不一样的背景颜色 } })//渲染日期 } .columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr') .rowsTemplate(this.riqi.length>35?'1fr 1fr 2fr 2fr 2fr 2fr 2fr 2fr 2fr 1fr':'1fr 1fr 2fr 2fr 2fr 2fr 2fr 2fr 1fr' )//根据月份天数判定需要几行}}function findday(y:number,m:number,d:number) {
- let run: Array<number> = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let feirun: Array<number> = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let sum: number = 0;
- let nian: number = 2000;
- let yue: number = 1;
- let ri: number = 1;
- let jujin: number = 0;
- for (let j = nian; j < y; j++) {
- //计算前几年有多少天,需区分是否为闰年
- sum = 0;
- if ((j % 400 == 0) || (j % 4 == 0 && j % 100 != 0)) {
- sum += 366;
- } else {
- sum += 365;
- }
- jujin += sum;
- }
- sum = 0; //计算当年有多少天
- if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0)) {
- for (let i = 0; i < m-1; i++) {
- sum += run[i];
- }
- } else {
- for (let i = 0; i < m-1; i++) {
- sum += feirun[i];
- }
- }
- jujin += sum;
- jujin = (jujin+6) % 7;
- //计算出要显示的日历前面需要空几格
- return jujin;
- }function tian(y:number,m:number,kong:number) {
- let day:Array<string>=new Array (35);
- for(let i=0;i<kong;i++){
- day[i]=" ";
- }//对没有日期的格子填空格
- let d:number;
- let run: Array<number> = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let feirun: Array<number> = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
- let sum: number = 0;
- if ((y % 400 == 0) || (y % 4 == 0 && y % 100 != 0)) {
- d=run[m-1];
- } else {
- d = feirun[m-1];
- }//填充有日期的格子
- let a=0;
- for(let i=kong;i<d+kong;i++){
- a++;
- day[i]=a.toString();
- }
- if(day.length<=35) {
- for (let i = d + kong; i < 35; i++) {
- day[i] = " ";
- }
- }
- else {
- for (let i = d + kong; i < 42; i++) {
- day[i] = " ";
- }
- }//补全剩余空格
- return day;
- //返回day数组给foreach以便进行循环渲染
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |