溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么封裝一個(gè)vue自定義日歷組件

發(fā)布時(shí)間:2023-04-13 10:08:13 來(lái)源:億速云 閱讀:126 作者:iii 欄目:編程語(yǔ)言

這篇文章主要介紹“怎么封裝一個(gè)vue自定義日歷組件”,在日常操作中,相信很多人在怎么封裝一個(gè)vue自定義日歷組件問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么封裝一個(gè)vue自定義日歷組件”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

核心代碼實(shí)現(xiàn)

1、梳理思路

  • 獲取到目標(biāo)日期數(shù)據(jù)

  • 獲取到當(dāng)前日期的各項(xiàng)重要屬性,諸如當(dāng)前年,當(dāng)前月當(dāng)前日期,當(dāng)前星期幾,當(dāng)前月一共有幾天,當(dāng)前月的第一天對(duì)應(yīng)的是星期幾上個(gè)月總共有多少天等。

  • 根據(jù)這些屬性,來(lái)生成具體的日歷日期數(shù)據(jù)列表,然后將其循環(huán)渲染到模板中。

  • 當(dāng)切換月份的時(shí)候,獲取到新的目標(biāo)日期對(duì)應(yīng)的各項(xiàng)關(guān)鍵數(shù)據(jù)。vue檢測(cè)到日歷屬性變化之后,通知頁(yè)面進(jìn)行更新。

2、初始化所需要的數(shù)據(jù)

一般來(lái)說(shuō),成熟的日歷組件,日期都是一個(gè)雙向綁定的變量。為了方便使用,我們也采用雙向綁定的方式。

<script setup>
import { reactive, ref, computed, watch } from "vue";

const props = defineProps({
 modelValue: Date,
});

const emits = defineEmits(["update:modelValue"]);

/**
* 最小年份
*/
const MIN_YEAR = 1900;
/**
* 最大年份
*/
const MAX_YEAR = 9999;

/**
* 目標(biāo)日期
*/
const targetDate = ref(props.modelValue);

接下來(lái),我們還需要初始化一些常量用來(lái)表示月份和日期:

/**
* 有關(guān)月度的名稱列表
*/
const monthNameList = {
 chineseFullName: [
   "一月",
   "二月",
   "三月",
   "四月",
   "五月",
   "六月",
   "七月",
   "八月",
   "九月",
   "十月",
   "十一月",
   "十二月",
 ],
 fullName: [
   "January",
   "February",
   "March",
   "April",
   "May",
   "June",
   "July",
   "August",
   "September",
   "October",
   "November",
   "December",
 ],
 mmm: [
   "Jan",
   "Feb",
   "Mar",
   "Apr",
   "May",
   "Jun",
   "Jul",
   "Aug",
   "Sep",
   "Oct",
   "Nov",
   "Dec",
 ],
};
/**
* 有關(guān)周幾的名稱列表
*/
const dayNameList = [
 {
   chineseFullName: "周日",
   chineseShortName: "日",
   fullName: "Sunday",
   shortName: "Sun",
   dayNumber: 0,
 },
 {
   chineseFullName: "周一",
   chineseShortName: "一",
   fullName: "Monday",
   shortName: "Mon",
   dayNumber: 1,
 },
 {
   chineseFullName: "周二",
   chineseShortName: "二",
   fullName: "Tuesday",
   shortName: "Tue",
   dayNumber: 2,
 },
 {
   chineseFullName: "周三",
   chineseShortName: "三",
   fullName: "Wednesday",
   shortName: "Wed",
   dayNumber: 3,
 },
 {
   chineseFullName: "周四",
   chineseShortName: "四",
   fullName: "Thursday",
   shortName: "Thu",
   dayNumber: 4,
 },
 {
   chineseFullName: "周五",
   chineseShortName: "五",
   fullName: "Friday",
   shortName: "Fri",
   dayNumber: 5,
 },
 {
   chineseFullName: "周六",
   chineseShortName: "六",
   fullName: "Saturday",
   shortName: "Sat",
   dayNumber: 6,
 },
];

