- vừa được xem lúc

Calendar với Reactjs Typescript sử dụng Moment

0 0 21

Người đăng: Huy Đỗ Hửu

Theo Viblo Asia

Hướng dẫn viết logic: trả ra kết quả như hình:

  • Danh sách ngày tháng trước , trong tháng và tháng tới : item trả ra kèm theo loại ngày, ngày hiện tại
  • Chi tiết ngày hiện tại

image.png

  1. Tạo Context API - để chia sẽ dữ liệu
'use client'; import { PropsWithChildren, createContext, useContext } from 'react';
import useLogic from './hook'; type Extra = {}; type ValueCtx = ReturnType<typeof useLogic> & Extra; export const CalendarCtx = createContext({} as ValueCtx); export const CalendarProvider = ({ ...props }: PropsWithChildren<Extra>) => { const valueCtx = useLogic(); return ( <CalendarCtx.Provider value={{ ...valueCtx, ...props }}> <>{props.children}</> </CalendarCtx.Provider> );
}; export const useCalendarCtx = () => useContext(CalendarCtx); 
  1. Tạo Hook - để xử lý logic
'use client'; import moment from 'moment';
import { useState } from 'react';
import { calcDays, dataDate } from './data';
import { onSolar2Lunar } from './lunar'; const useLogic = () => { const [date, setDate] = useState(moment()); const handleReload = () => { setDate(moment()); }; const handlePrev = () => { setDate((element: any) => moment(element).subtract(1, 'month')); }; const handleNext = () => { setDate((element: any) => moment(element).add(1, 'month')); }; const currentLunar = () => { const curdate = dataDate({ date: moment() }); const solar = onSolar2Lunar( curdate.day, curdate.curMonth, curdate.year ); return solar; }; return { date, setDate, listDay: calcDays({ ...dataDate({ date }) }), current: dataDate({ date }), handlePrev, handleNext, handleReload, currentLunar, };
}; export default useLogic; 
  1. Method: Xử lý ngày tháng

import { range } from 'lodash';
import moment, { Moment } from 'moment';
import 'moment/locale/vi';
import { onSolar2Lunar } from './lunar';
import { CalcDays, ItemDay } from './types'; enum DefineDays { DaysOut = 'DaysOut', DaysIn = 'DaysIn',
} export type DataDate = { date: Moment }; export const dataDate = ({ date }: DataDate) => { const day = date.date(); const year = date.year(); // lấy năm hiện tại const month = date.month(); // lấy tháng hiện tại const daysInMonth = date.daysInMonth(); // lấy số ngày trong tháng , ví dụ như 30 ngày const dayOfMonth = moment(date).subtract(1, 'months'); // lấy tháng vừa rồi const dayOf = moment(`${year}-${month + 1}-1`); // tuần đầu tiền của tháng const weekDayOf = dayOf.day(); // số ngày củ cua tháng rồi const dayNew = moment(`${year}-${month + 1}-${daysInMonth}`); // tuần cuối cùng của tháng const weekDayNew = dayNew.day(); // sô ngày mới của tháng tới return { day, year, month, curMonth: month + 1, daysInMonth, dayOfMonth, weekDayOf, weekDayNew, dayNew, };
}; export const calcDays = ({ weekDayOf, dayOfMonth, weekDayNew, daysInMonth, dayNew, year, month,
}: CalcDays) => { // lịch việt thì weekDayOf - 1 , weekDayOf + 1 , // lịch Quốc tế thì weekDayOf , weekDayOf + 1 const daysOld: ItemDay[] = range(weekDayOf - 1).map((item) => { const iday = dayOfMonth.daysInMonth() - weekDayOf + 1 + item + 1; return { daysLunar: onSolar2Lunar(iday, month, year), days: iday, type: DefineDays.DaysOut, daysSolar: { day: iday, month, year, ddmm: `${iday}/${month}`, ddmmyyyy: `${iday}/${month}/${year}`, }, }; }); const days: ItemDay[] = range(daysInMonth).map((item) => { const isToday = moment(`${item + 1}/${month + 1}/${year}`).isSame( moment(), 'day' ); return { daysLunar: onSolar2Lunar(item + 1, month + 1, year), days: item + 1, type: DefineDays.DaysIn, isToday, daysSolar: { day: item + 1, month: month + 1, year, ddmm: `${item + 1}/${month + 1}`, ddmmyyyy: `${item + 1}/${month + 1}/${year}`, } as const, }; }); const daysNew: ItemDay[] = range(6 + 1 - weekDayNew).map(() => { const iday = dayNew.add(1, 'day').date(); return { daysLunar: onSolar2Lunar(iday, month + 2, year), days: iday, type: DefineDays.DaysOut, daysSolar: { day: iday, month: month + 2, year, ddmm: `${iday}/${month + 2}`, ddmmyyyy: `${iday}/${month + 2}/${year}`, }, }; }); return daysOld.concat(days, daysNew);
}; 
  1. Định nghĩa Dữ liệu
