So animieren Sie das Element "details" mit WAAPI





Guten Tag, Freunde!



In diesem Artikel werde ich Ihnen zeigen, wie Sie das native Detailelement mithilfe der Webanimations-API animieren können .



Beginnen wir mit dem Markup.



Das Element "details" muss ein Element "summary" enthalten. Zusammenfassung ist der sichtbare Teil des Inhalts, wenn das Akkordeon geschlossen wird.



Alle anderen Elemente sind Teil des inneren Inhalts des Akkordeons. Um unsere Aufgabe zu vereinfachen, werden wir diesen Inhalt in ein Div mit der Klasse "Inhalt" einschließen.



<details>
  <summary>Summary of the accordion</summary>
  <div class="content">
    <p>
      Lorem, ipsum dolor sit amet consectetur adipisicing elit.
      Modi unde, ex rem voluptates autem aliquid veniam quis temporibus repudiandae illo, nostrum, pariatur quae!
      At animi modi dignissimos corrupti placeat voluptatum!
    </p>
  </div>
</details>


Akkordeon Klasse



Wir benötigen eine Akkordeonklasse, um unseren Code wiederverwenden zu können. Mit einer solchen Klasse können wir eine beliebige Anzahl von Details auf der Seite instanziieren.



class Accordion {
  constructor() {}

  // ,     summary
  onClick() {}

  // ,     
  shrink() {}

  // ,      
  open() {}

  // ,     
  expand() {}

  // ,    shrink  expand
  onAnimationFinish() {}
}


Konstrukteur ()



Der Konstruktor wird verwendet, um die für das Akkordeon erforderlichen Daten zu speichern.



constructor(el) {
  //  details
  this.el = el
  //  summary
  this.summary = el.querySelector('summary')
  //  div   "content"
  this.content = el.querySelector('.content')

  //    (    )
  this.animation = null
  //      ?
  this.isClosing = false
  //      ?
  this.isExpanding = false
  //    summary
  this.summary.addEventListener('click', (e) => this.onClick(e))
}


onClick ()



In der Funktion "onClick" prüfen wir, ob das Element gerade animiert (geschlossen oder erweitert) wird. Wir müssen dies für den Fall tun, dass der Benutzer auf das Akkordeon klickt, bevor die Animation endet. Wir wollen nicht, dass das Akkordeon von ganz offen nach ganz geschlossen springt.



Das Element "details" verfügt über ein Attribut "open", das vom Browser beim Öffnen des Elements hinzugefügt wird. Wir können den Wert dieses Attributs über this.el.open abrufen.



onClick(e) {
  //    
  e.preventDefault()
  //   details  "overflow"   "hidden"    
  this.el.style.overflow = 'hidden'
  // ,         
  if (this.isClosing || !this.el.open) {
    this.open()
    // ,         
  } else if (this.isExpanding || this.el.open) {
    this.shrink()
  }
}


schrumpfen ()



Die Verkleinerungsfunktion verwendet die WAAPI-Funktion "animieren". Über diese Funktion können Sie hier lesen . WAAPI ist der CSS-Anweisung "Keyframes" sehr ähnlich, da wir Keyframes für die Animation definieren müssen. In diesem Fall benötigen wir nur zwei solcher Frames: Der erste ist die aktuelle Höhe des Detailelements (offen), der zweite ist die Höhe der geschlossenen Details (zusammenfassende Höhe).



shrink() {
  //    
  this.isClosing = true

  //    
  const startHeight = `${this.el.offsetHeight}px`
  //   summary
  const endHeight = `${this.summary.offsetHeight}px`

  //    
  if (this.animation) {
    //  
    this.animation.cancel()
  }

  //  WAAPI 
  this.animation = this.el.animate({
    //   
    height: [startHeight, endHeight]
  }, {
    //         ,        (duration - )
    duration: 400,
    //        (easing (animation-timing-function) -  )
    easing: 'ease-out'
  })

  //     onAnimationFinish()
  this.animation.onfinish = () => this.onAnimationFinish(false)
  //   ,   "isClosing"  "false"
  this.animation.oncancel = () => this.isClosing = false
}