接下來(lái),準(zhǔn)備幾個(gè)vue的響應(yīng)式數(shù)據(jù):

/**
* 今日
*/
const today = new Date();

/**
* 日歷的各項(xiàng)屬性
*/
const calendarProps = reactive({
 target: {
   year: null,
   month: null,
   date: null,
   day: null,
   monthShortName: null,
   monthFullName: null,
   monthChineseFullName: null,
   firstDay: null,
   firstDayIndex: null,
   totalDays: null,
 },
 previous: {
   totalDays: null,
 },
});

/**
* 用于展現(xiàn)的日歷數(shù)據(jù)
*/
const calendarData = ref([]);

3、初始化日歷的各項(xiàng)屬性

接下來(lái),通過(guò)setCalendarProps方法獲取日歷的各個(gè)屬性,逐個(gè)填充calendarProps中的數(shù)據(jù):

function setCalendarProps() {
 if (!targetDate.value) {
   targetDate.value = today;
 }
 // 獲取目標(biāo)日期的年月日星期幾數(shù)據(jù)
 calendarProps.target.year = targetDate.value.getFullYear();
 calendarProps.target.month = targetDate.value.getMonth();
 calendarProps.target.date = targetDate.value.getDate();
 calendarProps.target.day = targetDate.value.getDay();

 if (
   calendarProps.target.year < MIN_YEAR ||
   calendarProps.target.year > MAX_YEAR
 ) {
   console.error("無(wú)效的年份,請(qǐng)檢查傳入的數(shù)據(jù)是否是正常");
   return;
 }

 // 獲取到目標(biāo)日期的月份【中文】名稱
 let dateString;
 dateString = targetDate.value.toString().split(" ");
 calendarProps.target.monthShortName = dateString[1];
 calendarProps.target.monthFullName =
   monthNameList.fullName[calendarProps.target.month];
 calendarProps.target.monthChineseFullName =
   monthNameList.chineseFullName[calendarProps.target.month];
 // 獲取目標(biāo)月份的第一天是星期幾,和在星期幾中的索引值
 const targetMonthFirstDay = new Date(
   calendarProps.target.year,
   calendarProps.target.month,
   1
 );
 calendarProps.target.firstDay = targetMonthFirstDay.getDay();
 calendarProps.target.firstDayIndex = dayNameList.findIndex(
   (day) => day.dayNumber === calendarProps.target.firstDay
 );

 // 獲取目標(biāo)月份總共多少天
 const targetMonthLastDay = new Date(
   calendarProps.target.year,
   calendarProps.target.month + 1,
   0
 );
 calendarProps.target.totalDays = targetMonthLastDay.getDate();

 // 獲取目標(biāo)月份的上個(gè)月總共多少天
 const previousMonth = new Date(
   calendarProps.target.year,
   calendarProps.target.month,
   0
 );
 calendarProps.previous.totalDays = previousMonth.getDate();
}

需要注意的一個(gè)知識(shí)點(diǎn)是,在獲取本月多少天和上個(gè)月多少天的時(shí)候,都將date值設(shè)置為了0。這是因?yàn)楫?dāng)date值為0的時(shí)候,返回的Date對(duì)象是上個(gè)月的最后一天。所以說(shuō),為了獲取本月多少天,需要將本月的month值加1。

執(zhí)行這個(gè)方法之后,此時(shí)calendarProps的值為:

怎么封裝一個(gè)vue自定義日歷組件

4、根據(jù)日歷屬性生成日歷日期的數(shù)據(jù)

當(dāng)我們已經(jīng)知道本月第一天對(duì)應(yīng)的周幾索引值、本月一共有多少天上個(gè)月一共有多少天這三個(gè)核心數(shù)據(jù)之后,就可以開(kāi)始生成對(duì)應(yīng)的日歷數(shù)據(jù)了。

