【前端】react+ts 輪播圖的實現

一、場景描述

在很多網站的頁面中都有輪播圖,所以我想利用react.js和ts實現一個輪播圖。自動輪播圖已經在前面實現過了,如:https://blog.csdn.net/weixin_43872912/article/details/145622444?sharetype=blogdetail&sharerId=145622444&sharerefer=PC&sharesource=weixin_43872912&spm=1011.2480.3001.8118。
思維導圖可以在網站:https://download.csdn.net/download/weixin_43872912/90429355?spm=1001.2014.3001.5503下載高清原圖。
在這里插入圖片描述

二、問題拆解

輪播圖(如下圖輪播圖所示)的實現可以分為三個:
第一個是自動輪播,就是每過一定的時間自動變成下一張圖;
第二個是前后按鈕的輪播,就是按左右的按鈕,按左邊的按鈕時,跳轉到前一張圖,按右邊的按鈕時,跳轉到后一張圖。
第三個就是按底部的按鈕切換輪播圖。
在這里插入圖片描述
在這里插入圖片描述

三、相關知識

3.1 setTimeout與setInterval的用法與詳解

setTimeout是指過了多久之后執行內部代碼,一次性的;setInterval是每過多久就要執行一次代碼。setTimeout里面開啟計時器的話,就需要先過setTimeout的時間,然后過setInterval的一次時間才會運行第一次。

    var time = 0;setInterval(() => {time += 1;console.log("當前時間為" + time + "秒");}, 1000);let count = 0;//test setTimeout & setIntervalvar testTimeFunction = function () {setTimeout(() => {setInterval(() => {count += 1;console.log("count輸出了" + count + "次");}, 3000);}, 3000);};testTimeFunction();

運行結果如下圖所示:
在這里插入圖片描述

3.2 react中的ref,利用ref獲取dom元素,并對dom元素的class進行操作

