Betriebswirtschaftlicher HintergrundLassen Sie mich zunächst kurz das Geschäftsszenario beschreiben. Es ruft die Zeitplaninformationen des Benutzers in Bürosoftware wie WeChat for Enterprise oder DingTalk ab und zeigt den Zeitplan im Web an. Wenn ein Zeitplankonflikt vorliegt, wird der Zeitplan des Konflikttages angezeigt, sodass der Planer den Zeitplan sinnvoll anordnen kann, um Konflikte zu vermeiden, wie in der Abbildung dargestellt. Technologie nutzen
Technische Schwierigkeiten
Gestaltungsideen 😱 Ein Gesicht voller Verwirrung und SchmerzBei der Entwicklung des Projekts habe ich dieselbe Komponentenbibliothek wie antd verwendet. Nachdem ich sie überprüft hatte, ging ich unbewusst zu antd, um zu sehen, ob es Komponenten gab, die sofort verwendet werden konnten. Leider!!! Es gibt keine solche wöchentliche oder tägliche Filterkomponente. Ich bin so verärgert. Alibaba hat so viele Komponenten geschrieben, warum haben sie diese übersehen? Also wandte ich mich an Baidu, den Allmächtigen, um zu prüfen, ob es verwandte Komponenten gab. Später fand ich die Komponente „fullcalendar“, aber ich hatte nicht einmal die Dokumentation oder Demo gelesen. Ich beschloss entschlossen, selbst eine zu schreiben! Zusammenfassend gibt es mehrere Gründe:
🙄Fang an zu denkenEigentlich wollte ich mich, als ich mit dem Konzipieren begann, auch auf das API-Design hervorragender Komponenten beziehen. Einige Komponenten sind jedoch wirklich schwer zu verwenden, und ich verstehe nicht, warum sie auf diese Weise geschrieben sind. Also habe ich aus der Perspektive eines Benutzers darüber nachgedacht und bin immer noch der Meinung, dass ich es gemäß meiner eigenen Aufrufmethode als 18.-klassiger, niedrigrangiger und faulster Programmierer entwerfen sollte - es kann sofort verwendet werden. Ein weiterer wichtiger Punkt ist die Entkopplung vom Business, sodass andere Projekte es direkt nutzen können. Warum nicht? Also habe ich den ganzen Morgen damit verbracht, einen Entwurf basierend auf meinen eigenen Ideen zu zeichnen: Dies wurde mit ProcessOn gezeichnet. Ich verwende es nicht oft, daher ist die Zeichnung nicht sehr gut. Bitte verzeihen Sie mir! 🌲Verzeichnisstruktur
🛠 Komponenten aufteilen Bei genauer Betrachtung des Bildes ist leicht zu erkennen, dass ich das Bauteil in drei Teile aufgeteilt habe:
CalendatrHeader-Header-Containerkomponente: eine Unterkomponente des Container-Containers. Diese Komponente ist für das Umschalten von Daten und das Ändern des Komponentenstatus Woche und Tag verantwortlich. Diese Komponente enthält die Kalenderkomponente, die Wochenkomponente, die Datumsfilterkomponente, die Tages- und Wochenumschaltkomponente, die Heute-Schaltflächenkomponente und schließlich einen Geschäftskomponentencontainer (businessRender). ScheduleCantainer-Zeitplancontainerkomponente: Diese Komponente wird von 25 ScheduleRender-Komponenten unterstützt (da es von 0:00 heute bis 0:00 nächsten Morgen geht) und ihre Unterkomponenten umfassen auch Zeitskalenkomponenten;
Dies ist die grobe Aufteilung der Komponenten. Der Text reicht nicht aus, aber Sie können ihn mit Bildern kombinieren. Als nächstes legen wir los!!! Code-ImplementierungSchauen wir uns zunächst die Definition der akzeptierten Parametertypen an: Typ Datentyp = { startTime: DOMTimeStamp; // Startzeitstempel endTime: DOMTimeStamp; // Endzeitstempel [propsName: string]: beliebig; // Geschäftsdaten }; Typ ContainerTyp = { data: dataType[]; // Geschäftsdaten initDay?: DOMTimeStamp; // Initialisierungszeitstempel onChange?: (params: DOMTimeStamp) => void; // onChange-Methode beim Ändern des Datums height?: number; // Die Höhe des ScheduleCantainer-Containers scheduleRender?: ({ Daten: Datentyp, Zeitstempelbereich: [DOMTimeStamp, DOMTimeStamp], }) => JSX.Element; // Der übergebene Rückruf empfängt die Geschäftsdaten der aktuellen Daten und den Zeitstempelbereich der aktuellen Geschäftsdaten; businessRender?: ({ timestamp: DOMTimeStamp }) => React.ReactNode; // Die übergebene Geschäftskomponente, frage das Front-End ab. Cai Xukun, sieh dir das Bild an, erinnerst du dich daran? Modus?: „Tag“ | „Woche“; // Initialisiere den Anzeigemodus von Tag und Woche}; ContainerCode: const Container: React.FC<ContainerType> = ({ initDay, beiÄnderung, ZeitplanRender, businessRender, Daten, Höhe = 560, Modus = "Tag", }) => { //Aktuell ausgewählter Datumszeitstempel const [targetDay, setTargetDay] = useState<DOMTimeStamp>(initDay); // Tag und Woche wechseln const [switchWeekandDay, setSwitchWeekandDay] = useState<'day' | 'week'>(mode); zurückkehren ( <div Klassenname = {style.Calendar_Container}> <CalendatrHeader Zieltag = {Zieltag} setTargetDay={(Zeitstempel) => { beiÄnderung(Zeitstempel); setTargetDay(Zeitstempel); }} businessRender={businessRender} switchWeekandDay={switchWeekandDay} setSwitchWeekandDay={setSwitchWeekandDay} /> <FahrplanContainer Höhe={Höhe} Daten={Daten} Zieltag = {Zieltag} scheduleRender={scheduleRender} /> </div> ); }; Wenn Sie sich den Code ansehen, können Sie darüber nachdenken. Es ist definitiv notwendig, die globalen Statusdaten zur Steuerung auf die höchste Ebene zu heben, was auch der Komponentendesignphilosophie von React entspricht. Behält den aktuellen Zeitstempel und Tages-/Wochenstatus bei, und der Status aller Unterkomponenten wird basierend auf dem Zieltag angezeigt. CalendatrHeader-Header-ContainerkomponenteIch denke, der Rest des Header-Containers ist in Ordnung. Da der Wochentag festgelegt ist (hauptsächlich bezogen auf die Kalenderkomponente von Apple, der Wochentag von Apple hat sich nicht geändert, daher verweise ich auf das hervorragende Design großer Hersteller), besteht der schwierigste Teil darin, den Wochentag genau anzuzeigen. Tatsächlich habe ich zwei Möglichkeiten zum Anzeigen des Wochendatums geschrieben: Die erste Methode besteht darin, den aktuellen Wochentag als Grundlage zu verwenden, jeweils vorwärts und rückwärts zu rechnen und schließlich eine Liste wie [29, 30, 31, 1, 2, 3, 4] auszugeben. Wenn heute zufällig der 1. oder 2. ist, dann ziehen Sie das Datum des letzten Tages des Vormonats und zählen Sie vorwärts; Die zweite Methode ist die folgende Codemethode, die auch den Wochentag des aktuellen Datums ermittelt und ihn dynamisch anhand des Zeitstempels berechnet. Solange Sie wissen, wie viele Tage Sie vom vorherigen Tag abziehen und wie viele Tage Sie zum nächsten Tag hinzufügen müssen, ist das kein Problem. Eigentlich sind beide Methoden in Ordnung. Ich habe mich letztendlich für die zweite entschieden, die offensichtlich prägnanter ist. Wie unten dargestellt: Die aktuelle Woche gibt aus: [12, 13, 14, 15, 16, 17, 18] Nachfolgend finden Sie den Code zur spezifischen Implementierung der oben genannten Schwierigkeiten: const calcWeekDayList: (Params: Zahl) => Wochentyp = (Params) => { const Ergebnis = []; für (lass i = 1; i < Wochentag(Params); i++) { Ergebnis.unshift(Parameter - 3600 * 1000 * 24 * i); } für (lass i = 0; i < 7 - Wochentag(Params) + 1; i++) { Ergebnis.push(Parameter + 3600 * 1000 * 24 * i); } returniere [...Ergebnis] als Wochentyp; }; Code: const CalendatrHeader: React.FC<CalendatrHeaderType> = ({ Zieltag, Zieltag festlegen, switchWeekandDay, businessRender, setzeWeekundDayUmschalten, }) => { // Datum der aktuellen Woche const [dateTextList, setDateTextList] = useState<WeekType | []>([]); // Dieser Zustand tritt auf, wenn zwischen Wochen gewechselt wird. Der Zeitstempel einer Woche wird direkt erhöht oder verringert und das Datum der nächsten oder vorherigen Woche wird automatisch berechnet. const [aktuelleZeit, aktuelleZeit festlegen] = useState<Zahl>(Zieltag); useEffect(() => { setDateTextList(calcWeekDayList(Zieltag)); }, [Zieltag]); // Berechnen Sie die Daten der Tage vor und nach dem aktuellen Zeitstempel. Da die Woche festgelegt ist, berechnen Sie einfach das Datum der aktuellen Woche. const calcWeekDayList: (params: number) => WeekType = (params) => { const Ergebnis = []; für (lass i = 1; i < Wochentag(Params); i++) { Ergebnis.unshift(Parameter - 3600 * 1000 * 24 * i); } für (lass i = 0; i < 7 - Wochentag(Params) + 1; i++) { Ergebnis.push(Parameter + 3600 * 1000 * 24 * i); } returniere [...Ergebnis] als Wochentyp; }; const onChangeWeek: (Typ: „vorherigeWoche“ | „nächsteWoche“, switchWay: „Woche“ | „Tag“) => void = ( Typ, switchWay, ) => { wenn (switchWay === 'Woche') { Konstante calcWeekTime = Typ === 'vorherigeWoche'? aktuelleZeit – 3600 * 1000 * 24 * 7 : aktuelleZeit + 3600 * 1000 * 24 * 7; setCurrTime(calcWeekTime); setDateTextList([...calcWeekDayList(calcWeekTime)]); } wenn (switchWay === 'Tag') { Konstante calcWeekTime = Typ === 'vorherigeWoche'? Zieltag – 3600 * 1000 * 24 : Zieltag + 3600 * 1000 * 24; setCurrTime(calcWeekTime); Zieltag festlegen(Wochenzeit berechnen); } }; zurückkehren ( <div Klassenname = {style.Calendar_Header}> <Tagesoptionen Zieltag = {Zieltag} setCurrTime={setCurrTime} setTargetDay={setTargetDay} dateTextList={dateTextList} switchWeekandDay={switchWeekandDay} setSwitchWeekandDay={(Wert) => { setzeWeekandDayUmschalten(Wert); if (Wert === 'Woche') { setDateTextList(calcWeekDayList(Zieltag)); } }} beiWochenwechsel={(Typ) => beiWochenwechsel(Typ, Wochentagwechsel)} /> {switchWeekandDay === 'Woche' && ( <WöchentlicheOptionen Zieltag = {Zieltag} setTargetDay={setTargetDay} dateTextList={dateTextList} /> )} <div className={style.Calendar_Header_businessRender}> <div className={style.Calendar_Header_Zone}>GMT+8</div> {businessRender({ Zeitstempel: Zieltag })} </div> </div> ); }; DailyOptions: Es handelt sich eigentlich um einen Container für Komponenten, die in der Kopfzeile zwischen „Wochentag“, „Tages- und Wochenmodus“ und „Heute“ wechseln; WeeklyOptions: Dies ist die Komponente, die den Wochentag und das Datum anzeigt. Wenn auf Tag umgeschaltet wird, wird es nicht angezeigt: wie in der Abbildung gezeigt: businessRender: Dies ist die vom Benutzer in der Spalte von Xiao Zhan übergebene Geschäftskomponente. ScheduleCantainer detaillierter ZeitplancontainerDies ist der Teil des Bildes: Tatsächlich ist dieser Teil des Codes ziemlich lang und daher nicht praktikabel, ihn vollständig zu veröffentlichen. Ich werde entsprechend der Funktionspunkte einige Ausschnitte veröffentlichen. Linke SkalaDie linke Skala ist eigentlich von 00:00 - 01:00 ---> 23:00 - 00:00 fest codiert, aber beim Schreiben gibt es ein kleines Problem, nämlich, dass diese Komponente nach links schwebt und mit dem Scrollen der Elemente auf der rechten Seite scrollen muss. Tatsächlich habe ich es am Anfang in eine Box geschrieben, und der Scroll-Container scrollt zusammen, aber ich bin auf ein kleines Problem gestoßen. Da die Elemente auf der rechten Seite zu breit werden, wird eine horizontale Bildlaufleiste angezeigt. Wenn der gesamte Container horizontal gescrollt wird, wird die Zeitskala auf der linken Seite aus dem sichtbaren Bereich herausgescrollt. Hören Sie sich also nach der absoluten Positionierung das Bildlaufereignis des Zeitplanelements rechts an, ändern Sie dynamisch den oberen Wert des Stils links und weisen Sie den Wert in die entgegengesetzte Richtung zu. Da nach unten gescrollt wird, muss die Zeitskala links nach oben gescrollt werden, sodass der obere Wert invertiert wird, um den Synchronisierungseffekt zu erzielen. Was für ein cleveres kleines Gespenst, hehe. Dieser Code nimmt keinen Platz weg. Jeder kann frei mitspielen. Wenn es einen besseren Weg gibt, hinterlassen Sie gerne eine Nachricht im Kommentarbereich. ScheduleItem-ZeitplancontainereintragSchauen Sie sich zunächst den Code dieser Komponente an: const ScheduleItem: React.FC<ScheduleItemType> = ({ Zeitstempelbereich, Datenelement, ZeitplanRender, Breite, Datenelementlänge, }) => { // Containerhöhe berechnen const calcHeight: (timestampList: [number, number]) => number = (timestampList) => timestampList.length > 1 ? (timestampList[1] - timestampList[0]) / 1000 / 60 / 2 : 30; const calcTop: (Startzeit: Zahl) => Zahl = (Startzeit) => Moment(Startzeit).Minute() / 2; // ScheduleItem-Breite berechnen const calcWidth: (w: Zahl, d: Zahl) => string = (w, d) => Breite === 0 || Datenelementlänge * Breite < 347 ? '100 %': `${d * w}px`; zurückkehren ( <div style={{ position: 'relative' }} className={style.Calendar_ScheduleItem_Fath}> <div Klassenname = {style.Calendar_ScheduleItem} Stil = {{ Breite: calcWidth (Breite, Datenelementlänge) }} > {dataItem.map((Daten, Index) => { zurückkehren ( <Fragmentschlüssel={index}> {data.startTime >= timestampRange[0] && data.startTime < timestampRange[1] && ( <div Klassenname = {`${style.Calendar_ScheduleItem_container} Calendar_ScheduleItem_container`} Stil={{ Höhe: `${calcHeight([data.startTime, data.endTime]) || 30}px`, oben: calcTop(Daten.Startzeit), }} > {scheduleRender({ Daten, Zeitstempelbereich })} </div> )} </Fragment> ); })} </div> </div> ); }; Warum benötigen wir für diesen Teil (den grauen Teil unten) eine separate Komponente? Lassen Sie uns zunächst darüber nachdenken ... Okay, ich will Sie nicht auf die Folter spannen. Tatsächlich geht es darum, die Zeitplandaten des Benutzers zu finden, z. B. heute 10:00-11:00, wo soll ich sie finden? Erinnern Sie sich an diese API? scheduleRender?: ({ Daten: Datentyp, Zeitstempelbereich: [DOMTimeStamp, DOMTimeStamp], }) => JSX.Element; Diese Komponente hat einen Parameter [DOMTimeStamp, DOMTimeStamp] (DOMTimeStamp bedeutet Zeitstempel). Diese beiden Zeitstempel sind tatsächlich die Start- und Endzeitstempel des aktuellen Zeitraums 10:00-11:00. Da die von uns akzeptierten Start- und Endzeiten ebenfalls Zeitstempel sind, können wir die Anzeige und das Ausblenden steuern, indem wir vergleichen, ob die Größe innerhalb dieses Bereichs liegt. Jetzt verstehen Sie, warum Zeitstempel verwendet werden. Vergleichen Sie einfach die Größe der Zahlen direkt; Lassen Sie uns über den Stil dieses Dings sprechen: Eigentlich habe ich dieses Ding auf 30px eingestellt, weil eine Stunde 60 Minuten hat. Wenn es 60px wäre, wäre es zu hoch. Also habe ich es auf 30px eingestellt, um die Positionierung zu vereinfachen. Schließlich bin ich faul und möchte keine zu komplizierten Berechnungen. Die Berechnung der Positionierung besteht also nur aus einer Codezeile: const calcTop: (startTime: number) => number = (startTime) => moment(startTime).minute() / 2; Das Problem der Höhenpositionierung ist gelöst! Haha~~ Als nächstes gibt es ein weiteres Problem, nämlich das Höhenproblem, wie in der Abbildung dargestellt: Die Höhenberechnung ist nicht schwierig. Sie wird hauptsächlich basierend auf dem Intervallbereich der aktuellen Start- und Endzeit berechnet (1px sind zwei Minuten). Eine spezifische Implementierung finden Sie im Code: const calcHeight: (Zeitstempelliste: [Zahl, Zahl]) => Zahl = (Zeitstempelliste) => timestampList.length > 1 ? (timestampList[1] - timestampList[0]) / 1000 / 60 / 2 : 30; Zuerst ermitteln wir, ob der von uns eingegebene Zeitstempel nur eine Zeitangabe enthält. Wenn er nur die Startzeit, aber keine Endzeit enthält, codieren wir ihn fest auf 30 Pixel. Wenn er die Start- und Endzeit enthält, konvertieren wir ihn in Minuten und berechnen ihn dynamisch. Schließlich stellt sich noch die Frage: Wie werden die Geschäftsdaten übergeben und wie werden sie der Komponente bereitgestellt? Schauen wir uns zunächst den JSON-Code an, den wir an das Datenfeld übergeben haben: [ { startTime: 1626057075000, // Startzeit endTime: 1626070875000, // Endzeitwert: 'any', // Geschäftsdaten}, { Startzeit: 1626057075000, Endzeit: 1626070875000, Wert: „beliebig“, }, { Startzeit: 1626057075000, Endzeit: 1626070875000, Wert: „beliebig“, }, { Startzeit: 1626057075000, Endzeit: 1626070875000, Wert: „beliebig“, }, ]; Tatsächlich verwenden wir beim Loopen und Rendern der ScheduleItem-Komponente die fest codierte 24-Stunden-Liste zum Loopen. Beim Loopen durchsuchen wir dann dynamisch die Geschäftsdaten nach den Geschäftsdaten, die dem Zeitbereich der aktuellen Schleife entsprechen, und fügen die Daten in die Komponente ein. Der allgemeine Code lautet wie folgt: für (lass i = 0; i < StundenListe.Länge; i++) { result.push({ Zeitstempelbereich: [heuteZeit + i * 3600 * 1000, heuteZeit + (i + 1) * 3600 * 1000], dataItem: [ // Aufgrund der aktuellen Zeitspanne kann es zu Zeitplankonflikten kommen, daher muss eine Liste an die Komponente übergeben werden...data.filter((item) => { zurückkehren ( item.startTime >= todayTime + i * 3600 * 1000 && item.startTime < todayTime + (i + 1) * 3600 * 1000 ); }), ], }); } ZusammenfassenOben ist die Implementierung des größten Teils dieser Komponente dargestellt, vom Empfangen der Anforderungen über das Entwerfen der Komponenten bis hin zu den Implementierungsdetails. Es ist möglicherweise nicht umfassend, stellt aber auch eine grundlegende Implementierungsidee dar. Die Implementierungsdetails der technischen Schwierigkeiten sind ebenfalls aufgeführt. Tatsächlich scheint es nicht schwierig zu sein, solange Sie Ihren Kopf ein wenig benutzen. Meine Implementierung ist möglicherweise nicht perfekt. Es gibt Tausende von Möglichkeiten, ein Programm zu implementieren. Ich habe nur meine Designideen zum Ausdruck gebracht und hoffe, dass Sie von mir lernen können. Wenn etwas falsch ist, weisen Sie bitte im Kommentarbereich darauf hin. Lassen Sie uns gemeinsam Fortschritte machen. Dies ist das Ende dieses Artikels über die Verwendung von React zum Erstellen einer Zeitplankomponente. Weitere Inhalte zu React-Zeitplankomponenten finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Beispielcode für Nginx zur Erreichung dynamischer und statischer Trennung
>>: Detaillierte Erklärung des Konzepts, Prinzips und der Verwendung von MySQL-Triggern
Da die Plattform weiter wächst, ist die Forschung...
Grundlegende Einführung Im vorherigen Artikel hab...
Dieser Artikel fasst die Wissenspunkte zu MySql-I...
Laden Sie die Windows-Version von Nginx von der o...
Vorbereiten: Definieren Sie eine Lehrertabelle un...
1. Laden Sie mysql-5.7.17-winx64.zip herunter; Li...
Vorwort Reduce ist eine der neuen herkömmlichen A...
In SQL wird GROUP BY verwendet, um Daten in den E...
In diesem Artikel untersuchen wir, warum async/aw...
In letzter Zeit besteht eine wachsende Nachfrage ...
Inhaltsverzeichnis Rendern Installieren Code-Impl...
Einführung in IPSec IPSec (Internet Protocol Secu...
Inhaltsverzeichnis 1. Erstellen Sie einen Socket ...
Während des Entwicklungsprozesses trat eine Anfor...
Inhaltsverzeichnis Überblick Durchführung Schutz-...