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.
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:
Folgen Sie mir als Nächstes, um zu sehen, wie Sie Ihre eigene Kalenderkomponente entwickeln.
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. 当前年
,当前月
,当前日期
,当前星期几
,当前月一共有几天
,当前月的第一天对应的是星期几
,上个月总共有多少天
等。
日历日期数据列表
,然后将其循环渲染到模板中。一般来说,成熟的日历组件,日期都是一个双向绑定的变量。为了方便使用,我们也采用双向绑定的方式。
<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([]);
接下来,通过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
的值为:
当我们已经知道本月第一天对应的周几索引值、本月一共有多少天和上个月一共有多少天这三个核心数据之后,就可以开始生成对应的日历数据了。
思路如下:
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
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. 🎜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🎜Nach der Ausführung dieser Methode ist der Wert von0
gesetzt wird. Dies liegt daran, dass das zurückgegebene Datumsobjekt der letzte Tag des vorherigen Monats ist, wenn der Datumswert0
ist. Um die Anzahl der Tage in diesem Monat zu erhalten, müssen Sie daher1
zum Monatswert dieses Monats hinzufügen. 🎜
calendarProps
: 🎜🎜🎜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. 🎜 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:
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
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!