EinführungDas Konzept der Animation ist sehr weit gefasst und umfasst verschiedene Bereiche. Hier beschränken wir den Umfang auf die Ebene der Front-End-Webanwendungen, ganz zu schweigen von Animationen im Spielebereich. Beginnen wir mit dem Einfachsten. Derzeit werden die meisten Webanwendungen auf der Grundlage von Frameworks wie Vue, React usw. entwickelt. Sie basieren alle auf datengesteuerten Ansichten. Vergleichen wir also, wie wir Animationen oder Übergangseffekte implementiert haben, als diese Frameworks noch nicht existierten, und wie wir sie mithilfe datengesteuerter Methoden erreichen konnten. Traditionelle ÜbergangsanimationAnimationseffekte spielen für das Erlebnis eine sehr wichtige Rolle, für viele Entwickler können sie jedoch ein sehr schwaches Glied sein. Seit dem Aufkommen von CSS3 ist der von vielen Anfängern am häufigsten verwendete Animationsübergang möglicherweise die Fähigkeit von CSS3. CSS-ÜbergangsanimationEs ist sehr einfach, die Übergangsanimation mit CSS zu starten. Schreiben Sie einfach das Übergangsattribut. Hier ist eine Demo <div id="app" class="normal"></div> .normal { Breite: 100px; Höhe: 100px; Hintergrundfarbe: rot; Übergang: alle 0,3 s; } .normal:hover { Hintergrundfarbe: gelb; Breite: 200px; Höhe: 200px; } Der Effekt ist immer noch sehr gut. CSS3-Übergänge erfüllen grundsätzlich die meisten Animationsanforderungen. Wenn sie nicht erfüllt sind, gibt es auch echte CSS3-Animationen. animieren-css Die berühmte CSS-Animationsbibliothek. Jeder, der sie verwendet, kennt sie. Ob CSS3-Übergang oder CSS3-Animation, wir verwenden es einfach, indem wir den Klassennamen wechseln. Wenn Sie eine Rückrufverarbeitung durchführen möchten, bietet der Browser auch Animationsrahmenereignisse wie ontransitionend und onanimationend, die über die JS-Schnittstelle abgehört werden können. var el = document.querySelector('#app') el.addEventListener('transitionstart', () => { console.log('Übergangsstart') }) el.addEventListener('transitionend', () => { console.log('Übergangsende') }) Ok, das ist die Grundlage der CSS-Animation. Die meisten Anforderungen an Animationsübergänge können auch durch JS-Kapselung erreicht werden, die Einschränkung besteht jedoch darin, dass nur die von CSS unterstützte Attributanimation gesteuert werden kann und die Steuerung relativ schwach ist. JS-Animation Schließlich ist js ein benutzerdefiniertes Codierungsprogramm, verfügt daher über eine leistungsstarke Kontrolle über Animationen und kann verschiedene Effekte erzielen, die von CSS nicht unterstützt werden. Was ist also die Grundlage für die Implementierung von Animationen in JS? <div id="app" class="normal"></div> // Tween ist nur eine Beschleunigungsfunktion var el = document.querySelector('#app') var Zeit = 0, Beginn = 0, Änderung = 500, Dauer = 1000, fps = 1000 / 60; Funktion startSport() { var val = Tween.Elastic.easeInOut(Zeit, Beginn, Änderung, Dauer); el.style.transform = "translateX(" + val + "px)"; if (Zeit <= Dauer) { Zeit += fps } anders { console.log('Animation endet und wird neu gestartet') Zeit = 0; } setzeTimeout(() => { startSport() }, fps) } startSport() Die kontinuierliche Aktualisierung der Eigenschaften auf der Zeitleiste kann über setTimeout oder requestAnimation erreicht werden. Was die Tween-Easing-Funktion betrifft, so ähnelt sie dem Konzept der Interpolation. Bei einer Reihe von Variablen können Sie den Wert jederzeit im Intervall abrufen. Es handelt sich um eine rein mathematische Formel und wird von fast allen Animationsframeworks verwendet. Wenn Sie mehr wissen möchten, können Sie sich auf Zhang Xinxus Tween.js beziehen OK, diese minimalistische Demo ist auch die Kerngrundlage der JS-Animation. Sie können sehen, dass wir den Generierungsprozess von Übergangswerten durch das Programm perfekt steuern. Alle anderen komplexen Animationsmechanismen folgen diesem Muster. Vergleich zwischen traditionellen und Vue/React-Frameworks Durch die vorherigen Beispiele, unabhängig davon, ob es sich um einen CSS-Übergang oder einen JS-Übergang handelt, erhalten wir direkt das DOM-Element und führen dann Attributoperationen am DOM-Element aus. Übergangsanimation unter dem Vue-FrameworkSie können das Dokument zunächst lesen Vue-Übergangsanimation Wir werden nicht darüber sprechen, wie man es verwendet, sondern analysieren, wie die von Vue bereitgestellte Übergangskomponente die Unterstützung für Animationsübergänge implementiert. Übergangskomponente Schauen Sie sich zunächst den Code der Übergangskomponente an, Pfad „src/platforms/web/runtime/components/transition.js“ // Hilfsfunktion, kopiere Props-Daten, Exportfunktion extractTransitionData (comp: Component): Object { const Daten = {} Konstante Optionen: ComponentOptions = comp.$options // Requisiten für (const key in options.propsData) { Daten[Schlüssel] = comp[Schlüssel] } // Ereignisse. const listeners: ?Objekt = Optionen._parentListeners für (const key in listeners) { Daten [Camelize (Schlüssel)] = Listener [Schlüssel] } Rückgabedaten } Standard exportieren { Name: "Übergang", Requisiten: ÜbergangsRequisiten, abstract: true, // Abstrakte Komponente, was bedeutet, dass sie nicht in DOM gerendert wird, um bei der Entwicklung von render (h: Funktion) { zu helfen. // Holen Sie sich die echten untergeordneten Rendering-Elemente über die Slots lass untergeordnete Elemente: any = this.$slots.default Konstantenmodus: Zeichenfolge = dieser.Modus const rawChild: VNode = Kinder[0] // Einen eindeutigen Schlüssel hinzufügen // Komponenteninstanz. Dieser Schlüssel wird verwendet, um ausstehende Knoten zu entfernen // während der Eingabe. const id: Zeichenfolge = `__transition-${this._uid}-` Kindschlüssel = getKey(id) : untergeordneter Schlüssel // Fügen Sie das Übergangsattribut in die Daten ein, um die durch die Eigenschaften übergebenen Daten zu speichern. const data: Object = (child.data || (child.data = {})).transition = extractTransitionData(this) const oldRawChild: VNode = this._vnode const altesKinderkind: VNode = getRealChild(altesRawChild) // wichtig für dynamische Übergänge! const oldData: Objekt = oldChild.data.transition = erweitern({}, data) // Übergangsmodus handhaben wenn (Modus === 'out-in') { // Platzhalterknoten und Warteschlangenaktualisierung zurückgeben, wenn das Verlassen beendet ist dies._leaving = wahr mergeVNodeHook(alteDaten, 'afterLeave', () => { this._leaving = falsch dies.$forceUpdate() }) Platzhalter zurückgeben (h, Rohkind) } sonst wenn (Modus === 'in-out') { let verzögertLeave const performLeave = () => { verzögertesLeave() } mergeVNodeHook(Daten, „nachEintreten“, „Austreten durchführen“) mergeVNodeHook(Daten, 'enterCancelled', performLeave) mergeVNodeHook(alteDaten, 'delayLeave', verlassen => { delayLeave = verlassen }) } Rohes Kind zurückgeben } } Wie Sie sehen, ist die Funktion dieser Komponente selbst relativ einfach. Sie ruft die untergeordneten Elemente der Elemente ab, die über Slots gerendert werden müssen, und kopiert dann die Props-Attributdaten des Übergangs in das Übergangsattribut der Daten, um sie anschließend in den Lebenszyklus einzufügen. mergeVNodeHook wird für die Lebenszyklusverwaltung verwendet. Module/Übergang Schauen Sie sich dann den Lebenszykluspfad an: Funktion _enter (_: beliebig, vnode: VNodeWithData) { wenn (vnode.data.show !== true) { eingeben(vnode) } } Standardmäßig im Browser exportieren? { erstellen: _enter, aktivieren: _enter, entfernen (vnode: VNode, rm: Funktion) { wenn (vnode.data.show !== true) { verlassen (vnode, rm) } } } : {} Hier wird „inBrowser“ als wahr betrachtet, da wir die Browserumgebung analysieren. Exportfunktion addTransitionClass (el: beliebig, cls: Zeichenfolge) { const Übergangsklassen = el._Übergangsklassen || (el._Übergangsklassen = []) wenn (transitionClasses.indexOf(cls) < 0) { Übergangsklassen.push(cls) Klasse hinzufügen(el, cls) } } Exportfunktion removeTransitionClass (el: beliebig, cls: Zeichenfolge) { wenn (el._transitionClasses) { entfernen(el._transitionClasses, cls) } entferneKlasse(el, cls) } Exportfunktion eingeben (vnode: VNodeWithData, toggleDisplay: ?() => void) { const el: any = vnode.elm // Callback jetzt verlassen wenn (isDef(el._leaveCb)) { el._leaveCb.cancelled = wahr el._leaveCb() } // Die im vorherigen Schritt in die Daten eingefügten Übergangsdaten const data = resolveTransition(vnode.data.transition) wenn (isUndef(data)) { zurückkehren } /* istanbul ignorieren wenn */ wenn (isDef(el._enterCb) || el.nodeType !== 1) { zurückkehren } Konstante { CSS, Typ, Klasse eingeben, Klasse eingeben, AktiveKlasse eingeben, erscheinenKlasse, erscheinenToClass, erscheinenActiveClass, vorEintreten, eingeben, nach der Eingabetaste, enterAbgebrochen, vorErscheinen, erscheinen, nach dem Erscheinen, erscheinenAbgebrochen, Dauer } = Daten let Kontext = aktive Instanz let transitionNode = activeInstance.$vnode const isAppear = !context._isMounted || !vnode.isRootInsert wenn (isAppear && !appear && erscheinen !== '') { zurückkehren } // Holen Sie sich den Klassennamen, der zum richtigen Zeitpunkt eingefügt werden soll const startClass = isAppear und erscheinenClass ?Klasse erscheinen :Klasse eingeben const activeClass = isAppear und appearActiveClass ?AktiveKlasse erscheinen :AktiveKlasse eingeben const toClass = isAppear und appearToClass ?InKlasseerscheinen :InKlasseeintreten const beforeEnterHook = isAppear ? (vorErscheinen || vorEintreten) : vorEingabe const enterHook = isAppear ? (Typ von erscheinen === 'Funktion' ? erscheinen: eingeben) : eingeben const afterEnterHook = isAppear ? (nachErscheinen || nachEingabe) :nachEingabe const enterCancelledHook = isAppear ? (erscheintAbgebrochen || tritt einAbgebrochen) :enterAbgebrochen const explicitEnterDuration: beliebig = bisZahl( isObject(Dauer) ? Dauer.Eingabe : Dauer ) const erwartetCSS = css !== false && !istIE9 const userWantsControl = getHookArgumentsLength(enterHook). // Rückrufverarbeitung nach Abschluss des Übergangs. Löschen Sie die Klasse beim Eintreten. const cb = el._enterCb = once(() => { wenn (erwartetCSS) { entferneTransitionClass(el, toClass) entferneTransitionClass(el, activeClass) } wenn (cb.abgebrochen) { wenn (erwartetCSS) { entferneTransitionClass(el, startClass) } enterCancelledHook und enterCancelledHook (el) } anders { nachEnterHook && nachEnterHook(el) } el._enterCb = null }) // Wenn DOM eintritt, Startklasse für Übergang hinzufügen beforeEnterHook && beforeEnterHook(el) wenn (erwartetCSS) { // Den Standardstil festlegen, bevor der Übergang beginnt addTransitionClass(el, startClass) Übergangsklasse hinzufügen(el, aktiveKlasse) // Der Browser rendert das nächste Frame, löscht den Standardstil und fügt toClass hinzu // End-Event-Listener hinzufügen, der Callback ist cb oben nächsterFrame(() => { entferneTransitionClass(el, startClass) wenn (!cb.abgebrochen) { Übergangsklasse hinzufügen(el, zuKlasse) if (!BenutzerWantsControl) { if (istGültigeDauer(expliziteEingabeDauer)) { setTimeout(cb, expliziteEingabedauer) } anders { wennTransitionEnds(el, Typ, cb) } } } }) } wenn (vnode.data.show) { Anzeige umschalten && Anzeige umschalten() EnterHook und EnterHook (el, cb) } wenn (!erwartetCSS && !userWantsControl) { cb() } } Enter verwendet eine Funktion whenTransitionEnds, die tatsächlich das Ereignis des Übergangs oder des Animationsendes überwacht: exportiere let transitionEndEvent = "Übergangsende" exportiere let animationEndEvent = 'animationsende' Exportfunktion whenTransitionEnds ( el: Element, erwarteter Typ: ?Zeichenfolge, cb: Funktion ) { const { Typ, Timeout, Eigenschaftenanzahl } = getTransitionInfo(el, erwarteterTyp) wenn (!Typ) return cb() const-Ereignis: Zeichenfolge = Typ === ÜBERGANG ? ÜbergangsEndeEvent : AnimationEndeEvent let beendet = 0 const end = () => { el.removeEventListener(Ereignis, bei Ende) cb() } const onEnd = e => { wenn (e.target === el) { wenn (++ended >= propCount) { Ende() } } } setzeTimeout(() => { wenn (beendet < propCount) { Ende() } }, Zeitüberschreitung + 1) el.addEventListener(Ereignis, am Ende) } OK, los geht’s. Gemäß der Kommentaranalyse des obigen Quellcodes können wir Folgendes feststellen:
Der Vorgang zum Verlassen ist der gleiche wie zum Eintreten, außer dass className in umgekehrter Reihenfolge hinzugefügt und entfernt wird. Fazit: Die Verarbeitungsmethode für Animationsübergänge von Vue ist im Wesentlichen dieselbe wie bei herkömmlichem DOM, wird jedoch zur Verarbeitung in die verschiedenen Lebenszyklen von Vue integriert. Im Wesentlichen wird es immer noch verarbeitet, wenn DOM hinzugefügt oder gelöscht wird. Übergangsanimation in ReactOh, wir haben die React-Dokumentation durchgeblättert und keine Verarbeitung von Übergangsanimationen gefunden. Hey, es scheint, dass es nicht offiziell nativ unterstützt wird. Wir können es jedoch selbst implementieren, beispielsweise indem wir einen Status über useState beibehalten und den Klassennamen entsprechend dem Status im Rendermodus wechseln. Was sollen wir jedoch tun, wenn es kompliziert ist? Glücklicherweise habe ich in der Community eine Wheel-Plugin-React-Transition-Gruppe gefunden Klasse Transition erweitert React.Component { statischer Kontexttyp = Übergangsgruppenkontext Konstruktor(Requisiten, Kontext) { super(Requisiten, Kontext) let übergeordneteGruppe = Kontext erscheinen lassen = übergeordneteGruppe und !übergeordneteGruppe.isMounting ? props.enter : props.appear let initialStatus this.appearStatus = null wenn (props.in) { wenn (erscheinen) { initialStatus = BEENDET this.appearStatus = EINGABE } anders { initialStatus = EINGETRAGEN } } anders { wenn (props.unmountOnExit || props.mountOnEnter) { InitialStatus = NICHT MOUNTED } anders { initialStatus = BEENDET } } dieser.Zustand = { Status: Anfangsstatus } this.nextCallback = null } // Beim Initialisieren des DOM den Standardanfangsstatus aktualisieren componentDidMount() { dies.updateStatus(true, dies.appearStatus) } // Wenn Daten aktualisiert werden, aktualisiere den entsprechenden Status componentDidUpdate(prevProps) { let nextStatus = null wenn (vorherigeProps !== diese.props) { const { status } = dieser.Zustand wenn (diese.props.in) { if (status !== EINGABE && status !== EINGABE) { nächsterStatus = EINGABE } } anders { if (status === EINGABE || status === EINGEGANGEN) { nächsterStatus = BEENDEN } } } dies.updateStatus(false, nächsterStatus) } updateStatus(mounting = false, nächsterStatus) { wenn (nächsterStatus !== null) { // Der nächste Status wird immer „ENTERING“ oder „EXITING“ sein. this.cancelNextCallback() wenn (nextStatus === EINGABE) { this.performEnter(Einhängen) } anders { dies.performExit() } } sonst wenn (this.props.unmountOnExit && this.state.status === EXITED) { this.setState({ status: NICHT MONTIERT }) } } durchführenEnter(Einhängen) { const { eingeben} = diese.props const erscheint = dieser.Kontext? dieser.Kontext.isMounting: Montage const [vielleichtNode, vielleichtErscheinend] = this.props.nodeRef ? [erscheint] : [ReactDOM.findDOMNode(dies), erscheint] const timeouts = this.getTimeouts() const enterTimeout = erscheint? timeouts.erscheinen : timeouts.enter // keine Enter-Animation, direkt zu ENTERED springen // wenn wir dies mounten und ausführen, bedeutet das, dass appear _gesetzt werden muss_ wenn ((!mounting && !enter) || config.disabled) { this.safeSetState({ status: EINGETRAGEN }, () => { this.props.onEntered(vielleichtKnoten) }) zurückkehren } this.props.onEnter(vielleichtKnoten, vielleichtErscheinen) this.safeSetState({ status: EINGABE }, () => { this.props.onEntering(vielleichtKnoten, vielleichtErscheinen) this.onTransitionEnd(enterTimeout, () => { this.safeSetState({ status: EINGETRAGEN }, () => { this.props.onEntered(vielleichtKnoten, vielleichtErscheinen) }) }) }) } führeExit() aus { const { exit } = diese.props const timeouts = this.getTimeouts() const maybeNode = this.props.nodeRef ? nicht definiert : ReactDOM.findDOMNode(dies) // keine Exit-Animation, direkt zu EXITED springen wenn (!exit || config.disabled) { this.safeSetState({ status: BEENDET }, () => { this.props.onExited(vielleichtKnoten) }) zurückkehren } this.props.onExit(vielleichtKnoten) this.safeSetState({ status: WIRD BEENDET }, () => { this.props.onExiting(vielleichtKnoten) dies.onTransitionEnd(timeouts.exit, () => { this.safeSetState({ status: BEENDET }, () => { this.props.onExited(vielleichtKnoten) }) }) }) } AbbrechenNächstenRückruf() { wenn (this.nextCallback !== null) { dies.nextCallback.abbrechen() this.nextCallback = null } } safeSetState(nächsterState, Rückruf) { // Das sollte nicht notwendig sein, aber es gibt seltsame Race Conditions mit // setState-Rückrufe und Unmounten beim Testen, also stellen Sie immer sicher, dass // Wir können alle ausstehenden SetState-Rückrufe abbrechen, nachdem wir die Bereitstellung aufgehoben haben. Rückruf = this.setNextCallback(Rückruf) dies.setState(nächsterState, Rückruf) } setzeNächstenRückruf(Rückruf) { let aktiv = wahr this.nextCallback = Ereignis => { wenn (aktiv) { aktiv = falsch this.nextCallback = null Rückruf (Ereignis) } } dies.nextCallback.cancel = () => { aktiv = falsch } gib diesen.nextCallback zurück } // Auf das Ende des Übergangs warten beiÜbergangsende(Timeout, Handler) { this.setNextCallback(handler) const node = this.props.nodeRef ? diese.props.nodeRef.current : ReactDOM.findDOMNode(dies) const hatkeinTimeoutoderListener = timeout == null && !this.props.addEndListener if (!node || hatKeinTimeoutOderListener) { setzeTimeout(diesen.nächstenCallback, 0) zurückkehren } wenn (this.props.addEndListener) { const [vielleichtNode, vielleichtNächsterCallback] = this.props.nodeRef ? [dieser.nächsterRückruf] : [Knoten, dieser.nächsterCallback] this.props.addEndListener(vielleichtKnoten, vielleichtNächsterRückruf) } wenn (Zeitüberschreitung != null) { setzeTimeout(diesen.nächstenCallback, Zeitüberschreitung) } } rendern() { const status = dieser.Zustand.status wenn (Status === NICHT MOUNTED) { return null } Konstante { Kinder, // Filtereigenschaften für „Übergang“ in: _in, mountOnEnter: _mountOnEnter, unmountOnExit: _unmountOnExit, erscheinen: _erscheinen, eingeben: _enter, beenden: _exit, Zeitüberschreitung: _Zeitüberschreitung, addEndListener: _addEndListener, beim Eintreten: _onEnter, beim Betreten: _beim Betreten, beim Eintreten: _beiEintreten, beim Verlassen: _onExit, beim Verlassen: _onExiting, beim Verlassen: _onExited, KnotenRef: _nodeRef, ...childProps } = diese.Eigenschaften zurückkehren ( // ermöglicht verschachtelte Übergänge <TransitionGroupContext.Provider-Wert={null}> {Typ der untergeordneten Elemente === 'Funktion' ? Kinder(Status, untergeordnete Eigenschaften) : React.cloneElement(React.Children.only(Kinder), childProps)} </TransitionGroupContext.Provider> ) } } Wie Sie sehen, ist es Vue sehr ähnlich, außer dass es in verschiedenen Lebenszyklusfunktionen von React verarbeitet wird. An diesem Punkt werden wir feststellen, dass sich sowohl die Vue-Transition-Komponente als auch die React-Transition-Group-Komponente auf die Animation von CSS-Attributen konzentrieren. Datengesteuerte AnimationIn tatsächlichen Szenen werden Sie immer auf Animationen stoßen, die CSS nicht verarbeiten kann. Derzeit gibt es zwei Lösungen: Holen Sie sich DOM über Ref und übernehmen Sie dann unsere traditionelle JS-Lösung. Oben finden Sie Einzelheiten zur Implementierung von Animationsübergangseffekten im Frontend. Weitere Informationen zur Implementierung von Animationsübergangseffekten im Frontend finden Sie in den anderen verwandten Artikeln auf 123WORDPRESS.COM! Das könnte Sie auch interessieren:
|
>>: Lösung für die Koexistenz mehrerer PHP-Versionen unter Linux-Systemen (super einfach)
Ich habe mir vor kurzem ein Video von einem Auslä...
Installieren Sie vsftpd $ sudo apt-get installier...
In HTML haben <, >, & usw. eine speziell...
Inhaltsverzeichnis 1. Einige Punkte, die Sie beac...
Vorwort Der Ursprung ist Frage 1: Wenn Ihre Umask...
Inhaltsverzeichnis 1. Verwenden Sie den Befehl „r...
Es gibt drei Hauptmethoden der MySQL-Replikation:...
In diesem Artikel erfahren Sie, wie Sie die selbs...
1. Einführung in LVM Bei der Verwaltung von Linux...
1. Zwei Möglichkeiten, den Zeichensatz der HTML-S...
1. MySQL installieren (1) Entpacken Sie die herun...
Der Zweck der Verwendung von HTML zum Markieren v...
Das <marquee>-Tag ist ein Tag, das paarweis...
NAT Auf diese Weise wird die Netzwerkkarte der vi...
Dieser Artikel beschreibt, wie xdebug in einer Ub...