Как использовать querySelectorAll в определенном контексте - PullRequest
0 голосов
/ 23 января 2019

Я использую Animate Plus для анимации аккордеона.У меня есть несколько списков определений (dl), и я хотел бы нацелить их все, а не только на первый.

Вот соответствующий фрагмент кода:

const accordion = {
  element: document.querySelector("dl"),
  translate: 0
}

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

Я былпытаясь преобразовать в массив и использовать оператор распространения […document.querySelectorAll("dl")], но безуспешно.

Как я могу использовать querySelectorAll в этом конкретном контексте для нацеливания на все теги dl?

Пример моего аккордеона можно найти здесь: https://codepen.io/anon/pen/QYwQqV

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Как насчет этого:

// collect all dl elements
const accordion = {
  definitionLists: Array.from(document.querySelectorAll("dl")),
  translate: 0
}

// get all button elements inside of each dl in a single array
const buttons = accordion.definitionLists.reduce((acc, dl) => {
  let currentDlButtons = Array.from(dl.getElementsByTagName("button"), 
   element => ({
     element,
     translate: 0
    }));
  return acc.concat(currentDlButtons);
}, []);
0 голосов
/ 23 января 2019

Вот обновленный CodePen , использующий Array.from(document.querySelectorAll('dl')) для нацеливания на каждый dl в документе:

https://codepen.io/jo_va/pen/OdVpbJ

Поскольку теперь существует несколько аккордеонов, я сначала строю массив аккордеонов и модифицирую почти все функции, чтобы в качестве первых параметров использовать аккордеон и список кнопок.

В конце вам просто нужно перебрать аккордеоны и выполнить ту же логику, что и у вас, но параметризованную для текущего аккордеона и его кнопок.

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"

Надеюсь, я правильно понял вашу проблему, и это вам поможет.

Приветствие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...