import { Moment } from 'moment'; export type CalcDays = { year: number; month: number; daysInMonth: any; dayOfMonth: Moment; weekDayOf: number; weekDayNew: number; dayNew: Moment;
}; export type ItemDay = { daysLunar: LunarType; days: number; type: string; isToday?: boolean; daysSolar?: DaySolarType;
}; export interface LunarType { dd: number; mm: any; yy: number; ix: any; LLLL: string; DM: string;
} export type DaySolarType = { day: number; month: number; year: number; ddmm?: string; ddmmyyyy?: string;
}; 
  1. Tính lịch âm : Lunar
/* eslint-disable id-length */
/* eslint-disable prefer-const */
import { chunk, range } from 'lodash'; export const LOCAL_TIMEZONE = 7.0; export const INT = (d = 0) => { return Math.floor(d);
}; export const MOD = (x = 0, y = 0) => { let z = x - y * Math.floor(x / y); if (z === 0) { z = y; } return z;
}; export const UniversalFromJD = (JD = 0) => { let Z; let A; let B; let C; let D; let E; let F; let alpha; let dd; let mm; let yyyy; Z = INT(JD + 0.5); F = JD + 0.5 - Z; if (Z < 2299161) { A = Z; } else { alpha = INT((Z - 1867216.25) / 36524.25); A = Z + 1 + alpha - INT(alpha / 4); } B = A + 1524; C = INT((B - 122.1) / 365.25); D = INT(365.25 * C); E = INT((B - D) / 30.6001); dd = INT(B - D - INT(30.6001 * E) + F); if (E < 14) { mm = E - 1; } else { mm = E - 13; } if (mm < 3) { yyyy = C - 4715; } else { yyyy = C - 4716; } return { dd, mm, yyyy };
}; export const UniversalToJD = (D = 0, M = 0, Y = 0) => { let JD; if ( Y > 1582 || (Y === 1582 && M > 10) || (Y === 1582 && M === 10 && D > 14) ) { JD = 367 * Y - INT((7 * (Y + INT((M + 9) / 12))) / 4) - INT((3 * (INT((Y + (M - 9) / 7) / 100) + 1)) / 4) + INT((275 * M) / 9) + D + 1721028.5; } else { JD = 367 * Y - INT((7 * (Y + 5001 + INT((M - 9) / 7))) / 4) + INT((275 * M) / 9) + D + 1729776.5; } return JD;
}; export const LocalFromJD = (JD = 0) => { return UniversalFromJD(JD + LOCAL_TIMEZONE / 24.0);
};
export const LocalToJD = (D = 0, M = 0, Y = 0) => { return UniversalToJD(D, M, Y) - LOCAL_TIMEZONE / 24.0;
}; export const { PI } = Math; export const NewMoon = (k = 0) => { const T = k / 1236.85; const T2 = T * T; const T3 = T2 * T; const dr = PI / 180; let Jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * T2 - 0.000000155 * T3; Jd1 = Jd1 + 0.00033 * Math.sin((166.56 + 132.87 * T - 0.009173 * T2) * dr); // Mean new moon const M = 359.2242 + 29.10535608 * k - 0.0000333 * T2 - 0.00000347 * T3; // Sun's mean anomaly const Mpr = 306.0253 + 385.81691806 * k + 0.0107306 * T2 + 0.00001236 * T3; // Moon's mean anomaly const F = 21.2964 + 390.67050646 * k - 0.0016528 * T2 - 0.00000239 * T3; // Moon's argument of latitude let C1 = (0.1734 - 0.000393 * T) * Math.sin(M * dr) + 0.0021 * Math.sin(2 * dr * M); C1 = C1 - 0.4068 * Math.sin(Mpr * dr) + 0.0161 * Math.sin(dr * 2 * Mpr); C1 = C1 - 0.0004 * Math.sin(dr * 3 * Mpr); C1 = C1 + 0.0104 * Math.sin(dr * 2 * F) - 0.0051 * Math.sin(dr * (M + Mpr)); C1 = C1 - 0.0074 * Math.sin(dr * (M - Mpr)) + 0.0004 * Math.sin(dr * (2 * F + M)); C1 = C1 - 0.0004 * Math.sin(dr * (2 * F - M)) - 0.0006 * Math.sin(dr * (2 * F + Mpr)); C1 = C1 + 0.001 * Math.sin(dr * (2 * F - Mpr)) + 0.0005 * Math.sin(dr * (2 * Mpr + M)); let deltat; if (T < -11) { deltat = 0.001 + 0.000839 * T + 0.0002261 * T2 - 0.00000845 * T3 - 0.000000081 * T * T3; } else { deltat = -0.000278 + 0.000265 * T + 0.000262 * T2; } const JdNew = Jd1 + C1 - deltat; return JdNew;
}; export const SunLongitude = (jdn = 0) => { const T = (jdn - 2451545.0) / 36525; // Time in Julian centuries from 2000-01-01 12:00:00 GMT const T2 = T * T; const dr = PI / 180; // degree to radian const M = 357.5291 + 35999.0503 * T - 0.0001559 * T2 - 0.00000048 * T * T2; // mean anomaly, degree const L0 = 280.46645 + 36000.76983 * T + 0.0003032 * T2; // mean longitude, degree let DL = (1.9146 - 0.004817 * T - 0.000014 * T2) * Math.sin(dr * M); DL = DL + (0.019993 - 0.000101 * T) * Math.sin(dr * 2 * M) + 0.00029 * Math.sin(dr * 3 * M); let L = L0 + DL; // true longitude, degree L = L * dr; L = L - PI * 2 * INT(L / (PI * 2)); // Normalize to (0, 2*PI) return L;
}; export const LunarMonth11 = (Y = 0) => { const off = LocalToJD(31, 12, Y) - 2415021.076998695; const k = INT(off / 29.530588853); let jd = NewMoon(k); const ret = LocalFromJD(jd); const sunLong = SunLongitude(LocalToJD(ret.dd, ret.mm, ret.yyyy)); // sun longitude at local midnight if (sunLong > (3 * PI) / 2) { jd = NewMoon(k - 1); } return LocalFromJD(jd);
}; export const initLeapYear = (ret: any) => { const sunLongitudes = [ret.length]; for (let index = 0; index < ret.length; index++) { const a = ret[index]; const jdAtMonthBegin = LocalToJD(a[0], a[1], a[2]); sunLongitudes[index] = SunLongitude(jdAtMonthBegin); } let found = false; for (let index = 0; index < ret.length; index++) { if (found) { ret[index][3] = MOD(index + 10, 12); continue; } const sl1 = sunLongitudes[index]; const sl2 = sunLongitudes[index + 1]; const hasMajorTerm = Math.floor((sl1 / PI) * 6) !== Math.floor((sl2 / PI) * 6); if (!hasMajorTerm) { found = true; ret[index][4] = 1; ret[index][3] = MOD(index + 10, 12); } }
}; export const LunarYear = (Y = 0) => { let ret: any = chunk(range(13 * 5), 5); const month11A = LunarMonth11(Y - 1); const jdMonth11A = LocalToJD(month11A.dd, month11A.mm, month11A.yyyy); const k = Math.floor(0.5 + (jdMonth11A - 2415021.076998695) / 29.530588853); const month11B = LunarMonth11(Y); const off = LocalToJD(month11B.dd, month11B.mm, month11B.yyyy) - jdMonth11A; const leap = off > 365.0; if (!leap) { ret = chunk(range(13 * 5), 5); } ret[0] = [month11A.dd, month11A.mm, month11A.yyyy, 0, 0]; ret[ret.length - 1] = [month11B.dd, month11B.mm, month11B.yyyy, 0, 0]; for (let index = 1; index < ret.length - 1; index++) { const nm = NewMoon(k + index); const a = LocalFromJD(nm); ret[index] = [a.dd, a.mm, a.yyyy, 0, 0]; } for (let index = 0; index < ret.length; index++) { ret[index][3] = MOD(index + 11, 12); } if (leap) { initLeapYear(ret); } return ret;
}; // dương sang âm
export const onSolar2Lunar = (D = 0, M = 0, Y = 0) => { let yy = Y; let ly = LunarYear(Y); const month11 = ly[ly.length - 1]; const jdToday = LocalToJD(D, M, Y); const jdMonth11 = LocalToJD(month11[0], month11[1], month11[2]); if (jdToday >= jdMonth11) { ly = LunarYear(Y + 1); yy = Y + 1; } let index = Number(ly.length - 1); while (jdToday < LocalToJD(ly[index][0], ly[index][1], ly[index][2])) { index--; } const dd = jdToday - LocalToJD(ly[index][0], ly[index][1], ly[index][2]) + 1; const mm = ly[index][3]; if (mm >= 11) { yy--; } const ix = ly[index][4]; return { dd, mm, yy, ix, LLLL: `${dd}/${mm}/${yy}`, DM: `${dd}/${mm}`, };
}; // âm sang dương
export const Lunar2Solar = (D = 0, M = 0, Y = 0, leap = 0) => { let yy = Y; if (M >= 11) { yy = Y + 1; } const lunarYear = LunarYear(yy); let lunarMonth = null; for (const index of lunarYear) { const lm = lunarYear[index]; if (lm[3] === M && lm[4] === leap) { lunarMonth = lm; break; } } if (lunarMonth != null) { const jd = LocalToJD(lunarMonth[0], lunarMonth[1], lunarMonth[2]); return LocalFromJD(jd + D - 1); } else { return null; }
}; 

