使用React+ts實現(xiàn)無縫滾動的走馬燈詳細過程
一、走馬燈的作用
走馬燈是一種常見的網(wǎng)頁交互組件,可以展示多張圖片或者內(nèi)容,通過自動播放或者手動切換的方式,讓用戶能夠方便地瀏覽多張圖片或者內(nèi)容。本次實現(xiàn)的不是輪播圖而是像傳送帶一樣的無限滾動的形式。
二、需求梳理
走馬燈可設置一下屬性:
- 滾動速度
- 滾動方向
- 一屏要顯示項的個數(shù)
- 容器的寬度
- 要展示的數(shù)據(jù)
- 自定義展示項

三、實現(xiàn)思路
3.1 首先確定一下我們的dom元素
wrap>list>item*n
- 最外層wrap用于限制顯示區(qū)域的寬度,超過寬度就隱藏。
- list 用于滾動顯示數(shù)據(jù),所以我們的動畫加在這個元素上。
- item 用于放置展示項。
3.2 實現(xiàn)無限滾動的動畫
我們用keyframes關鍵幀動畫來做。但是要滾動多少距離才能實現(xiàn)無限滾動呢?
1.計算動畫滾動距離

從上面的圖中我們可以看到當list的寬度<wrap的寬度(containerWidth)時,會出現(xiàn)滾動后出現(xiàn)空白的情況。那么第二張圖,list的寬度>=wrap的兩倍,就能在向左滾動完list的一半后,不會出現(xiàn)空白,而且為了給人一種無限滾動的效果,list的前后兩部分數(shù)據(jù)要保持一致。所以滾動的距離 = 展示數(shù)據(jù)的個數(shù) * 每項的寬度,而為了無限滾動效果,我們還需要對原始數(shù)據(jù)進行處理。分為以下幾種情況:
- 數(shù)據(jù)個數(shù)>= 一屏展示個數(shù)(showNum)
此時重復兩次原始數(shù)據(jù)就能得到滾動數(shù)據(jù)
- 數(shù)據(jù)個數(shù)< 一屏展示個數(shù)
首先我們要保證沒有空白,那要如何填充呢?只填充到=showNum,行不行呢?我們可以看一下:比如說原始數(shù)據(jù)為[1,2,3],填充完再進行重復則為 [1,2,3,1,1,2,3,1],這樣會出現(xiàn)1這一項連續(xù)出現(xiàn)了。所以最好的方式是直接填充原始數(shù)據(jù)直到>=showNum,所以最終我們得到的滾動數(shù)據(jù)是[1,2,3,1,2,3 ,1,2,3,1,2,3]
2.插入動畫
因為我們的動畫是根據(jù)傳入的變量得來的,所以不能直接寫在樣式文件里,我們通過在useEffect里插入樣式表對象的方式來實現(xiàn)。
四、完整代碼
組件代碼
import { ReactElement, useEffect } from "react";
import * as React from "react";
import "./index.less";
import { ItemProps } from "./demo";
interface Props {
Item: (item: ItemProps) => ReactElement;
showNum: number;
speed: number;
containerWidth: number;
data: Array<any>;
hoverStop?: boolean;
direction?: "left" | "right";
}
const fillArray = (arr: any[], length: number): any[] => {
const result: any[] = [];
while (result.length < length) {
result.push(...arr);
}
return result.concat(result);
};
function AutoplayCarousel({
Item,
showNum,
speed,
containerWidth,
data,
hoverStop = false,
direction = "left"
}: Props) {
const showData = fillArray(data, showNum);
const length = showData.length;
const itemWidth = containerWidth / showNum;
useEffect(() => {
// 創(chuàng)建一個新的樣式表對象
const style = document.createElement("style");
// 定義樣式表的內(nèi)容
let start = "0";
let end = `-${(itemWidth * length) / 2}`;
if (direction === "right") {
start = end;
end = "0";
}
style.innerText = `
@keyframes templates-partner-moving {
0% {
transform: translateX(${start}px);
}
100% {
transform: translateX(${end}px);
}
}
`;
if (hoverStop) {
style.innerText += `.list:hover {
/*鼠標經(jīng)過后,動畫暫停*/
animation-play-state: paused !important;
}`;
}
// 將樣式表插入到文檔頭部
document.head.appendChild(style);
// 組件卸載時清除樣式表
return () => document.head.removeChild(style) as any;
}, []);
return (
<div style={{ width: `${containerWidth}px` }} className="wrap">
<div
className="list"
style={{
width: `${itemWidth * length}px`,
animation: `templates-partner-moving ${
(length / showNum / 2) * speed
}s infinite linear`
}}
>
{showData.map((item) => (
<div style={{ width: `${itemWidth}px` }}>
<Item {...item} />
</div>
))}
</div>
</div>
);
}
export default AutoplayCarousel;demo代碼
import React from "react";
import AutoplayCarousel from "./index";
const data = new Array(5).fill(0).map((item, index) => {
return { num: index };
});
console.log("data", data);
export interface ItemProps {
num: number;
}
const itemStyle = {
border: "1px solid #ccc",
background: "#fff",
height: "50px",
color: "red",
marginRight: "15px"
};
function Demo() {
const Item = (item: ItemProps) => {
return <div style={itemStyle}>{item.num}</div>;
};
return (
<AutoplayCarousel
Item={Item}
containerWidth={500}
showNum={5}
speed={8}
data={data}
/>
);
}
export default Demo;樣式代碼
* {
margin: 0;
padding: 0;
}
.wrap {
overflow: hidden;
.list {
position: relative;
top: 0px;
left: 0px;
height: 100%;
display: flex;
}
}總結(jié)
到此這篇關于使用React+ts實現(xiàn)無縫滾動的走馬燈的文章就介紹到這了,更多相關React+ts實現(xiàn)無縫滾動走馬燈內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
在React項目中使用iframe嵌入一個網(wǎng)站的步驟
本文介紹了如何在React項目中通過iframe嵌入百度網(wǎng)站的步驟,首先創(chuàng)建一個Baidu.js組件,并在該組件中設置iframe來加載百度,然后在App.js中引入并使用Baidu組件,還討論了因安全策略可能無法加載某些網(wǎng)站的問題,需要的朋友可以參考下2024-09-09
React子組件調(diào)用父組件方法獲取的數(shù)據(jù)不是最新值的解決方法
這篇文章主要介紹了React子組件調(diào)用父組件方法獲取的數(shù)據(jù)不是最新值的解決方法,文中通過代碼示例介紹的非常詳細,對大家的學習或工作有一定的幫助,需要的朋友可以參考下2024-09-09
JavaScript的React框架中的JSX語法學習入門教程
這篇文章主要介紹了JavaScript的React框架中的JSX語法學習入門教程,React是由Facebook開發(fā)并開源的高人氣js框架,需要的朋友可以參考下2016-03-03
解決React報錯Rendered more hooks than during
這篇文章主要為大家介紹了React報錯Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-12-12
簡析React Native startReactApplication 方法
這篇文章主要介紹了React Native startReactApplication 方法簡析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
使用VScode 插件debugger for chrome 調(diào)試react源碼的方法
這篇文章主要介紹了使用VScode 插件debugger for chrome 調(diào)試react源碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09