import React, { useState, useRef } from "react”;const divRef = useRef<HTMLDivElement>(null);
//tsx部分
<div ref={divRef}><buttononClick={() => {console.log(divRef);let target = divRef.current as HTMLElement;  //ts里面要將其定義為htmlElement再操作target.classList.add("preActive");console.log(target);}}>打印ref</button>
</div>

四、輪播圖的按鈕部分實現

4.1 上一張和下一張的按鈕實現

在這里插入圖片描述
上一張和下一張的按鈕部分其實就是自動輪播部分的手動操作,這部分的內容關注一下自動輪播部分和手動輪播部分的聯動就可以了。
按鈕事件:
跳轉的按鈕事件, 可以看到其實就是設置了一下currentIndex,這是一個state,更新之后會引起組件渲染,然后就會更新dom元素的class。

//跳轉到上一張圖的按鈕事件。
<buttonclassName="carousel-control-prev"type="button"data-bs-target="#carouselExample"onClick={() => {//clearCrouselClass();setCurrentIndex((pre) => {let nowCurrentIndex =currentIndex.currentIndex - 1 === -1? img.length - 1: currentIndex.currentIndex - 1;let nowPreIndex =nowCurrentIndex - 1 === -1? img.length - 1: nowCurrentIndex - 1;let nownextIndex =nowCurrentIndex + 1 === img.length ? 0 : nowCurrentIndex + 1;return {preIndex: nowPreIndex,currentIndex: nowCurrentIndex,nextIndex: nownextIndex,};});}}
>
//跳轉到下一張圖的按鈕事件。
<buttonclassName="carousel-control-next"type="button"data-bs-target="#carouselExample"onClick={() => {//clearCrouselClass();setCurrentIndex((pre) => {let nowCurrentIndex =currentIndex.currentIndex + 1 === img.length? 0: currentIndex.currentIndex + 1;let nowPreIndex =nowCurrentIndex - 1 === -1? img.length - 1: nowCurrentIndex - 1;let nownextIndex =nowCurrentIndex + 1 === img.length ? 0 : nowCurrentIndex + 1;return {preIndex: nowPreIndex,currentIndex: nowCurrentIndex,nextIndex: nownextIndex,};});}}
>

手動換圖與自動輪播圖之間的不和諧在于,手動換圖后自動輪播還在執行會導致換兩次可能,所以手動換圖的時候需要停止自動輪播,結束后開啟。
換圖每次都會伴隨著cunrrentIndex的變動,所以在這里我們用useEffect去檢測cunrrentIndex的變化,只要變化就停止計時器,然后重新開啟。 — 這里我用了異步

 //開啟計時器,設置preIndex是當前index的前一個index(index-1),nextIndex是index+1const startAutoplay = async () => {interval.current = setInterval(() => {setCurrentIndex((preCurrentIndex) => {return {preIndex:((preCurrentIndex.currentIndex + 1) % img.length) - 1 === -1? img.length - 1: ((preCurrentIndex.currentIndex + 1) % img.length) - 1,currentIndex: (preCurrentIndex.currentIndex + 1) % img.length,nextIndex:((preCurrentIndex.currentIndex + 1) % img.length) + 1 === img.length? 0: ((preCurrentIndex.currentIndex + 1) % img.length) + 1,};});}, 3000);};const stopAutoPlay = () => {if (interval.current !== null) {clearInterval(interval.current as NodeJS.Timeout);interval.current = null;}};  useEffect(() => {clearInterval(interval.current as NodeJS.Timeout);interval.current = null;let target = imgRef.current as HTMLElement;console.log(target.childNodes);if (interval.current !== null) {stopAutoPlay();}if (interval.current === null) {   //避免因為定時器什么的緣故導致計時器多開startAutoplay();}//eslint-disable-next-line react-hooks/exhaustive-deps}, [currentIndex]);

4.2 底部小圓點按鈕

這塊部分就是將點擊按鈕所對應的圖片轉到主頁。這個要實現用setCurrentIndex()就可以,但是要加動畫,首先需要將目標頁先移到上一頁或者下一頁的位置,準備平移至主頁位置。所以,需要預先將目標圖移到動畫的起始位置。
在這里插入圖片描述
如上圖所示,如果是目標頁是當前頁的前面幾頁(目標頁的index比currentIndex小)。需要提前把目標頁移到上一頁的位置,反之,移到下一頁的位置。
移完之后設置currentIndex進行重新渲染。

if (index < currentIndex.currentIndex) {target.classList.add("preActive”);        //移到上一頁的位置,class設為preActive// target1.classList.add("nextActive");// target1.classList.remove("active");setTimeout(() => {setCurrentIndex((pre) => {console.log(currentIndex);// let nextIndex = index + 1 === img.length ? 0 : index + 1;// if(nextIndex === pre.currentIndex) return;return {preIndex:index - 1 === -1 ? img.length - 1 : index - 1,currentIndex: index,nextIndex: pre.currentIndex,};});}, 10);
} else if (index > currentIndex.currentIndex) {target.classList.add("nextActive”);     //移到下一頁的位置,class設為nextActive// target1.classList.add("preActive");// target1.classList.remove("active");console.log(currentIndex);setTimeout(() => {setCurrentIndex((pre) => {return {nextIndex:index + 1 === img.length ? 0 : index + 1,currentIndex: index,preIndex: pre.currentIndex,};});}, 10);
}

到此為止出現的問題:
和“自動輪播和前后按鈕換圖”之前的聯動出現的錯誤是:當跳到前面頁面的時候,下一頁的類名沒有nextActive所以跳到下一頁可能沒有動畫;相同的跳到前面頁的時候,上一頁的類名沒有preActive,可能沒有翻頁動畫。因此,我們要保證當前頁的前一頁類名有preActive,后一頁類名有nextActive.

<div
key={index}
className={`carousel-item ${index === currentIndex.currentIndex ? "active" : ""
}${index ===(currentIndex.currentIndex - 1 === -1? img.length - 1: currentIndex.currentIndex - 1) ||(index === currentIndex.preIndex )? "preActive": ""
} ${index ===(currentIndex.currentIndex + 1 === img.length? 0: currentIndex.currentIndex + 1) ||index === currentIndex.nextIndex? "nextActive": ""
}`}
>

這樣寫存在的錯誤是會造成同一個圖片有preActive和nextActive的情況
在這里插入圖片描述
解決方案:按鍵跳轉前的主頁是目標頁的下一頁:因此,當preIndex等于currentIndex+1不給preIndex

<div
key={index}
className={`carousel-item ${index === currentIndex.currentIndex ? "active" : ""
}${index ===(currentIndex.currentIndex - 1 === -1? img.length - 1: currentIndex.currentIndex - 1) ||//下面這部分代碼就是 當preIndex等于currentIndex+1不給preIndex(index === currentIndex.preIndex &&currentIndex.preIndex !==(currentIndex.currentIndex + 1 === img.length? 0: currentIndex.currentIndex + 1))? "preActive": ""
} ${index ===(currentIndex.currentIndex + 1 === img.length? 0: currentIndex.currentIndex + 1) ||index === currentIndex.nextIndex? "nextActive": ""
}`}
>

在這里插入圖片描述
五、遇到的問題

    useEffect(() => {console.log("停止計時器");console.log(currentIndex);clearInterval(interval.current as NodeJS.Timeout);interval.current = null;let target = imgRef.current as HTMLElement;console.log(target.childNodes);if (interval.current !== null) {stopAutoPlay();}//如果這里這樣寫會出現問題,如果在這三秒內點的話,就會導致setCurrentIndex的值都變成NaNsetTimeout(()=>{if (interval.current === null) {startAutoplay();}},3000)//eslint-disable-next-line react-hooks/exhaustive-deps}, [currentIndex]);//改完之后的版本useEffect(() => {console.log("停止計時器");console.log(currentIndex);clearInterval(interval.current as NodeJS.Timeout);interval.current = null;let target = imgRef.current as HTMLElement;console.log(target.childNodes);if (interval.current !== null) {stopAutoPlay();}
//改成異步函數,或者setTimeout的事件變短一點if (interval.current === null) {startAutoplay();}//eslint-disable-next-line react-hooks/exhaustive-deps}, [currentIndex]);

整個項目可以在下面鏈接下載:https://download.csdn.net/download/weixin_43872912/90429357?spm=1001.2014.3001.5501

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/70776.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70776.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70776.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python與C系列語言的差異總結(4)

如果具有傳統編譯型語言的經驗&#xff0c;大家可能會對是否使用字典而猶豫不決&#xff0c;擔心字典的效率比列表或數組低。事實上Python字典的執行速度已經相當快了。Python語言的許多內部特性都依賴于字典&#xff0c;為提高字典的效率已經投入了大量的心血。Python的所有數…

[Web 安全] 反序列化漏洞 - 學習筆記

關注這個專欄的其他相關筆記&#xff1a;[Web 安全] Web 安全攻防 - 學習手冊-CSDN博客 0x01&#xff1a;反序列化漏洞 — 漏洞介紹 反序列化漏洞是一種常見的安全漏洞&#xff0c;主要出現在應用程序將 序列化數據 重新轉換為對象&#xff08;即反序列化&#xff09;的過程中…

深入理解C語言中的位段

在C語言編程中&#xff0c;我們常常會遇到需要對內存進行精細控制的場景&#xff0c;位段&#xff08;bit - field&#xff09;便是C語言提供的一種強大工具&#xff0c;它允許我們在一個字節或多個字節內對數據進行按位的定義和操作&#xff0c;極大地提高了內存使用效率。 一…

實現使用RBF(徑向基函數)神經網絡模擬二階電機數學模型中的非線性干擾,以及使用WNN(小波神經網絡)預測模型中的非線性函數來抵消遲滯影響的功能

下面將詳細介紹如何實現使用RBF&#xff08;徑向基函數&#xff09;神經網絡模擬二階電機數學模型中的非線性干擾&#xff0c;以及使用WNN&#xff08;小波神經網絡&#xff09;預測模型中的非線性函數來抵消遲滯影響的功能。我們將按照以下步驟進行&#xff1a; 步驟1&#x…

Grouped-Query Attention(GQA)詳解: Pytorch實現

Grouped-Query Attention&#xff08;GQA&#xff09;詳解 Grouped-Query Attention&#xff08;GQA&#xff09; 是 Multi-Query Attention&#xff08;MQA&#xff09; 的改進版&#xff0c;它通過在 多個查詢頭&#xff08;Query Heads&#xff09;之間共享 Key 和 Value&am…

ReentrantLock 用法與源碼剖析筆記

&#x1f4d2; ReentrantLock 用法與源碼剖析筆記 &#x1f680; 一、ReentrantLock 核心特性 &#x1f504; 可重入性&#xff1a;同一線程可重復獲取鎖&#xff08;最大遞歸次數為 Integer.MAX_VALUE&#xff09;&#x1f527; 公平性&#xff1a;支持公平鎖&#xff08;按等…

基于GO語言的車牌識別api技術-港澳車牌文字識別

隨著科技的飛速發展&#xff0c;智能化管理逐漸滲透到我們生活的方方面面。車牌識別技術作為智能交通的重要組成部分&#xff0c;不僅極大提升了交通管理的效率&#xff0c;還為市民出行帶來了更多便利。而港澳地區的車牌識別技術&#xff0c;憑借其高效、精準、快速的特點&…

基于 DeepSeek LLM 本地知識庫搭建開源方案(AnythingLLM、Cherry、Ragflow、Dify)認知

寫在前面 博文內容涉及 基于 Deepseek LLM 的本地知識庫搭建使用 ollama 部署 Deepseek-R1 LLM知識庫能力通過 Ragflow、Dify 、AnythingLLM、Cherry 提供理解不足小伙伴幫忙指正 &#x1f603;,生活加油 我站在人潮中央&#xff0c;思考這日日重復的生活。我突然想&#xff0c…

PCB設計常用布局布線方法

PCB設計常用布局布線方法 **1.模塊化布局&#xff0c;**先放大器件再放小器件。 立創在原理圖框完后&#xff0c;在PCB快捷shiftp 2.布局對齊美觀 3.重要信號線優先處理 分類再畫 4.減少Stub布線&#xff1a;就是避免為連接的線段&#xff0c;防止產生“天線效應”&#xff…

Mac 版 本地部署deepseek ? RAGflow 知識庫搭建流程分享(附問題解決方法)

安裝&#xff1a; 1、首先按照此視頻的流程一步一步進行安裝&#xff1a;(macos版&#xff09;ragflowdeepseek 私域知識庫搭建流程分享_嗶哩嗶哩_bilibili 2、RAGflow 官網文檔指南&#xff1a;https://ragflow.io 3、RAGflow 下載地址&#xff1a;https://github.com/infi…

娛閑放鬆篇2

最近看了好多動畫和以前的新聞&#xff0c;都挺有想法&#xff0c;可以了解一下 有些是N年前的&#xff0c;希望見怪莫怪 若說如何用最小作用量去理解世界觀的話&#xff0c;其實就是書&#xff0c;以動畫的角度來看&#xff0c;日本動畫足以 一.高達系列 一系列的利用巨大…

OpenIPC開源FPV之Adaptive-Link安裝

OpenIPC開源FPV之Adaptive-Link安裝 1. 源由2. 介紹2.1 天空端安裝2.2 地面端安裝 3. 問題匯總3.1 安裝腳本問題3.2 網絡安裝問題3.3 非SSC30KQ/SSC338Q硬件3.4 代碼疑問 4. 總結5. 后續 1. 源由 鑒于飛行過程&#xff0c;發現一些馬賽克現象&#xff0c;且60FPS桌面30FPS的錄…

解析第十一頁

多選707、如圖所示組網,SWA、SWB、SWC、SWD運行RSTP,則以下說法正確的是? A、可以在SWB的GE0/0/2端口開啟邊緣端口,讓連接終端的接口快速進入轉發狀態 B、邊緣端口收到BPDU之后會重新參與生成樹的計算 C、可以在SWC的GEO/0/2端口開啟邊緣端口,讓連接終端的接口快速進入轉…

禾邁電力電子嵌入式面經和參考答案

CMakeLists 怎么寫? CMakeLists.txt 是 CMake 構建系統的配置文件,用于描述項目的構建規則和依賴關系。以下是一個簡單的 CMakeLists.txt 示例及基本寫法說明。 首先,指定 CMake 的最低版本要求,例如cmake_minimum_required(VERSION 3.10)。 然后,定義項目名稱,如project…

我的AI工具箱Tauri版-FluxCharacterGeneration參考圖像生成人像手辦(Flux 版)

本教程基于自研的AI工具箱Tauri版進行ComfyUI工作流FluxCharacterGeneration參考圖像生成人像手辦&#xff08;Flux 版&#xff09;。 我的AI工具箱Tauri版 - FluxCharacterGeneration參考圖像生成人像手辦&#xff08;Flux版&#xff09; 基于先進的FLUX模型&#xff0c;通過…

什么是DrawCall?DrawCall為什么會影響游戲運行效率?如何減少DrawCall?

目錄 1 什么是DrawCall&#xff1f; 2 DrawCall為什么會影響游戲運行效率&#xff1f; 3 如何減少 DrawCall&#xff1f;&#xff08;結合性能分析工具&#xff09; 1 什么是DrawCall&#xff1f; DrawCall&#xff08;繪制調用&#xff09; 是 GPU 的一個指令&#xff0c…

深入解析提示詞:從基礎到結構化應用

在人工智能蓬勃發展的當下&#xff0c;提示詞&#xff08;Prompt&#xff09;扮演著至關重要的角色。無論是在與聊天機器人交流&#xff0c;還是驅動復雜智能體完成任務&#xff0c;精準且高效的提示詞都能起到事半功倍的效果。本文將帶你全面了解提示詞&#xff0c;深入探索結…

【前端基礎】Day 2 HTML

目錄 1.表格標簽 2.列表標簽 3.表單標簽 4.綜合案例 5.查閱文檔 1.表格標簽 <body><table align"center" border"1" cellpadding"0" cellspacing"0" width"500" height"100"><thead> …

R與RStudio簡介及安裝

目錄 一、R與RStudio關系 二、R簡介 2.1. 發展歷史 2.2. R語言特點 三、安裝指南 3.1 R安裝指南 3.2 R studio安裝指南 一、R與RStudio關系 R是統計領域廣泛使用的工具&#xff0c;屬于GNU系統的一個自由、免費、源代碼開放的軟件&#xff0c;是 用于統計計算和統計繪圖…

20分鐘 Bash 上手指南

文章目錄 bash 概念與學習目的第一個 bash 腳本bash 語法變量的使用位置參數管道符號&#xff08;過濾條件&#xff09;重定向符號條件測試命令條件語句case 條件分支Arrayfor 循環函數exit 關鍵字 bash 腳本記錄歷史命令查詢文件分發內容 bash 概念與學習目的 bash&#xff0…