日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

怎么開發一個自定義日歷的vue組件,下面本篇文章就手把手教你如何封裝一個自定義日歷組件,希望對大家有所幫助!


詳解怎么使用vue封裝一個自定義日歷組件


眾所周知啊,一般來說,如果項目中有需要用到日歷組件,往往是找第三方UI庫中的組件來使用,或者是找現成的其他第三方插件。對于很多小伙伴來說,第一眼看到日歷組件,下意識的就會覺得很復雜,無從下手。但是當我閱讀了這個日歷插件的源碼之后,發現并沒有我想象中的復雜。我以前傻傻得認為,想要做一個日歷組件,得需要把距離現在年份前后至少十年的日歷數據都獲取到,然后才能進行下一步的開發。

然而,在我嘗試著閱讀了dycalendar.js這個庫的源碼之后,一方面感覺自己太笨了,把問題想得太復雜了。另外也感慨作者思路之清晰。看完之后感覺受益匪淺。

在將作者的思路邏輯梳理完畢后,我依據這個思路開發了一個vue組件。如下圖所示:


詳解怎么使用vue封裝一個自定義日歷組件


接下來,就隨著我一起看看如何開發一個自己的日歷組件吧。


核心代碼實現

1、梳理思路

獲取到目標日期數據

獲取到當前日期的各項重要屬性,諸如當前年當前月當前日期當前星期幾當前月一共有幾天當前月的第一天對應的是星期幾上個月總共有多少天等。

根據這些屬性,來生成具體的日歷日期數據列表,然后將其循環渲染到模板中。

當切換月份的時候,獲取到新的目標日期對應的各項關鍵數據。vue檢測到日歷屬性變化之后,通知頁面進行更新。

2、初始化所需要的數據

一般來說,成熟的日歷組件,日期都是一個雙向綁定的變量。為了方便使用,我們也采用雙向綁定的方式。

<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;
/**
 * 目標日期
 */
const targetDate = ref(props.modelValue);

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

/**
 * 有關月度的名稱列表
 */
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",
  ],
};
/**
 * 有關周幾的名稱列表
 */
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,
  },
];

接下來,準備幾個vue的響應式數據:

/**
 * 今日
 */
const today = new Date();
/**
 * 日歷的各項屬性
 */
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,
  },
});
/**
 * 用于展現的日歷數據
 */
const calendarData = ref([]);

3、初始化日歷的各項屬性

接下來,通過setCalendarProps方法獲取日歷的各個屬性,逐個填充calendarProps中的數據:

function setCalendarProps() {
  if (!targetDate.value) {
    targetDate.value = today;
  }
  // 獲取目標日期的年月日星期幾數據
  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("無效的年份,請檢查傳入的數據是否是正常");
    return;
  }
  // 獲取到目標日期的月份【中文】名稱
  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];
  // 獲取目標月份的第一天是星期幾,和在星期幾中的索引值
  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
  );
  // 獲取目標月份總共多少天
  const targetMonthLastDay = new Date(
    calendarProps.target.year,
    calendarProps.target.month + 1,
    0
  );
  calendarProps.target.totalDays = targetMonthLastDay.getDate();
  // 獲取目標月份的上個月總共多少天
  const previousMonth = new Date(
    calendarProps.target.year,
    calendarProps.target.month,
    0
  );
  calendarProps.previous.totalDays = previousMonth.getDate();
}

需要注意的一個知識點是,在獲取本月多少天和上個月多少天的時候,都將date值設置為了0。這是因為當date值為0的時候,返回的Date對象是上個月的最后一天。所以說,為了獲取本月多少天,需要將本月的month值加1

執行這個方法之后,此時calendarProps的值為:


詳解怎么使用vue封裝一個自定義日歷組件


4、根據日歷屬性生成日歷日期的數據

當我們已經知道本月第一天對應的周幾索引值本月一共有多少天上個月一共有多少天這三個核心數據之后,就可以開始生成對應的日歷數據了。

思路如下

由于大部分情況下,本月的第一天不是從頭開始的,之前的部分是上個月的日期。所以第一行要單獨進行處理。

設置一個公用的date數值,初始值設置為1。然后從本月第一天對應的周幾索引值開始進行遞增。本月之前的日期和之后的日期設置一個算法進行計算。

為了方便之后進行日期切換、樣式區分,將生成的數據加工成一個對象,其中包含日期類型——dateType,表示是本月還是上月還是下月;

/**
 * 生成日歷的數據
 */
function setCalendarData() {
  let i;
  let date = 1;
  const originData = [];
  const firstRow = [];
  // 設置第一行數據
  for (i = 0; i <= 6; i++) {
    // 設置目標月份之前月份的日期數據
    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 {
      // 設置目標月份當月的日期數據
      firstRow.push({
        dateObj: new Date(
          calendarProps.target.year,
          calendarProps.target.month,
          date
        ),
        dateNumber: date,
        dateType: "current"
      });
      date++;
    }
  }
  originData.push(firstRow);
  // 設置后面五行的數據
  for (let j = 0; j <= 4; j++) {
    const rowData = [];
    for (let k = 0; k <= 6; k++) {
      // 設置目標月份剩下的日期數據
      if (date <= calendarProps.target.totalDays) {
        rowData.push({
          dateObj: new Date(
            calendarProps.target.year,
            calendarProps.target.month,
            date
          ),
          dateNumber: date,
          dateType: "current"
        });
      } else {
        // 設置目標月份下個月的日期數據
        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;
}

至此,這個日歷組件的核心部分的邏輯就已經實現了。你看,是不是很簡單?

接下來,我們只需要根據calendarData中的數據渲染出相應的html模板和添加上樣式就可以了。

5、添加模板和樣式部分

一般來說,日歷組件都是網格狀的結構,所以我選擇table的方式進行渲染。不過你要是問我還有沒有別的方式,那還是有的,比如使用flex布局或者grid布局,但是如果采用這種方式的話,calendarData的數據結構就不是現在這個樣子了。

dom結構如下圖:


詳解怎么使用vue封裝一個自定義日歷組件


至于按鈕邊框的流動效果,是我參照蘇蘇的文章做的,詳情請見:

Clip-path實現按鈕流動邊框動畫 juejin.cn/post/719877…

然后剩下的樣式部分,即興發揮或者根據UI設計圖繪制即可。想必各位都領教過UI姐姐們精美的設計圖吧(嘻嘻

具體的代碼部分就不貼在文章中了,如有需要可以直接查看下方的完整源碼

gitee.com/wushengyuan…


結語

有些感覺很麻煩的組件,可能核心邏輯往往不是那么復雜。有些時候,可能僅僅是需要一些耐心,將代碼一行一行的拆解出來閱讀,理清楚其中的思路。


分享到:
標簽:vue封裝組件 自定義日歷組件
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定