Heim  >  Artikel  >  Web-Frontend  >  Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird

Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird

藏色散人
藏色散人nach vorne
2023-04-06 15:12:402208Durchsuche

Dieser Artikel vermittelt Ihnen relevantes Wissen über Front-End-Kalender. Es geht hauptsächlich darum, wie man eine benutzerdefinierte Kalenderkomponente kapselt. Ich hoffe, dass er für alle hilfreich ist.

Vorwort

Wie wir alle wissen, wird die Kalenderkomponente bei Bedarf in einem Projekt im Allgemeinen häufig von Komponenten in UI-Bibliotheken von Drittanbietern oder anderen vorgefertigten Plug-Ins von Drittanbietern verwendet -ins. Wenn viele Freunde die Kalenderkomponente zum ersten Mal sehen, denken sie unbewusst, dass sie sehr kompliziert ist und keinen Einstieg finden. Aber als ich den Quellcode dieses Kalender-Plug-Ins las, stellte ich fest, dass es nicht so kompliziert war, wie ich dachte. Früher dachte ich törichterweise, wenn ich eine Kalenderkomponente erstellen wollte, müsste ich Kalenderdaten für mindestens zehn Jahre vor und nach dem aktuellen Jahr erhalten, bevor ich mit dem nächsten Entwicklungsschritt fortfahren konnte.

Nachdem ich jedoch versucht hatte, den Quellcode von dycalendar.js zu lesen, hatte ich einerseits das Gefühl, dass ich zu dumm war und das Problem für zu kompliziert hielt. Ich bewundere auch die klare Denkweise des Autors. Nachdem ich es gelesen hatte, hatte ich das Gefühl, dass es mir sehr geholfen hat.

Nachdem ich die Ideenlogik des Autors geklärt hatte, entwickelte ich eine Vue-Komponente basierend auf dieser Idee. Wie im Bild unten gezeigt:

Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird

Folgen Sie mir als Nächstes, um zu sehen, wie Sie Ihre eigene Kalenderkomponente entwickeln.

Kerncode-Implementierung

1. Sortieren Sie die Ideen

  • Erhalten Sie die Zieldatumsdaten
  • Erhalten Sie die wichtigen Attribute des aktuellen Datums, z. B. aktuelles Jahr, aktueller Monat, <code>Das aktuelle Datum, Der aktuelle Wochentag, Die Anzahl der Tage im aktuellen Monat, Der erste Der Tag des aktuellen Monats entspricht dem Wochentag. Wie viele Tage, Wie viele Tage gab es im letzten Monat usw. 当前年当前月当前日期当前星期几当前月一共有几天当前月的第一天对应的是星期几上个月总共有多少天等。
  • 根据这些属性,来生成具体的日历日期数据列表,然后将其循环渲染到模板中。
  • 当切换月份的时候,获取到新的目标日期对应的各项关键数据。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的值为:

Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird

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

Generieren Sie basierend auf diesen Attributen eine bestimmte Kalenderdatumsdatenliste und rendern Sie sie dann in einer Schleife in die Vorlage. 🎜🎜Besorgen Sie sich beim Monatswechsel die Eckdaten zum neuen Zieldatum. Nachdem Vue Änderungen in Kalenderattributen erkennt, wird die Benachrichtigungsseite aktualisiert. 🎜

2. Für die Initialisierung erforderliche Daten🎜🎜Im Allgemeinen ist das Datum in ausgereiften Kalenderkomponenten eine bidirektional gebundene Variable. Aus Gründen der Benutzerfreundlichkeit verwenden wir auch eine Zwei-Wege-Bindung. 🎜rrreee🎜Als nächstes müssen wir auch einige Konstanten initialisieren, um den Monat und das Datum darzustellen: 🎜rrreee🎜Als nächstes bereiten wir einige Vue-Reaktionsdaten vor: 🎜rrreee

