文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

如何使用vue封装一个自定义日历组件

2023-07-05 19:59

关注

本文小编为大家详细介绍“如何使用vue封装一个自定义日历组件”,内容详细,步骤清晰,细节处理妥当,希望这篇“如何使用vue封装一个自定义日历组件”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

核心代码实现

1、梳理思路

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、根据日历属性生成日历日期的数据

当我们已经知道本月第一天对应的周几索引值本月一共有多少天上个月一共有多少天这三个核心数据之后,就可以开始生成对应的日历数据了。

思路如下

  1. 由于大部分情况下,本月的第一天不是从头开始的,之前的部分是上个月的日期。所以第一行要单独进行处理。

  2. 设置一个公用的date数值,初始值设置为1。然后从本月第一天对应的周几索引值开始进行递增。本月之前的日期和之后的日期设置一个算法进行计算。

  3. 为了方便之后进行日期切换、样式区分,将生成的数据加工成一个对象,其中包含日期类型——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封装一个自定义日历组件

读到这里,这篇“如何使用vue封装一个自定义日历组件”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