Rất đơn giản đúng hông, tính sẳn hết rùi.

Phần tiếp theo là Countdown

Bình luận

Bài viết tương tự

- vừa được xem lúc

FSCalendar - Paging nội dung theo ngày.

FSCalendar là gì. Mọi người thể tìm hiểu thêm tại đây. https://github.com/WenchaoD/FSCalendar.

0 0 34

- vừa được xem lúc

Calendar UI Design with Dark Mode and Animation Using HTML CSS JavaScript

Calendar UI Design with Dark Mode and Animation Using HTML CSS JavaScript. . In this video, we will make calendar using HTML CSS and JavaScript. Dark mode and animation included.

0 0 67

- vừa được xem lúc

Hướng dẫn viết Testcase cho dropdownlist date time Calendar

Bài viết dưới đây chia sẻ cho các bạn QA/ Tester mới vào nghề bộ TCs cho trường cho trường ngày tháng năm. .

0 0 18

- vừa được xem lúc

Những điều cần lưu ý và sử dụng Hook trong React (Phần 5)

V. Sử dụng useRef như thế nào cho đúng.

0 0 140

- vừa được xem lúc

7 Cách viết code React "clean" hơn

Mở đầu. Là nhà phát triển React, tất cả chúng ta đều muốn viết code sạch hơn, đơn giản hơn và dễ đọc hơn. 1. Sử dụng JSX shorthands.

0 0 199

- vừa được xem lúc

Create app covid-19 use Reactjs

Chào các bạn hôm nay mình sẽ chia sẻ với các bạn một app covid-19, để mọi người cùng tham khảo, tính năng của App này chỉ đơn giản là show số liệu về dịch Covid của các nước trên thế giới như: Số ngườ

0 0 55