日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

用react實現一個簡單的scrollView組件

瀏覽:30日期:2022-06-13 14:58:20
目錄效果設計考慮的問題1: 結構結構搭建邏輯處理問題總結效果

我們先看一下效果,大概就是希望點擊左邊按鈕 或者右邊按鈕將元素以 每一個 子選項卡長度單位進行精準偏移。

設計考慮的問題

在這之前,大家不妨思考一下這個需求給到你,你應該怎么去設計這個東西?

1 : 父盒子的長度多少 ? 如何控制多出的元素隱藏?

2 :我們應該如何進行偏移 ? 用定位還是位移 ? 他們有什么區別?如何保證偏移量一點不差?

3 :每次偏移的量是多少?如何處理邊界情況?

好,帶著以下幾個問題,我們一起來思考一下這個組件,應該如何封裝。

1: 結構

首先 , 結構如下圖,我們有一個 父盒子(content-wapper-hidden) ,還有一個子盒子內嵌在 父盒子中,父盒子負責元素的溢出隱藏,固定寬度,子盒子負責渲染,和滾動。

結構搭建

scrollView.tsx

import { ReactNode, memo, useRef } from 'react'import { ScrollViewWapper } from './style'interface ScrollViewProps { children: ReactNode}const ScrollView = memo(( { children }: ScrollViewProps) => { const contentRef = useRef<HTMLDivElement>(null) return ( <ScrollViewWapper> <div className='leftIcon'>左邊</div> <div className='content-wapper-hidden'><div className='render-content' ref={contentRef}> {children}</div> </div> <div className='rightIcon'>右邊</div> </ScrollViewWapper> )})export default ScrollView邏輯處理

1 : 接下來 我們分別給兩個 按鈕綁定事件 , 并且 在初始化的時候 去計算 最大可偏移的值,