思路如下

  1. 由于大部分情況下,本月的第一天不是從頭開(kāi)始的,之前的部分是上個(gè)月的日期。所以第一行要單獨(dú)進(jìn)行處理。

  2. 設(shè)置一個(gè)公用的date數(shù)值,初始值設(shè)置為1。然后從本月第一天對(duì)應(yīng)的周幾索引值開(kāi)始進(jìn)行遞增。本月之前的日期和之后的日期設(shè)置一個(gè)算法進(jìn)行計(jì)算。

  3. 為了方便之后進(jìn)行日期切換、樣式區(qū)分,將生成的數(shù)據(jù)加工成一個(gè)對(duì)象,其中包含日期類型——dateType,表示是本月還是上月還是下月;

/**
* 生成日歷的數(shù)據(jù)
*/
function setCalendarData() {
 let i;
 let date = 1;
 const originData = [];
 const firstRow = [];
 // 設(shè)置第一行數(shù)據(jù)
 for (i = 0; i <= 6; i++) {
   // 設(shè)置目標(biāo)月份之前月份的日期數(shù)據(jù)
   if (i < calendarProps.target.firstDayIndex) {
     const previousDate =
       calendarProps.previous.totalDays -
       calendarProps.target.firstDayIndex +
       (i + 1);
     firstRow.push({
       dateObj: new Date(
         calendarProps.target.year,
         calendarProps.target.month - 1,
         previousDate
       ),
       dateNumber: previousDate,
       dateType: "previous"
     });
   } else {
     // 設(shè)置目標(biāo)月份當(dāng)月的日期數(shù)據(jù)
     firstRow.push({
       dateObj: new Date(
         calendarProps.target.year,
         calendarProps.target.month,
         date
       ),
       dateNumber: date,
       dateType: "current"
     });
     date++;
   }
 }
 originData.push(firstRow);
 // 設(shè)置后面五行的數(shù)據(jù)
 for (let j = 0; j <= 4; j++) {
   const rowData = [];
   for (let k = 0; k <= 6; k++) {
     // 設(shè)置目標(biāo)月份剩下的日期數(shù)據(jù)
     if (date <= calendarProps.target.totalDays) {
       rowData.push({
         dateObj: new Date(
           calendarProps.target.year,
           calendarProps.target.month,
           date
         ),
         dateNumber: date,
         dateType: "current"
       });
     } else {
       // 設(shè)置目標(biāo)月份下個(gè)月的日期數(shù)據(jù)
       const nextDate = date - calendarProps.target.totalDays;
       rowData.push({
         dateObj: new Date(
           calendarProps.target.year,
           calendarProps.target.month + 1,
           nextDate
         ),
         dateNumber: nextDate,
         dateType: "next"
       });
     }
     date++;
   }
   originData.push(rowData);
 }
 calendarData.value = originData;
}

至此,這個(gè)日歷組件的核心部分的邏輯就已經(jīng)實(shí)現(xiàn)了。你看,是不是很簡(jiǎn)單?

接下來(lái),我們只需要根據(jù)calendarData中的數(shù)據(jù)渲染出相應(yīng)的html模板和添加上樣式就可以了。

5、添加模板和樣式部分

一般來(lái)說(shuō),日歷組件都是網(wǎng)格狀的結(jié)構(gòu),所以我選擇table的方式進(jìn)行渲染。不過(guò)你要是問(wèn)我還有沒(méi)有別的方式,那還是有的,比如使用flex布局或者grid布局,但是如果采用這種方式的話,calendarData的數(shù)據(jù)結(jié)構(gòu)就不是現(xiàn)在這個(gè)樣子了。

dom結(jié)構(gòu)如下圖:

怎么封裝一個(gè)vue自定義日歷組件

到此,關(guān)于“怎么封裝一個(gè)vue自定義日歷組件”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

vue
AI