|
|
@ -83,40 +83,84 @@ function initMembersCarousel() { |
|
|
const el = root.querySelector(".ab-members__panels-swiper"); |
|
|
const el = root.querySelector(".ab-members__panels-swiper"); |
|
|
const buttons = [...root.querySelectorAll(".ab-members__logo")]; |
|
|
const buttons = [...root.querySelectorAll(".ab-members__logo")]; |
|
|
if (!el || !buttons.length) return; |
|
|
if (!el || !buttons.length) return; |
|
|
|
|
|
|
|
|
|
|
|
const mobileMq = window.matchMedia("(max-width: 576px)"); |
|
|
|
|
|
const getGroupSize = () => mobileMq.matches ? 2 : 5; |
|
|
|
|
|
const total = buttons.length; |
|
|
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; |
|
|
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; |
|
|
const canLoop = buttons.length > 1; |
|
|
|
|
|
|
|
|
const initial = Math.max(0, buttons.findIndex((btn) => btn.classList.contains("is-active"))); |
|
|
|
|
|
|
|
|
const swiper = new SwiperCtor(el, { |
|
|
const swiper = new SwiperCtor(el, { |
|
|
initialSlide: Math.max(0, buttons.findIndex((btn) => btn.classList.contains("is-active"))), |
|
|
|
|
|
loop: canLoop, |
|
|
|
|
|
|
|
|
initialSlide: initial, |
|
|
|
|
|
loop: false, |
|
|
grabCursor: true, |
|
|
grabCursor: true, |
|
|
speed: 600, |
|
|
speed: 600, |
|
|
autoplay: canLoop && !reduceMotion ? { |
|
|
|
|
|
delay: 3e3, |
|
|
|
|
|
disableOnInteraction: false, |
|
|
|
|
|
pauseOnMouseEnter: true |
|
|
|
|
|
} : false |
|
|
|
|
|
|
|
|
autoplay: false |
|
|
}); |
|
|
}); |
|
|
const logos = root.querySelector(".ab-members__logos"); |
|
|
|
|
|
|
|
|
|
|
|
const syncNav = (index) => { |
|
|
const syncNav = (index) => { |
|
|
|
|
|
const GROUP = getGroupSize(); |
|
|
|
|
|
const groupStart = Math.floor(index / GROUP) * GROUP; |
|
|
buttons.forEach((btn, i) => { |
|
|
buttons.forEach((btn, i) => { |
|
|
|
|
|
const inGroup = total <= GROUP || (i >= groupStart && i < groupStart + GROUP); |
|
|
|
|
|
btn.hidden = !inGroup; |
|
|
const on = i === index; |
|
|
const on = i === index; |
|
|
btn.classList.toggle("is-active", on); |
|
|
btn.classList.toggle("is-active", on); |
|
|
btn.setAttribute("aria-selected", on ? "true" : "false"); |
|
|
btn.setAttribute("aria-selected", on ? "true" : "false"); |
|
|
}); |
|
|
}); |
|
|
const btn = buttons[index]; |
|
|
|
|
|
if (logos && btn) { |
|
|
|
|
|
const left = btn.offsetLeft - (logos.clientWidth - btn.offsetWidth) / 2; |
|
|
|
|
|
logos.scrollTo({ left: Math.max(0, left), behavior: "smooth" }); |
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const goTo = (index) => { |
|
|
|
|
|
const next = Math.max(0, Math.min(index, total - 1)); |
|
|
|
|
|
swiper.slideTo(next); |
|
|
|
|
|
syncNav(next); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
/** 组内下一项;组末跳到下一组第一个;全部结束后回到 0 */ |
|
|
|
|
|
const nextInSequence = () => { |
|
|
|
|
|
const GROUP = getGroupSize(); |
|
|
|
|
|
const i = swiper.activeIndex; |
|
|
|
|
|
const groupStart = Math.floor(i / GROUP) * GROUP; |
|
|
|
|
|
const groupEnd = Math.min(groupStart + GROUP - 1, total - 1); |
|
|
|
|
|
if (i < groupEnd) goTo(i + 1); |
|
|
|
|
|
else if (groupEnd + 1 < total) goTo(groupEnd + 1); |
|
|
|
|
|
else goTo(0); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let timer = null; |
|
|
|
|
|
const stopAutoplay = () => { |
|
|
|
|
|
if (timer) { |
|
|
|
|
|
clearInterval(timer); |
|
|
|
|
|
timer = null; |
|
|
} |
|
|
} |
|
|
}; |
|
|
}; |
|
|
|
|
|
const startAutoplay = () => { |
|
|
|
|
|
stopAutoplay(); |
|
|
|
|
|
if (reduceMotion || total <= 1) return; |
|
|
|
|
|
timer = setInterval(nextInSequence, 3e3); |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
buttons.forEach((btn, i) => { |
|
|
buttons.forEach((btn, i) => { |
|
|
btn.addEventListener("click", () => { |
|
|
btn.addEventListener("click", () => { |
|
|
if (canLoop) swiper.slideToLoop(i); |
|
|
|
|
|
else swiper.slideTo(i); |
|
|
|
|
|
|
|
|
goTo(i); |
|
|
|
|
|
startAutoplay(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
swiper.on("slideChange", () => syncNav(swiper.realIndex)); |
|
|
|
|
|
syncNav(swiper.realIndex); |
|
|
|
|
|
|
|
|
swiper.on("slideChange", () => syncNav(swiper.activeIndex)); |
|
|
|
|
|
|
|
|
|
|
|
const onGroupBreakpoint = () => { |
|
|
|
|
|
syncNav(swiper.activeIndex); |
|
|
|
|
|
startAutoplay(); |
|
|
|
|
|
}; |
|
|
|
|
|
if (mobileMq.addEventListener) mobileMq.addEventListener("change", onGroupBreakpoint); |
|
|
|
|
|
else mobileMq.addListener(onGroupBreakpoint); |
|
|
|
|
|
|
|
|
|
|
|
const card = root.querySelector(".ab-members__card"); |
|
|
|
|
|
card?.addEventListener("mouseenter", stopAutoplay); |
|
|
|
|
|
card?.addEventListener("mouseleave", startAutoplay); |
|
|
|
|
|
|
|
|
|
|
|
syncNav(swiper.activeIndex); |
|
|
|
|
|
startAutoplay(); |
|
|
} |
|
|
} |
|
|
$(function() { |
|
|
$(function() { |
|
|
setActiveNav(); |
|
|
setActiveNav(); |
|
|
|