【问题标题】:Animation suddenly jumps when padding is set on an element在元素上设置填充时动画突然跳跃
【发布时间】:2019-02-22 19:00:13
【问题描述】:

在使用Animate Plus 制作动画的手风琴中,当在元素上设置padding 时,关闭时折叠动画会突然跳跃……

不设置padding时动画流畅……

如何在设置padding 时平滑地为手风琴制作动画?

我的 JavaScript 代码:

const accordions = Array.from(document.querySelectorAll("dl")).map(dl => ({
  element: dl,
  translate: 0
}))

const getButtons = accordion =>
  Array.from(accordion.element.getElementsByTagName("button"), element => ({
    element,
    translate: 0
  }))

const timing = {
  easing: "out-quartic",
  duration: 400
}

const clear = element =>
  Object.values(element.attributes).forEach(({ name }) =>
    element.removeAttribute(name)
  )

const hide = async (accordion, buttons, collapsing) => {
  const objects = buttons.filter(({ translate }) => translate)
  const direction = "reverse"
  rotate(collapsing.previousElementSibling.lastElementChild, direction)
  slide(accordion, objects)
  await fold(collapsing, direction)
  clear(collapsing)
}

const show = (accordion, buttons, expanding) => {
  const button = expanding.previousElementSibling.lastElementChild
  const index = buttons.findIndex(({ element }) => element == button)
  const objects = buttons.slice(index + 1)
  const { height } = expanding.getBoundingClientRect()
  expanding.className = "open"
  rotate(button)
  slide(accordion, objects, height)
  fold(expanding)
}

const slide = (accordion, array, to = 0) => {
  center(accordion, to)
  animate({
    ...timing,
    elements: array.map(({ element }) => element.parentElement),
    transform(index) {
      const object = array[index]
      const from = object.translate
      object.translate = to
      return [`translateY(${from}px)`, to]
    }
  })
}

const center = (accordion, height) => {
  const from = accordion.translate
  const to = Math.round(-height / 2)
  accordion.translate = to
  animate({
    ...timing,
    elements: accordion.element,
    transform: [`translateY(${from}px)`, to]
  })
}

const fold = async (content, direction = "normal") => {
  const scrollHeight = content.scrollHeight
  await animate({
    ...timing,
    direction,
    elements: content,
    opacity: [0, 1],
    maxHeight: ["0px", scrollHeight + "px"],
    transform: ["scaleY(0)", 1]
  })
}
const rotate = ({ lastElementChild: elements }, direction = "normal") =>
  animate({
    elements,
    direction,
    easing: "out-cubic",
    duration: 600,
    transform: ["rotate(0turn)", 0.5]
  })

const toggle = (accordion, buttons) => async ({ target }) => {
  const collapsing = accordion.element.querySelector(".open")
  const expanding = target.parentElement.nextElementSibling
  if (collapsing) await hide(accordion, buttons, collapsing)
  if (collapsing != expanding) show(accordion, buttons, expanding)
}

accordions.forEach(accordion => {
  const buttons = getButtons(accordion)
  buttons.forEach(({ element }) =>
    element.addEventListener("click", toggle(accordion, buttons))
  )
})

import animate from "https://cdn.jsdelivr.net/npm/animateplus@2/animateplus.js"

我的手风琴完整代码可以在 CodePen 上找到:

https://codepen.io/anon/pen/KJjYba

【问题讨论】:

  • 或许可以试试你自己的与 Animate Plus 动画同时运行的 css 动画: transition: Animation Plus 动画的填充持续时间;

标签: javascript css animation ecmascript-6 animateplus


【解决方案1】:

您必须将paddingToppaddingBottom 添加到fold 函数中:

const fold = async (content, direction = "normal") => {
  const scrollHeight = content.scrollHeight
    await animate({
        ...timing,
        direction,
        elements: content,
        opacity: [0, 1],
        maxHeight: ['0px', scrollHeight + 'px'],
        transform: ["scaleY(0)", 1],
        paddingTop: ['0em', '2em'], // add this
        paddingBottom: ['0em', '2em'] // add this
    })
}

Code pen

【讨论】:

  • 在随后的切换中检查这一点(不仅仅是一次打开/关闭)。
  • @ItoPizarro 我明白你的意思,这是另一个问题,不是由解决方案引起的,没有它也会发生。
  • 您对timing.duration 的更改正在影响并发/顺序动画的时间。我得到了基本相同的解决方案,但按原样保留了时间,并且它没有表现出这种价值复合行为。
  • @ItoPizarro 哦,我在调试时这样做了,我忘了删除它,答案中的 sn-p 中没有提到它,所以它不应该是它的一部分,我更新了 Pen ,谢谢你发现它。
【解决方案2】:

fold() 方法中动画填充;将所需的测量值添加到 paddingBottompaddingTop 属性。然后,您可以从 CSS 中的 .open 类规则中删除填充属性。

const fold = async (content, direction = "normal") => {
  const scrollHeight = content.scrollHeight;
  await animate({
    ...timing,
    direction,
    elements: content,
    opacity: [0, 1],
    maxHeight: ["0px", scrollHeight + "px"],
    paddingTop: ["0em", "2em"],
    paddingBottom: ["0em", "2em"],
    transform: ["scaleY(0)", 1]
  });
};

CodePen

【讨论】:

    【解决方案3】:

    您可以将填充设置为新的子元素。因此,将内容包装在一个额外的 div 中,如下所示:

    <dd><div>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
    eiusmod tempor incididunt ut labore et dolore magna aliqua.</div></dd>
    

    然后,而不是样式 .open 样式 div 里面:

    .open div {
        padding: 2em 0;
    }
    

    它不会使用孩子跳跃。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-27
      • 2015-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多