XML请求加载后CSS Marquee动画失效问题求助
解决XHR加载HTML后GSAP跑马灯动画失效问题
问题根源
- 原GSAP动画代码在页面初始
window.onload阶段执行,但此时通过XHR请求的跑马灯DOM还未插入页面,代码找不到目标元素,动画根本没初始化。 - 当跑马灯内容通过
innerHTML插入容器后,没有触发动画初始化逻辑,新插入的DOM元素从未被绑定GSAP动画。
修复方案
把GSAP动画逻辑封装成独立初始化函数,在XHR成功插入DOM后立即调用该函数,确保动画绑定到新插入的元素上。
修改后的完整代码
1. 更新后的marquee.js
function includeMarquee() { var xhr = new XMLHttpRequest(); var marqueeFilePath = 'marquee.html'; xhr.open('GET', marqueeFilePath, true); xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { var marqueeContent = xhr.responseText; var marqueeContainer = document.getElementById('marquee-container'); if (marqueeContainer) { marqueeContainer.innerHTML = marqueeContent; // 插入DOM后立即初始化动画 initMarqueeAnimation(); } } }; xhr.send(); } function initMarqueeAnimation() { // 遍历所有跑马灯行,初始化每个行的动画 const lines = document.querySelectorAll(".stb_line_single"); lines.forEach((line, i) => { const links = line.querySelectorAll("a"); const tl = horizontalLoop(links, { repeat: -1, // 改成-1实现无限循环,原1.7只循环1.7次就停了 speed: 1 + i / 5, reversed: i ? true : false, paddingRight: parseFloat(gsap.getProperty(links[0], "marginRight", "px")) }); links.forEach(link => { link.addEventListener("mouseenter", () => gsap.to(tl, {timeScale: 0, overwrite: true})); link.addEventListener("mouseleave", () => gsap.to(tl, {timeScale: i ? -1 : 1, overwrite: true})); }); }); } // horizontalLoop工具函数保持不变 function horizontalLoop(items, config) { items = gsap.utils.toArray(items); config = config || {}; let tl = gsap.timeline({repeat: config.repeat, paused: config.paused, defaults: {ease: "none"}, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100)}), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], xPercents = [], curIndex = 0, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? v => v : gsap.utils.snap(config.snap || 1), totalWidth, curX, distanceToStart, distanceToLoop, item, i; gsap.set(items, { xPercent: (i, el) => { let w = widths[i] = parseFloat(gsap.getProperty(el, "width", "px")); xPercents[i] = snap(parseFloat(gsap.getProperty(el, "x", "px")) / w * 100 + gsap.getProperty(el, "xPercent")); return xPercents[i]; } }); gsap.set(items, {x: 0}); totalWidth = items[length-1].offsetLeft + xPercents[length-1] / 100 * widths[length-1] - startX + items[length-1].offsetWidth * gsap.getProperty(items[length-1], "scaleX") + (parseFloat(config.paddingRight) || 0); for (i = 0; i < length; i++) { item = items[i]; curX = xPercents[i] / 100 * widths[i]; distanceToStart = item.offsetLeft + curX - startX; distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, "scaleX"); tl.to(item, {xPercent: snap((curX - distanceToLoop) / widths[i] * 100), duration: distanceToLoop / pixelsPerSecond}, 0) .fromTo(item, {xPercent: snap((curX - distanceToLoop + totalWidth) / widths[i] * 100)}, {xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false}, distanceToLoop / pixelsPerSecond) .add("label" + i, distanceToStart / pixelsPerSecond); times[i] = distanceToStart / pixelsPerSecond; } function toIndex(index, vars) { vars = vars || {}; (Math.abs(index - curIndex) > length / 2) && (index += index > curIndex ? -length : length); let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex]; if (time > tl.time() !== index > curIndex) { vars.modifiers = {time: gsap.utils.wrap(0, tl.duration())}; time += tl.duration() * (index > curIndex ? 1 : -1); } curIndex = newIndex; vars.overwrite = true; return tl.tweenTo(time, vars); } tl.next = vars => toIndex(curIndex+1, vars); tl.previous = vars => toIndex(curIndex-1, vars); tl.current = () => curIndex; tl.toIndex = (index, vars) => toIndex(index, vars); tl.times = times; if (config.reversed) { tl.vars.onReverseComplete(); tl.reverse(); } return tl; } window.onload = function () { includeMarquee(); };
2. 其他文件保持不变
- CSS样式(原代码中的CSS部分)
marquee.html(原跑马灯HTML结构)- 页面中的容器和脚本引用:
<div id="marquee-container"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script> <!-- 确保GSAP库先加载 --> <script src="/src/js/include-marquee.js"></script>
额外说明
- 把原动画代码中的
repeat:1.7改成了repeat:-1,实现真正的无限循环,避免动画跑1.7次后停止。 - 修复了原动画代码中未定义的
line和i变量问题,通过遍历所有.stb_line_single元素初始化每个跑马灯行的动画。 - 必须确保GSAP库在自定义脚本之前加载,否则会报错
gsap is not defined。
内容的提问来源于stack exchange,提问作者ambaamba
相关产品推荐
相关产品推荐

