简体   繁体   中英

Moving all elements in an animated accordion

An accordion animated with Animate Plus contains dl and legend elements within fieldset . Everything works as it's supposed to, except fieldset doesn't expand and legend doesn't move with the rest of the elements.

手风琴动画示例

I would like to smoothly resize fieldset height by the same ammount dl is increased.

My JavaScript code:

 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") => await animate({ ...timing, direction, elements: content, opacity: [0, 1], 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"

My full code for an accordion can be found on CodePen:

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

The issue all stems from the fact that you have:

dd {
    position: absolute;
    /* more styles */
}

Essentially, this makes it so that the height of this element gets ignored when calculating its parent's height.

I'm not familiar with the library you are using, but doing a quick modification to remove that, set the max-height to 0 when it's hidden, and then animate that height to the scrollHeight of the content (ie the height of the content when maxHeight is ignored).

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

dd {
    opacity: 0;
    max-height: 0;
}

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM