JS實現(xiàn)跑馬燈效果主要有三種方案:1.基于css overflow:hidden和js定時器,2.使用css animation動畫,3.利用canvas繪圖。第一種方案通過overflow:hidden隱藏超出容器文字,并用js定時器不斷改變marginleft實現(xiàn)滾動;第二種方案使用css animation定義關(guān)鍵幀動畫,代碼簡潔性能好但靈活性較差;第三種方案使用canvas繪制文字并動態(tài)更新位置,靈活性高但實現(xiàn)復(fù)雜。性能優(yōu)化技巧包括減少dom操作、使用requestanimationframe替代setinterval、節(jié)流控制頻率、使用transform代替left/top屬性、避免復(fù)雜css樣式。要實現(xiàn)文字從左向右循環(huán)滾動,需修改marginleft或x的初始值為負文字寬度,并調(diào)整判斷條件使文字完全移出右側(cè)后重新從左側(cè)開始。要讓跑馬燈滾動到指定位置停止,可在js方案中清除定時器,在css方案中動態(tài)移除動畫class,在canvas方案中取消動畫幀請求,并設(shè)置最終位置確保文字停在目標點。選擇方案應(yīng)根據(jù)需求權(quán)衡實現(xiàn)難度與性能表現(xiàn)。
跑馬燈效果,簡單來說,就是讓文字像走馬燈一樣滾動起來。JS實現(xiàn)跑馬燈效果,核心在于利用定時器不斷改變文字的位置,造成動態(tài)滾動的視覺效果。
解決方案
實現(xiàn)跑馬燈效果,主要有三種方案:
- 基于CSS overflow: hidden 和 JS 定時器: 這是最常見的方案,也是比較容易理解的一種。
- 使用 CSS animation 動畫: 這種方案性能更好,代碼更簡潔,但需要一定的CSS基礎(chǔ)。
- 利用 Canvas 繪圖: 這種方案最靈活,可以實現(xiàn)各種復(fù)雜的跑馬燈效果,但實現(xiàn)起來也最復(fù)雜。
下面分別介紹這三種方案:
方案一:CSS overflow: hidden + JS 定時器
這種方案的原理是,將需要滾動的文字放在一個容器中,容器設(shè)置 overflow: hidden,然后使用 JS 定時器不斷改變文字容器的 marginLeft 或 marginRight 屬性,使文字滾動起來。
<div id="marquee-container" style="max-width:90%"> <span id="marquee-text">這是一段需要滾動的文字,長度超過容器寬度才能看到效果。</span> </div> <script> const marqueeContainer = document.getElementById('marquee-container'); const marqueeText = document.getElementById('marquee-text'); let marginLeft = 200; function marquee() { marginLeft--; if (marginLeft < -marqueeText.offsetWidth) { marginLeft = 200; // 從右側(cè)重新開始 } marqueeText.style.marginLeft = marginLeft + 'px'; } setInterval(marquee, 20); </script>
這段代碼的關(guān)鍵在于:
- overflow: hidden:隱藏超出容器寬度的文字。
- white-space: nowrap:防止文字換行,保證文字在同一行滾動。
- marginLeft:控制文字的水平位置。
- setInterval:定時調(diào)用 marquee 函數(shù),不斷改變 marginLeft 的值。
方案二:CSS animation 動畫
這種方案使用 CSS animation 來實現(xiàn)跑馬燈效果,代碼更簡潔,性能更好。
<div id="marquee-container" style="width: 200px; overflow: hidden;"> <span id="marquee-text" style="display: inline-block; padding-left: 100%; animation: marquee 10s linear infinite;"> 這是一段需要滾動的文字,長度超過容器寬度才能看到效果。 </span> </div> <style> @keyframes marquee { 0% { transform: translateX(0%); } 100% { transform: translateX(-100%); } } </style>
這段代碼的關(guān)鍵在于:
- animation: marquee 10s linear infinite:定義了一個名為 marquee 的動畫,持續(xù)時間為 10 秒,線性運動,無限循環(huán)。
- @keyframes marquee:定義了動畫的關(guān)鍵幀,從 translateX(0%) 到 translateX(-100%),使文字從右向左滾動。
- padding-left: 100%:讓文字一開始出現(xiàn)在容器的右側(cè)。
這種方案的優(yōu)點是性能好,代碼簡潔,缺點是靈活性稍差,不容易實現(xiàn)復(fù)雜的跑馬燈效果。
方案三:Canvas 繪圖
這種方案使用 Canvas 繪圖來實現(xiàn)跑馬燈效果,最靈活,可以實現(xiàn)各種復(fù)雜的跑馬燈效果,例如文字漸變、文字旋轉(zhuǎn)、文字顏色變化等。
<canvas id="marquee-canvas" width="200" height="30"></canvas> <script> const canvas = document.getElementById('marquee-canvas'); const ctx = canvas.getContext('2d'); const text = '這是一段需要滾動的文字,長度超過容器寬度才能看到效果。'; let x = 200; function marquee() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空畫布 ctx.font = '16px Arial'; ctx.fillStyle = 'black'; ctx.fillText(text, x, 20); x--; if (x < -ctx.measureText(text).width) { x = 200; } requestAnimationFrame(marquee); // 使用 requestAnimationFrame 優(yōu)化性能 } marquee(); </script>
這段代碼的關(guān)鍵在于:
- canvas.getContext(‘2d’):獲取 Canvas 的 2D 繪圖上下文。
- ctx.fillText(text, x, 20):在 Canvas 上繪制文字,x 表示文字的水平位置,20 表示文字的垂直位置。
- ctx.measureText(text).width:獲取文字的寬度。
- requestAnimationFrame(marquee):使用 requestAnimationFrame 來定時調(diào)用 marquee 函數(shù),可以獲得更好的性能。
這種方案的優(yōu)點是靈活性高,可以實現(xiàn)各種復(fù)雜的跑馬燈效果,缺點是實現(xiàn)起來比較復(fù)雜,需要一定的 Canvas 基礎(chǔ)。
JS跑馬燈性能優(yōu)化有哪些技巧?
性能優(yōu)化對于跑馬燈效果至關(guān)重要,尤其是在處理大量文本或高頻率滾動時。
-
減少DOM操作: 避免在循環(huán)中頻繁修改DOM。可以將需要更新的內(nèi)容先在內(nèi)存中處理好,然后一次性更新到DOM上。例如,在方案一中,可以先計算好新的marginLeft值,然后再設(shè)置marqueeText.style.marginLeft。
-
使用requestAnimationFrame: requestAnimationFrame 比 setInterval 或 setTimeout 更適合動畫,因為它會在瀏覽器重繪之前執(zhí)行,避免不必要的重繪和卡頓。方案三中已經(jīng)使用了requestAnimationFrame。
-
節(jié)流(Throttling): 如果跑馬燈的更新頻率過高,可以考慮使用節(jié)流技術(shù),限制一段時間內(nèi)只執(zhí)行一次更新。這可以減少CPU的負擔(dān),提高性能。
-
CSS動畫優(yōu)化: 如果使用CSS動畫,盡量使用transform屬性進行位移,而不是left或top。transform通常比改變布局屬性性能更好。
-
離屏渲染(Offscreen Rendering): 對于復(fù)雜的跑馬燈效果,可以先在離屏Canvas中渲染,然后再將離屏Canvas的內(nèi)容繪制到屏幕上。這可以避免在每次更新時都重新渲染整個畫面。
-
文字預(yù)渲染: 如果跑馬燈的文字內(nèi)容是固定的,可以預(yù)先將文字渲染成圖片,然后滾動圖片,而不是每次都重新渲染文字。
-
避免使用復(fù)雜的CSS樣式: 復(fù)雜的CSS樣式會增加瀏覽器的渲染負擔(dān),盡量使用簡單的CSS樣式來實現(xiàn)跑馬燈效果。
如何實現(xiàn)文字從左向右,循環(huán)滾動的跑馬燈效果?
要實現(xiàn)文字從左向右循環(huán)滾動,只需修改一下方案一和方案三中的邏輯即可。
方案一(CSS overflow: hidden + JS 定時器)修改:
<div id="marquee-container" style="width: 200px; overflow: hidden; white-space: nowrap;"> <span id="marquee-text">這是一段需要滾動的文字,長度超過容器寬度才能看到效果。</span> </div> <script> const marqueeContainer = document.getElementById('marquee-container'); const marqueeText = document.getElementById('marquee-text'); let marginLeft = -marqueeText.offsetWidth; // 從左側(cè)開始 function marquee() { marginLeft++; if (marginLeft > marqueeContainer.offsetWidth) { marginLeft = -marqueeText.offsetWidth; // 從左側(cè)重新開始 } marqueeText.style.marginLeft = marginLeft + 'px'; } setInterval(marquee, 20); </script>
關(guān)鍵修改點:
- marginLeft 初始值設(shè)置為 -marqueeText.offsetWidth,讓文字從左側(cè)開始。
- 判斷條件改為 marginLeft > marqueeContainer.offsetWidth,當(dāng)文字完全移出容器右側(cè)時,重新從左側(cè)開始。
方案三(Canvas 繪圖)修改:
<canvas id="marquee-canvas" width="200" height="30"></canvas> <script> const canvas = document.getElementById('marquee-canvas'); const ctx = canvas.getContext('2d'); const text = '這是一段需要滾動的文字,長度超過容器寬度才能看到效果。'; let x = -ctx.measureText(text).width; // 從左側(cè)開始 function marquee() { ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空畫布 ctx.font = '16px Arial'; ctx.fillStyle = 'black'; ctx.fillText(text, x, 20); x++; if (x > canvas.width) { x = -ctx.measureText(text).width; // 從左側(cè)重新開始 } requestAnimationFrame(marquee); // 使用 requestAnimationFrame 優(yōu)化性能 } marquee(); </script>
關(guān)鍵修改點:
- x 初始值設(shè)置為 -ctx.measureText(text).width,讓文字從左側(cè)開始。
- 判斷條件改為 x > canvas.width,當(dāng)文字完全移出畫布右側(cè)時,重新從左側(cè)開始。
如何讓跑馬燈文字滾動到指定位置后停止?
讓跑馬燈文字滾動到指定位置后停止,需要在代碼中添加一個判斷條件,當(dāng)文字滾動到指定位置時,停止定時器或動畫。
方案一(CSS overflow: hidden + JS 定時器)修改:
<div id="marquee-container" style="width: 200px; overflow: hidden; white-space: nowrap;"> <span id="marquee-text">這是一段需要滾動的文字,長度超過容器寬度才能看到效果。</span> </div> <script> const marqueeContainer = document.getElementById('marquee-container'); const marqueeText = document.getElementById('marquee-text'); let marginLeft = 200; const stopPosition = 50; // 指定停止的位置 let intervalId; function marquee() { marginLeft--; if (marginLeft < -marqueeText.offsetWidth) { marginLeft = 200; } if (marginLeft <= stopPosition) { clearInterval(intervalId); // 停止定時器 marqueeText.style.marginLeft = stopPosition + 'px'; // 最終位置 return; } marqueeText.style.marginLeft = marginLeft + 'px'; } intervalId = setInterval(marquee, 20); </script>
關(guān)鍵修改點:
- 添加 stopPosition 變量,指定停止的位置。
- 添加 intervalId 變量,保存定時器的 ID,方便停止定時器。
- 在 marquee 函數(shù)中,判斷 marginLeft 是否小于等于 stopPosition,如果是,則停止定時器,并設(shè)置文字的最終位置。
方案二(CSS animation 動畫)修改:
CSS動畫要停止,稍微麻煩一點,需要動態(tài)的添加和移除動畫class。
<div id="marquee-container" style="width: 200px; overflow: hidden;"> <span id="marquee-text" style="display: inline-block; padding-left: 100%;" class="marquee"> 這是一段需要滾動的文字,長度超過容器寬度才能看到效果。 </span> </div> <style> .marquee { animation: marquee 10s linear infinite; } @keyframes marquee { 0% { transform: translateX(0%); } 100% { transform: translateX(-100%); } } </style> <script> const marqueeText = document.getElementById('marquee-text'); const stopPosition = 50; // 指定停止的位置 // 假設(shè)在某個事件觸發(fā)時停止動畫 setTimeout(() => { marqueeText.classList.remove('marquee'); // 移除動畫class marqueeText.style.transform = `translateX(${stopPosition}px)`; // 設(shè)置最終位置 }, 5000); // 假設(shè)5秒后停止 </script>
關(guān)鍵修改點:
- 給 marquee-text 添加一個 class marquee,該 class 定義了動畫。
- 使用 setTimeout 模擬某個事件觸發(fā),然后移除 marquee class,停止動畫。
- 設(shè)置 marqueeText.style.transform,讓文字停留在指定位置。
方案三(Canvas 繪圖)修改:
<canvas id="marquee-canvas" width="200" height="30"></canvas> <script> const canvas = document.getElementById('marquee-canvas'); const ctx = canvas.getContext('2d'); const text = '這是一段需要滾動的文字,長度超過容器寬度才能看到效果。'; let x = 200; const stopPosition = 50; // 指定停止的位置 let animationFrameId; function marquee() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.font = '16px Arial'; ctx.fillStyle = 'black'; ctx.fillText(text, x, 20); if (x <= stopPosition) { cancelAnimationFrame(animationFrameId); // 停止動畫幀 x = stopPosition; // 最終位置 ctx.fillText(text, x, 20); // 確保最終位置顯示文字 return; } x--; animationFrameId = requestAnimationFrame(marquee); } marquee(); </script>
關(guān)鍵修改點:
- 添加 stopPosition 變量,指定停止的位置。
- 添加 animationFrameId 變量,保存 requestAnimationFrame 的 ID,方便停止動畫幀。
- 在 marquee 函數(shù)中,判斷 x 是否小于等于 stopPosition,如果是,則停止動畫幀,并設(shè)置文字的最終位置。
選擇哪種方案取決于具體的需求。如果需要簡單的跑馬燈效果,可以使用 CSS animation;如果需要復(fù)雜的跑馬燈效果,可以使用 Canvas 繪圖。在性能方面,CSS animation 通常比 JS 定時器性能更好,而 Canvas 繪圖的性能則取決于具體的實現(xiàn)方式。