3 Initialisieren Sie die verschiedenen Attribute des Kalenders🎜🎜Als nächstes erhalten Sie die verschiedenen Attribute des Kalenders über die Methode setCalendarProps und geben die Daten nacheinander in calendarProps ein: 🎜rrreee
🎜 Zu beachtende Dinge Ein Wissenspunkt ist, dass bei der Ermittlung der Anzahl der Tage in diesem Monat und der Anzahl der Tage im letzten Monat der Datumswert auf 0 gesetzt wird. Dies liegt daran, dass das zurückgegebene Datumsobjekt der letzte Tag des vorherigen Monats ist, wenn der Datumswert 0 ist. Um die Anzahl der Tage in diesem Monat zu erhalten, müssen Sie daher 1 zum Monatswert dieses Monats hinzufügen. 🎜
🎜Nach der Ausführung dieser Methode ist der Wert von calendarProps: 🎜🎜Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird🎜

4. Generieren Sie Kalenderdatumsdaten basierend auf Kalenderattributen🎜🎜Wenn wir wissen der Indexwert des Wochentags, der dem ersten Tag dieses Monats entspricht, die Gesamtzahl der Tage in diesem Monat und die Gesamtzahl der Tage in den letzten Monat Nach dem Sammeln der Kerndaten können Sie mit der Generierung der entsprechenden Kalenderdaten beginnen. 🎜🎜Die Idee ist wie folgt: 🎜
    🎜Da der erste Tag des Monats in den meisten Fällen nicht von vorne beginnt, ist der vorherige Teil das Datum des Vormonats. Daher muss die erste Zeile separat verarbeitet werden. 🎜🎜Legen Sie einen öffentlichen Datumswert fest und der Anfangswert wird auf 1 gesetzt. Beginnen Sie dann mit der Erhöhung ab dem Indexwert für den Wochentag, der dem ersten Tag des Monats entspricht. Legen Sie einen Algorithmus fest, um Daten vor und nach diesem Monat zu berechnen. 🎜🎜Um den Datumswechsel und die Stilunterscheidung später zu erleichtern, werden die generierten Daten in einem Objekt verarbeitet, das den Datumstyp dateType enthält und angibt, ob es sich um diesen Monat, den vorherigen Monat oder den nächsten handelt Monat; 🎜 ol>rrreee🎜An diesem Punkt wurde die Kernlogik dieser Kalenderkomponente implementiert. Sehen Sie, ist das nicht ganz einfach? 🎜🎜Als nächstes müssen wir nur noch die entsprechende HTML-Vorlage rendern und Stile basierend auf den Daten in calendarData hinzufügen. 🎜

    5. Fügen Sie den Vorlagen- und Stilteil hinzu

    Im Allgemeinen haben Kalenderkomponenten eine gitterartige Struktur, daher wähle ich die Tabellenmethode zum Rendern. Wenn Sie mich jedoch fragen, ob es andere Möglichkeiten gibt, gibt es immer noch einige, z. B. die Verwendung eines Flex-Layouts oder eines Raster-Layouts. Wenn diese Methode jedoch verwendet wird, ist die Datenstruktur von calendarData nicht mehr so, wie sie jetzt ist.

    Die Dom-Struktur ist wie folgt:

    Eine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird

    Was den fließenden Effekt des Knopfrandes betrifft, habe ich ihn unter Bezugnahme auf den Artikel von Su Su erstellt, siehe:

    Clip-Pfad realisiert den Knopffluss Randanimationjuejin.cn/post /719877…

    Dann kann der verbleibende Stilteil improvisiert oder gemäß der UI-Designzeichnung gezeichnet werden. Ich glaube, Sie alle haben die exquisiten Designzeichnungen der UI-Schwestern erlebt (hee hee

    Der spezifische Codeteil wird nicht im Artikel veröffentlicht. Bei Bedarf können Sie den vollständigen Quellcode unten direkt anzeigen

    gitee. com/ wushengyuan…

    Fazit

    Bei einigen Komponenten, die sich problematisch anfühlen, ist die Kernlogik möglicherweise nicht so kompliziert. Manchmal braucht man einfach etwas Geduld, um den Code Zeile für Zeile zu lesen und die Ideen zu klären

    Empfohlen Lernen: „vue Video-Tutorial

Das obige ist der detaillierte Inhalt vonEine ausführliche Analyse, wie eine benutzerdefinierte Vue-Kalenderkomponente gekapselt wird. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen