使用React+ts實(shí)現(xiàn)無縫滾動的走馬燈詳細(xì)過程
一、走馬燈的作用
走馬燈是一種常見的網(wǎng)頁交互組件,可以展示多張圖片或者內(nèi)容,通過自動播放或者手動切換的方式,讓用戶能夠方便地瀏覽多張圖片或者內(nèi)容。本次實(shí)現(xiàn)的不是輪播圖而是像傳送帶一樣的無限滾動的形式。
二、需求梳理
走馬燈可設(shè)置一下屬性:
- 滾動速度
- 滾動方向
- 一屏要顯示項(xiàng)的個(gè)數(shù)
- 容器的寬度
- 要展示的數(shù)據(jù)
- 自定義展示項(xiàng)
三、實(shí)現(xiàn)思路
3.1 首先確定一下我們的dom元素
wrap>list>item*n
- 最外層wrap用于限制顯示區(qū)域的寬度,超過寬度就隱藏。
- list 用于滾動顯示數(shù)據(jù),所以我們的動畫加在這個(gè)元素上。
- item 用于放置展示項(xiàng)。
3.2 實(shí)現(xiàn)無限滾動的動畫
我們用keyframes關(guān)鍵幀動畫來做。但是要滾動多少距離才能實(shí)現(xiàn)無限滾動呢?
1.計(jì)算動畫滾動距離
從上面的圖中我們可以看到當(dāng)list的寬度<wrap的寬度(containerWidth)時(shí),會出現(xiàn)滾動后出現(xiàn)空白的情況。那么第二張圖,list的寬度>=wrap的兩倍,就能在向左滾動完list的一半后,不會出現(xiàn)空白,而且為了給人一種無限滾動的效果,list的前后兩部分?jǐn)?shù)據(jù)要保持一致。所以滾動的距離 = 展示數(shù)據(jù)的個(gè)數(shù) * 每項(xiàng)的寬度,而為了無限滾動效果,我們還需要對原始數(shù)據(jù)進(jìn)行處理。分為以下幾種情況:
- 數(shù)據(jù)個(gè)數(shù)>= 一屏展示個(gè)數(shù)(showNum)
此時(shí)重復(fù)兩次原始數(shù)據(jù)就能得到滾動數(shù)據(jù)
- 數(shù)據(jù)個(gè)數(shù)< 一屏展示個(gè)數(shù)
首先我們要保證沒有空白,那要如何填充呢?只填充到=showNum,行不行呢?我們可以看一下:比如說原始數(shù)據(jù)為[1,2,3],填充完再進(jìn)行重復(fù)則為 [1,2,3,1,1,2,3,1],這樣會出現(xiàn)1這一項(xiàng)連續(xù)出現(xiàn)了。所以最好的方式是直接填充原始數(shù)據(jù)直到>=showNum,所以最終我們得到的滾動數(shù)據(jù)是[1,2,3,1,2,3 ,1,2,3,1,2,3]
2.插入動畫
因?yàn)槲覀兊膭赢嬍歉鶕?jù)傳入的變量得來的,所以不能直接寫在樣式文件里,我們通過在useEffect里插入樣式表對象的方式來實(shí)現(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)建一個(gè)新的樣式表對象 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 { /*鼠標(biāo)經(jīng)過后,動畫暫停*/ animation-play-state: paused !important; }`; } // 將樣式表插入到文檔頭部 document.head.appendChild(style); // 組件卸載時(shí)清除樣式表 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é)
到此這篇關(guān)于使用React+ts實(shí)現(xiàn)無縫滾動的走馬燈的文章就介紹到這了,更多相關(guān)React+ts實(shí)現(xiàn)無縫滾動走馬燈內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在React項(xiàng)目中使用iframe嵌入一個(gè)網(wǎng)站的步驟
本文介紹了如何在React項(xiàng)目中通過iframe嵌入百度網(wǎng)站的步驟,首先創(chuàng)建一個(gè)Baidu.js組件,并在該組件中設(shè)置iframe來加載百度,然后在App.js中引入并使用Baidu組件,還討論了因安全策略可能無法加載某些網(wǎng)站的問題,需要的朋友可以參考下2024-09-09React子組件調(diào)用父組件方法獲取的數(shù)據(jù)不是最新值的解決方法
這篇文章主要介紹了React子組件調(diào)用父組件方法獲取的數(shù)據(jù)不是最新值的解決方法,文中通過代碼示例介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-09-09JavaScript的React框架中的JSX語法學(xué)習(xí)入門教程
這篇文章主要介紹了JavaScript的React框架中的JSX語法學(xué)習(xí)入門教程,React是由Facebook開發(fā)并開源的高人氣js框架,需要的朋友可以參考下2016-03-03解決React報(bào)錯(cuò)Rendered more hooks than during
這篇文章主要為大家介紹了React報(bào)錯(cuò)Rendered more hooks than during the previous render解決方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12簡析React Native startReactApplication 方法
這篇文章主要介紹了React Native startReactApplication 方法簡析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09使用VScode 插件debugger for chrome 調(diào)試react源碼的方法
這篇文章主要介紹了使用VScode 插件debugger for chrome 調(diào)試react源碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09