import { ReactNode, memo, useEffect, useRef, useState } from 'react'import { ScrollViewWapper } from './style'interface ScrollViewProps { children: ReactNode}const ScrollView = memo(( { children }: ScrollViewProps) => { const contentRef = useRef<HTMLDivElement>(null) const [maxoffset, setMaxOffset] = useState(0) // 兩者最大的偏移量 可滾動距離 const [currentOffsetIndex, setCurrentOffsetIndex] = useState(0) // 當前滾動元素的索引 const handelIconClick = (isRoght: boolean) => { // 事件處理函數 } function getScrollOffset() { const scrollWidth = contentRef.current!.scrollWidth const clientWidth = contentRef.current!.clientWidth setMaxOffset(scrollWidth - clientWidth) // 計算最大偏移量 } useEffect(() => { getScrollOffset() }, []) return ( <ScrollViewWapper> <div className='leftIcon' onClick={() => handelIconClick(false)}>左邊</div> <div className='content-wapper-hidden'><div className='render-content' ref={contentRef}> {children}</div> </div> <div className='rightIcon' onClick={() => handelIconClick(true)}>右邊</div> </ScrollViewWapper> )})export default ScrollView

在這里我們通過 ref 綁定了 一個 內容元素 ,然后 初始化的時候 ,我們去計算了元素最大可滾動的距離, 然后當我們點擊了 按鈕時 我們獲取了 contentRef 下所有 綁定 類名為 item的元素,點擊時判斷 是否為 右側 如果是 右側 點擊 則 索引 + 1 否則 索引 -1 ,然后做邊界處理,依次獲得item的 offsetLeft ,注意 offsetleft 是相對于 父級元素的距離,然后 將元素 contentRef 進行 translate 位移

import { ReactNode, memo, useEffect, useRef, useState } from 'react'import { ScrollViewWapper } from './style'interface ScrollViewProps { children: ReactNode}const ScrollView = memo(( { children }: ScrollViewProps) => { const contentRef = useRef<HTMLDivElement>(null) const [maxoffset, setMaxOffset] = useState(0) // 兩者最大的偏移量 可滾動距離 const [currentOffsetIndex, setCurrentOffsetIndex] = useState(0) const [isContinueScroll, setisContinueScroll] = useState(true) const handelIconClick = (isRight: boolean) => { const newIndex = isRight ? currentOffsetIndex + 1 : currentOffsetIndex - 1 if (newIndex < 0 || (!isContinueScroll && isRight)) return // 邊界處理 const TabAllList = getAllElements('item', 'class') // 獲取conntentRef 下面的 所有 item 子節點 const TabItem = TabAllList[newIndex] as HTMLDivElement // 獲取下一個 準備滾動元素 const TabItemOffsetLeft = TabItem.offsetLeft contentRef.current!.style.transform = `translateX(${-TabItemOffsetLeft}px)` setisContinueScroll(maxoffset > TabItemOffsetLeft) // 是否能繼續滾動 如果 你的 offsetLeft 都 // 比我可滾動距離大了 , 則肯定是不能滾動的 setCurrentOffsetIndex(newIndex) } const getAllElements = (querySelectorName: string, type: 'id' | 'class' | 'el' = 'class') => { let seletorName = null if (type === 'id') { // 對選擇器 做不同類型處理 seletorName = `#${querySelectorName.replace(/\^#/, '')}` } else if (type == 'class') { seletorName = `.${querySelectorName.replace(/\^./, '')}` } else { seletorName = `${querySelectorName.replace(/\^(.|#)/, '')}` } return contentRef.current!.querySelectorAll(seletorName) } function getScrollOffset() { const scrollWidth = contentRef.current!.scrollWidth const clientWidth = contentRef.current!.clientWidth setMaxOffset(scrollWidth - clientWidth) } useEffect(() => { getScrollOffset() }, []) return ( <ScrollViewWapper> <div className='leftIcon' onClick={() => handelIconClick(false)}>左邊</div> <div className='content-wapper-hidden'><div className='render-content' ref={contentRef}> {children}</div> </div> <div className='rightIcon' onClick={() => handelIconClick(true)}>右邊</div> </ScrollViewWapper> )})export default ScrollView

外部使用ScrollView 組件

import classNames from 'classnames';import { memo, useState } from 'react';import ScrollView from './components';const Login = memo(() => { const [list, setList] = useState(['YYDS', '易烊千璽', '李易峰', '雞哥', '古巨基', '羅志祥', '肖站', '彭于晏']) const [currentIndex, setCurrentIndex] = useState(0) return ( <div id='danmu-container'> <ScrollView>{ list.map((item, index) => { return ( <div className='item' key={item} onClick={() => setCurrentIndex(index)}><div className={classNames('tab-item', currentIndex === index ? 'active' : '')}>{item}</div> </div> ) })} </ScrollView> </div> )})export default Login

ok 到這里 scrollView 組件就簡單的封裝完成了 , 當然你還可以集成 點擊某個選項時 再進行偏移也是可以的,額可以拓展一下。

問題

為什么 用 tranform 而不是定位 ?

答案很簡單 : 定位移動的回引發視圖重繪,而transform 不會觸發重回,出于這一點可以在性能上做優化,當然 掘友在上一張 彈幕的文章中也講到 這一點,謝謝大家

總結

總結下來,這個組件 我們主要做的就是它的transform ,當然還有更多的功能大家可以拓展一下,如果你覺得還有哪些可以補充的,歡迎評論區留言。

以上就是用react實現一個簡單的scrollView組件的詳細內容,更多關于react實現scrollView組件的資料請關注好吧啦網其它相關文章!

標簽: JavaScript
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
麻豆成人av在线| 欧美精品中文| 精品伊人久久久| 国产日韩一区| 日本免费新一区视频| 日韩三级一区| 欧美精品三级在线| 九九九精品视频| 啪啪国产精品| 狠狠爱成人网| 一区二区三区网站| 在线日韩成人| 国产精品成人3p一区二区三区| 国产精品v日韩精品v欧美精品网站| 国产精品22p| 国产精品久久久免费| 成人在线丰满少妇av| 五月天久久777| 日韩午夜视频在线| 手机在线电影一区| 日韩专区在线视频| 久久精品伊人| aa国产精品| 国产毛片精品| 美女久久久久| 国产精品色婷婷在线观看| 97视频热人人精品免费| 黄色日韩精品| 国产女人18毛片水真多18精品| 久久精品国产99久久| 美女网站视频一区| 国产综合婷婷| 亚洲aa在线| 国产精品蜜月aⅴ在线| 久久中文视频| 亚洲一二av| 精品国产不卡一区二区| 日韩久久精品网| 日韩手机在线| 国产黄大片在线观看| 欧美精品羞羞答答| 亚洲激情另类| 国产在线不卡一区二区三区| 日韩精品dvd| 欧美在线日韩| 亚洲天堂黄色| 日韩av资源网| 9色国产精品| 国产欧美啪啪| 久久国产三级| 9国产精品视频| 欧美一级久久| 99精品99| 另类欧美日韩国产在线| 亚洲午夜免费| 精品久久久久中文字幕小说| 日韩88av| 日韩成人精品一区二区三区| xxxxx性欧美特大| 国产免费av一区二区三区| 久久久精品网| 国产一区二区三区天码| 一区久久精品| 神马久久午夜| 日韩一区二区三区高清在线观看| 欧美午夜不卡| 欧美天堂在线| 免费精品国产| 久久久夜精品| 国产精品porn| 日本a级不卡| 另类综合日韩欧美亚洲| 亚洲精品四区| 欧美少妇精品| 精品久久91| 日本va欧美va瓶| 国产一级久久| 麻豆国产在线| 亚洲精品亚洲人成在线观看| av不卡免费看| 色婷婷综合网| 国产一区2区| 91成人精品观看| 亚洲专区视频| 午夜国产精品视频| 亚洲一级二级| 麻豆久久久久久| 国产精品亚洲人成在99www| 亚洲激情五月| 欧美精品自拍| 久久免费黄色| 亚洲精品极品| 喷白浆一区二区| 美女少妇全过程你懂的久久| 亚洲电影在线| 高清一区二区三区| 91视频精品| 欧美aⅴ一区二区三区视频| 国产极品久久久久久久久波多结野 | a天堂资源在线| 日本a级不卡| 日韩精选在线| 视频一区视频二区中文| 亚洲视频二区| 黄色成人91| 蜜臀av性久久久久蜜臀aⅴ四虎| 中文字幕亚洲精品乱码| 精品一区二区三区中文字幕| 日韩一区二区三区高清在线观看| 国产视频一区二| 免费在线观看不卡| 久久精品国产99久久| 亚洲国产成人精品女人| 亚洲性图久久| 蜜臀a∨国产成人精品| 国产一区导航| 久久精品国产久精国产| 欧美国产专区| 国产精品**亚洲精品| 国产精品porn| 加勒比视频一区| 国产欧美成人| 国产欧美日韩精品一区二区免费 | 日韩精品第一| 亚洲一区二区av| 久久99久久人婷婷精品综合| 欧美黄色一区| 亚洲调教视频在线观看| 99精品综合| 国产亚洲毛片在线| 免费日韩视频| 国产精品亚洲片在线播放| 国产精品尤物| 免费不卡在线视频| 国产探花一区在线观看| 麻豆视频观看网址久久| 精品亚洲美女网站| 欧美日韩免费观看视频| 鲁大师成人一区二区三区| 免费不卡在线观看| 久久精品伊人| 久久狠狠婷婷| 青草国产精品久久久久久| 国产精品国码视频| 亚洲精品91| 日韩精品国产欧美| 久久久精品日韩| 日韩在线观看一区二区| 国产一区丝袜| 日韩在线一区二区| av最新在线| 丝袜脚交一区二区| 美女毛片一区二区三区四区最新中文字幕亚洲 | 亚洲最大av| 97精品资源在线观看| 麻豆成人综合网| 欧美专区18| 欧美一区二区三区久久精品| 日韩国产综合| 丝瓜av网站精品一区二区| 国产精品视频一区视频二区| 精品少妇av| 亚洲精品裸体| 精品一区二区三区的国产在线观看| 日本午夜免费一区二区 | 好吊一区二区三区| 国产欧美日韩一级| 亚洲精品.com| 鲁大师影院一区二区三区| 国内精品麻豆美女在线播放视频| 亚洲视频国产精品| 国产一区一一区高清不卡| 久久久影院免费| 亚洲一区二区三区免费在线观看| 久久久久久久欧美精品| 国产欧美激情| 亚洲精品国产偷自在线观看| 久久午夜视频| 日本久久黄色| 午夜欧美视频| 久久婷婷久久| 国产精品99久久免费| 最新国产精品| 欧产日产国产精品视频| 免费日韩成人| 免费中文字幕日韩欧美| 九九综合在线| 久久亚洲黄色| 国产精品毛片久久久| 亚洲激精日韩激精欧美精品| 美女av一区| 日本aⅴ亚洲精品中文乱码 | 欧美黄色精品| 午夜欧美理论片| 你懂的国产精品| 国产偷自视频区视频一区二区| 蜜桃免费网站一区二区三区| 午夜精品影视国产一区在线麻豆| 国产尤物精品| 欧美极品中文字幕|