Maison  >  Article  >  interface Web  >  Une analyse approfondie de la façon d'encapsuler un composant de calendrier personnalisé vue

Une analyse approfondie de la façon d'encapsuler un composant de calendrier personnalisé vue

藏色散人
藏色散人avant
2023-04-06 15:12:402208parcourir

Cet article vous apporte des connaissances pertinentes sur les calendriers frontaux. Il explique principalement comment encapsuler un composant de calendrier personnalisé. Les amis intéressés peuvent y jeter un œil ci-dessous.

Avant-propos

Comme nous le savons tous, de manière générale, s'il est nécessaire d'utiliser le composant calendrier dans un projet, il est souvent utilisé par des composants dans des bibliothèques d'interface utilisateur tierces ou par d'autres plug-ins tiers prêts à l'emploi. -ins. Pour de nombreux amis, lorsqu'ils voient pour la première fois le composant calendrier, ils pensent inconsciemment que c'est très compliqué et n'ont aucun moyen de commencer. Mais quand j’ai lu le code source de ce plug-in de calendrier, j’ai découvert que ce n’était pas aussi compliqué que je le pensais. Je pensais bêtement que si je voulais créer un composant de calendrier, je devrais obtenir des données de calendrier pour au moins dix ans avant et après l'année en cours avant de passer à l'étape suivante du développement.

Cependant, après avoir essayé de lire le code source de dycalendar.js, d'une part, j'ai senti que j'étais trop stupide et j'ai pensé au problème trop compliqué. J'admire également la clarté de pensée de l'auteur. Après l'avoir lu, je sens que j'en ai beaucoup bénéficié.

Après avoir débrouillé la logique de l'idée de l'auteur, j'ai développé un composant vue basé sur cette idée. Comme le montre l'image ci-dessous :

Une analyse approfondie de la façon dencapsuler un composant de calendrier personnalisé vue

Ensuite, suivez-moi pour voir comment développer votre propre composant de calendrier.

Implémentation du code de base

1. Triez les idées

  • Obtenez les données de la date cible
  • Obtenez les attributs importants de la date actuelle, tels que année en cours, mois en cours, <code>La date actuelle, Le jour actuel de la semaine, Le nombre de jours du mois en cours, Le premier le jour du mois en cours correspond au jour de la semaine Combien de jours, Combien de jours y avait-il au cours du mois dernier, etc. 当前年当前月当前日期当前星期几当前月一共有几天当前月的第一天对应的是星期几上个月总共有多少天等。
  • 根据这些属性,来生成具体的日历日期数据列表,然后将其循环渲染到模板中。
  • 当切换月份的时候,获取到新的目标日期对应的各项关键数据。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的值为:

Une analyse approfondie de la façon dencapsuler un composant de calendrier personnalisé 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

Sur la base de ces attributs, générez une liste de données de date de calendrier spécifique, puis restituez-la dans le modèle en boucle. 🎜🎜Lorsque vous changez de mois, obtenez les données clés correspondant à la nouvelle date cible. Une fois que vue a détecté des modifications dans les attributs du calendrier, elle demande à la page de la mettre à jour. 🎜

2. Données requises pour l'initialisation🎜🎜De manière générale, dans les composants de calendrier matures, la date est une variable liée dans les deux sens. Pour faciliter l’utilisation, nous utilisons également une reliure bidirectionnelle. 🎜rrreee🎜Ensuite, nous devons également initialiser quelques constantes pour représenter le mois et la date : 🎜rrreee🎜Ensuite, préparez quelques données réactives Vue : 🎜rrreee

3. du calendrier🎜🎜Ensuite, obtenez les différents attributs du calendrier grâce à la méthode setCalendarProps, et remplissez les données dans calendarProps une par une : 🎜rrreee
🎜 Points à noter Un point de connaissance est que lors de l'obtention du nombre de jours de ce mois et du nombre de jours du mois dernier, la valeur de date est définie sur 0. En effet, lorsque la valeur de date est 0, l'objet Date renvoyé est le dernier jour du mois précédent. Par conséquent, afin d'obtenir le nombre de jours de ce mois, vous devez ajouter 1 à la valeur mensuelle de ce mois. 🎜
🎜Après avoir exécuté cette méthode, la valeur de calendarProps est : 🎜🎜Une analyse approfondie de la façon dencapsuler un composant de calendrier personnalisé vue🎜

4. Générer des données de date de calendrier basées sur les attributs du calendrier🎜🎜Quand nous savons les trois valeurs d'indice du jour de la semaine correspondant au premier jour de ce mois, du nombre total de jours de ce mois et du nombre total de jours au cours du mois dernier Après avoir collecté les données de base, vous pouvez commencer à générer les données de calendrier correspondantes. 🎜🎜L'idée est la suivante : 🎜
    🎜Comme dans la plupart des cas, le premier jour du mois ne commence pas depuis le début, la partie précédente est la date du mois précédent. La première ligne doit donc être traitée séparément. 🎜🎜Définissez une valeur de date publique et la valeur initiale est définie sur 1. Commencez ensuite à incrémenter à partir de la valeur de l'indice du jour de la semaine correspondant au premier jour du mois. Définissez un algorithme pour calculer les dates avant et après ce mois. 🎜🎜Afin de faciliter le changement de date et la différenciation de style ultérieurement, les données générées sont traitées dans un objet, qui contient le type de date - dateType, indiquant s'il s'agit de ce mois, du mois précédent ou du suivant. mois ; 🎜 ol>rrreee🎜À ce stade, la logique de base de ce composant de calendrier a été implémentée. Écoutez, n'est-ce pas très simple ? 🎜🎜Ensuite, il nous suffit de restituer le modèle html correspondant et d'ajouter des styles basés sur les données de calendarData. 🎜

    5. Ajoutez le modèle et la partie style

    De manière générale, les composants du calendrier ont une structure de type grille, j'ai donc choisi la méthode du tableau pour le rendu. Mais si vous me demandez s'il existe d'autres moyens, il en existe encore, comme l'utilisation d'une disposition flexible ou d'une disposition en grille, mais si cette méthode est utilisée, la structure des données de calendarData ne sera pas ce qu'elle est actuellement.

    La structure du dom est la suivante :

    Une analyse approfondie de la façon dencapsuler un composant de calendrier personnalisé vue

    En ce qui concerne l'effet fluide de la bordure du bouton, je l'ai réalisé en référence à l'article de Su Su. Pour plus de détails, veuillez consulter :

    Clip-path réalise le flux du bouton. animation de bordurejuejin.cn/post /719877…

    Ensuite, la partie de style restante peut être improvisée ou dessinée selon le dessin de conception de l'interface utilisateur. Je crois que vous avez tous expérimenté les dessins de conception exquis des sœurs de l'interface utilisateur (hee hee

    La partie spécifique du code ne sera pas publiée dans l'article. Si nécessaire, vous pouvez directement consulter le code source complet ci-dessous

    gitee. com/ wushengyuan…

    Conclusion

    Pour certains composants qui semblent gênants, la logique de base n'est peut-être pas si compliquée. Parfois, vous aurez peut-être juste besoin d'un peu de patience pour lire le code ligne par ligne et clarifier les idées

    Recommandé. apprentissage : "tutoriel vidéo vue"

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer