如何使用WAAPI设置“细节”元素的动画





朋友们,美好的一天!



在本文中,我将向您展示如何使用Web Animations API来对本机细节元素进行动画处理



让我们从标记开始。



“详细信息”元素必须包含“摘要”元素。摘要是关闭手风琴时内容的可见部分。



任何其他元素都是手风琴内部内容的一部分。为了使我们的任务更轻松,我们将把此内容包装在带有“内容”类的div中。



<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>


手风琴课



我们需要一个Accordion类来重用我们的代码。使用此类,我们可以在页面上实例化任意数量的详细信息。



class Accordion {
  constructor() {}

  // ,     summary
  onClick() {}

  // ,     
  shrink() {}

  // ,      
  open() {}

  // ,     
  expand() {}

  // ,    shrink  expand
  onAnimationFinish() {}
}


构造函数()



构造函数用于存储手风琴所需的数据。



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()



在“ onClick”功能中,我们检查元素是否处于动画制作(关闭或展开)过程中。对于用户在动画结束之前单击手风琴的情况,我们需要这样做。我们不希望手风琴从完全打开过渡到完全关闭。



打开“ details”元素时,浏览器会添加“ open”属性。我们可以通过this.el.open获取此属性的值。



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()
  }
}


缩小()



收缩功能使用WAAPI的“动画”功能。您可以在此处阅读有关此功能的信息WAAPI与CSS“关键帧”语句非常相似,因为我们需要为动画定义关键帧。在这种情况下,我们只需要两个这样的框架:第一个是“详细信息”元素的当前高度(打开),第二个是闭合明细的高度(摘要高度)。



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”属性以使内容可见,但同时由于溢出而隐藏:隐藏和元素的固定高度。接下来,我们等待下一帧调用expand函数并对元素进行动画处理。



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


展开()



扩展功能类似于收缩功能,但是我们没有从元素的当前高度到其闭合高度进行动画处理,而是从元素的高度到其完整高度进行了动画处理。总高度是汇总高度加上内部内容的高度。



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()



在打开和关闭动画细节的结尾处调用此函数。它使用一个参数,即“ open”属性的布尔值,该参数将不再由浏览器处理(如果您还记得的话,我们取消了“ onClick”功能中的默认浏览器行为)。



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 = ''
}


初始化手风琴



我们快完成了。



剩下要做的就是为页面上的每个details元素创建Accordion类的实例。



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


备注



为了正确地计算元素在打开和关闭状态下的高度,摘要和内容在整个动画中必须具有相同的高度。



不要在打开的摘要中添加内部空格,因为这可能导致突然跳转。内部内容也是如此-它必须具有固定的高度,并且在打开细节时应避免更改其高度。



另外,请勿在摘要和内容之间添加外部空格,因为在计算关键帧的高度时不会考虑它们。而是在内容上使用填充以增加一些空间。



结论



这样,我们便可以轻松,简单地用纯JavaScript创建手风琴。







希望您发现自己感兴趣的东西。感谢您的关注。



All Articles