open ()



Die "Öffnen" -Funktion wird aufgerufen, wenn wir das Akkordeon öffnen möchten. Diese Funktion steuert nicht die Animation des Akkordeons. Zuerst berechnen wir die Höhe des Elements "Details" und fügen ihm die entsprechenden Inline-Stile hinzu. Danach können wir ein "open" -Attribut hinzufügen, um den Inhalt sichtbar zu machen, aber gleichzeitig dank des Überlaufs verborgen: versteckt und die feste Höhe des Elements. Als nächstes warten wir auf den nächsten Frame, um die Erweiterungsfunktion aufzurufen und das Element zu animieren.



open() {
  //    
  this.el.style.height = `${this.el.offsetHeight}px`
  //  details  "open"
  this.el.open = true
  //       "expand"
  requestAnimationFrame(() => this.expand())
}


erweitern ()



Die Erweiterungsfunktion ähnelt der Verkleinerungsfunktion, aber anstatt von der aktuellen Höhe des Elements zu seiner geschlossenen Höhe zu animieren, animieren wir von der Höhe des Elements zu seiner vollen Höhe. Die Gesamthöhe ist die Gesamthöhe plus die Höhe des inneren Inhalts.



expand() {
  //    
  this.isExpanding = true
  //    
  const startHeight = `${this.el.offsetHeight}px`
  //     ( summary +  )
  const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`

  //    
  if (this.animation) {
    //  
    this.animation.cancel()
  }

  //  WAAPI 
  this.animation = this.el.animate({
    height: [startHeight, endHeight]
  }, {
    duration: 400,
    easing: 'ease-out'
  })

  this.animation.onfinish = () => this.onAnimationFinish(true)
  this.animation.oncancel = () => this.isClosing = false
}


onAnimationFinish ()



Diese Funktion wird am Ende der Details zum Öffnen und Schließen der Animation aufgerufen. Es wird ein Parameter benötigt, ein boolescher Wert für das Attribut "open", der vom Browser nicht mehr verarbeitet wird (wenn Sie sich erinnern, haben wir das Standardverhalten des Browsers in der Funktion "onClick" abgebrochen).



onAnimationFinish(open) {
  //    "open"
  this.el.open = open
  //  ,  
  this.animation = null
  //  
  this.isClosing = false
  this.isExpanding = false
  //  overflow   
  this.el.style.height = this.el.style.overflow = ''
}


Akkordeons initialisieren



Fuh! Wir sind fast fertig.



Sie müssen lediglich eine Instanz der Akkordeon-Klasse für jedes Detailelement auf der Seite erstellen.



document.querySelectorAll('details').forEach(el => {
  new Accordion(el)
})


Bemerkungen



Um die Höhe eines Elements im geöffneten und geschlossenen Zustand korrekt zu berechnen, müssen Zusammenfassung und Inhalt in der gesamten Animation dieselbe Höhe haben.



Fügen Sie für die offene Zusammenfassung keine internen Leerzeichen hinzu, da dies zu plötzlichen Sprüngen führen kann. Gleiches gilt für internen Inhalt - er muss eine feste Höhe haben, und Sie sollten vermeiden, seine Höhe beim Öffnen von Details zu ändern.



Fügen Sie außerdem keine externen Leerzeichen zwischen Zusammenfassung und Inhalt hinzu, da diese bei der Berechnung der Höhe in Keyframes nicht berücksichtigt werden. Verwenden Sie stattdessen das Auffüllen Ihrer Inhalte, um Speicherplatz hinzuzufügen.



Fazit



So haben wir es einfach und unkompliziert geschafft, ein Akkordeon in reinem JavaScript zu erstellen.







Ich hoffe, Sie haben etwas Interessantes für sich gefunden. Vielen Dank für Ihre Aufmerksamkeit.



All Articles