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

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

用react實(shí)現(xiàn)一個(gè)簡(jiǎn)單的scrollView組件

瀏覽:29日期:2022-06-13 14:58:20
目錄效果設(shè)計(jì)考慮的問(wèn)題1: 結(jié)構(gòu)結(jié)構(gòu)搭建邏輯處理問(wèn)題總結(jié)效果

我們先看一下效果,大概就是希望點(diǎn)擊左邊按鈕 或者右邊按鈕將元素以 每一個(gè) 子選項(xiàng)卡長(zhǎng)度單位進(jìn)行精準(zhǔn)偏移。

設(shè)計(jì)考慮的問(wèn)題

在這之前,大家不妨思考一下這個(gè)需求給到你,你應(yīng)該怎么去設(shè)計(jì)這個(gè)東西?

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

2 :我們應(yīng)該如何進(jìn)行偏移 ? 用定位還是位移 ? 他們有什么區(qū)別?如何保證偏移量一點(diǎn)不差?

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

好,帶著以下幾個(gè)問(wèn)題,我們一起來(lái)思考一下這個(gè)組件,應(yīng)該如何封裝。

1: 結(jié)構(gòu)

首先 , 結(jié)構(gòu)如下圖,我們有一個(gè) 父盒子(content-wapper-hidden) ,還有一個(gè)子盒子內(nèi)嵌在 父盒子中,父盒子負(fù)責(zé)元素的溢出隱藏,固定寬度,子盒子負(fù)責(zé)渲染,和滾動(dòng)。

結(jié)構(gòu)搭建

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 : 接下來(lái) 我們分別給兩個(gè) 按鈕綁定事件 , 并且 在初始化的時(shí)候 去計(jì)算 最大可偏移的值,

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) // 兩者最大的偏移量 可滾動(dòng)距離 const [currentOffsetIndex, setCurrentOffsetIndex] = useState(0) // 當(dāng)前滾動(dòng)元素的索引 const handelIconClick = (isRoght: boolean) => { // 事件處理函數(shù) } function getScrollOffset() { const scrollWidth = contentRef.current!.scrollWidth const clientWidth = contentRef.current!.clientWidth setMaxOffset(scrollWidth - clientWidth) // 計(jì)算最大偏移量 } 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

在這里我們通過(guò) ref 綁定了 一個(gè) 內(nèi)容元素 ,然后 初始化的時(shí)候 ,我們?nèi)ビ?jì)算了元素最大可滾動(dòng)的距離, 然后當(dāng)我們點(diǎn)擊了 按鈕時(shí) 我們獲取了 contentRef 下所有 綁定 類(lèi)名為 item的元素,點(diǎn)擊時(shí)判斷 是否為 右側(cè) 如果是 右側(cè) 點(diǎn)擊 則 索引 + 1 否則 索引 -1 ,然后做邊界處理,依次獲得item的 offsetLeft ,注意 offsetleft 是相對(duì)于 父級(jí)元素的距離,然后 將元素 contentRef 進(jìn)行 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) // 兩者最大的偏移量 可滾動(dòng)距離 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 子節(jié)點(diǎn) const TabItem = TabAllList[newIndex] as HTMLDivElement // 獲取下一個(gè) 準(zhǔn)備滾動(dòng)元素 const TabItemOffsetLeft = TabItem.offsetLeft contentRef.current!.style.transform = `translateX(${-TabItemOffsetLeft}px)` setisContinueScroll(maxoffset > TabItemOffsetLeft) // 是否能繼續(xù)滾動(dòng) 如果 你的 offsetLeft 都 // 比我可滾動(dòng)距離大了 , 則肯定是不能滾動(dòng)的 setCurrentOffsetIndex(newIndex) } const getAllElements = (querySelectorName: string, type: 'id' | 'class' | 'el' = 'class') => { let seletorName = null if (type === 'id') { // 對(duì)選擇器 做不同類(lèi)型處理 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 組件就簡(jiǎn)單的封裝完成了 , 當(dāng)然你還可以集成 點(diǎn)擊某個(gè)選項(xiàng)時(shí) 再進(jìn)行偏移也是可以的,額可以拓展一下。

問(wèn)題

為什么 用 tranform 而不是定位 ?

答案很簡(jiǎn)單 : 定位移動(dòng)的回引發(fā)視圖重繪,而transform 不會(huì)觸發(fā)重回,出于這一點(diǎn)可以在性能上做優(yōu)化,當(dāng)然 掘友在上一張 彈幕的文章中也講到 這一點(diǎn),謝謝大家

總結(jié)

總結(jié)下來(lái),這個(gè)組件 我們主要做的就是它的transform ,當(dāng)然還有更多的功能大家可以拓展一下,如果你覺(jué)得還有哪些可以補(bǔ)充的,歡迎評(píng)論區(qū)留言。

以上就是用react實(shí)現(xiàn)一個(gè)簡(jiǎn)單的scrollView組件的詳細(xì)內(nèi)容,更多關(guān)于react實(shí)現(xiàn)scrollView組件的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: JavaScript
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩黄色大片网站| 欧美精品观看| 99久久亚洲精品蜜臀| 日本中文字幕视频一区| 久久久久免费| 国产精品久一| 日日夜夜免费精品视频| 日韩精品一区二区三区免费观影| 亚洲欧洲美洲国产香蕉| 精品一区在线| 欧美一区三区| 亚洲精品在线影院| 精品国产网站| 久久精品日韩欧美| 日本91福利区| 日韩有吗在线观看| 久久不射网站| 久久九九精品| caoporn视频在线| 国产成人精品三级高清久久91| 青青草91视频| 国产伦精品一区二区三区视频| 免费成人av在线播放| 激情欧美日韩一区| 精品欧美日韩精品| 麻豆精品在线观看| 精品久久免费| 日韩一区二区三区在线看| 亚洲永久字幕| 美女黄网久久| 天堂俺去俺来也www久久婷婷| 亚洲区第一页| 亚洲人成网站在线在线观看| 激情五月色综合国产精品| 今天的高清视频免费播放成人| 日韩精品专区| 9国产精品视频| 日韩亚洲精品在线观看| 国产精品伊人| 中国字幕a在线看韩国电影| 久久婷婷激情| 日韩精品亚洲专区| 久久精品亚洲一区二区| 国产精品对白| 欧美在线不卡| 日韩一区二区在线免费| 日韩中文字幕| 吉吉日韩欧美| 日本免费在线视频不卡一不卡二| 久久夜夜操妹子| 欧美日韩一区二区三区在线电影| 中文久久精品| 国产欧美在线| 国产伦精品一区二区三区在线播放| 日韩中文在线播放| 国产精品香蕉| 亚洲精选成人| 亚洲精品网址| 久久国产中文字幕| 国产精品久久久久久久久久10秀| 亚洲一二av| 夜夜嗨网站十八久久| 欧美精品资源| 国产三级一区| 婷婷精品在线观看| 久热综合在线亚洲精品| 欧美日韩第一| 99在线精品免费视频九九视| 日韩三区在线| 日韩久久精品网| 国产一二在线播放| 国产精品网址| 久久精品午夜| 国产一区二区亚洲| 国产精品99久久免费观看| 三级久久三级久久久| 深夜福利亚洲| 清纯唯美亚洲综合一区| 噜噜噜躁狠狠躁狠狠精品视频| 一区二区视频欧美| 老司机久久99久久精品播放免费| 欧美特黄视频| 中文字幕日韩高清在线| 久久亚洲欧洲| 7777精品| 精品一区不卡| 亚洲精品福利电影| 久久亚洲国产| 亚洲天堂日韩在线| 在线天堂中文资源最新版| 国产成人精品免费视| 成人精品视频| 青青草精品视频| 国产亚洲毛片| aa国产精品| 免费看日韩精品| 欧美精品99| 午夜视频精品| 久久在线91| 久久人人99| 日韩成人av影视| 亚洲国产福利| 少妇精品久久久一区二区 | 午夜电影亚洲| 国产精品免费大片| 亚洲一级影院| 日韩精品国产欧美| 精品免费av一区二区三区| 欧美日韩高清| 久久久水蜜桃av免费网站| 国产美女亚洲精品7777| 一区福利视频| 麻豆精品av| 超碰在线99| 波多野结衣一区| 激情国产在线| 91福利精品在线观看| 99久久亚洲精品| 美女视频一区在线观看| 视频一区视频二区中文| 日本国产精品| 国产精品久久久久久久久久齐齐| 女人天堂亚洲aⅴ在线观看| 精品国产精品久久一区免费式| 亚洲综合福利| 一区二区高清| 亚洲另类av| 最新国产精品| 日韩免费精品| 欧美久久一区二区三区| 国产乱子精品一区二区在线观看 | 亚洲欧美久久久| 制服诱惑一区二区| 国产91精品对白在线播放| 激情亚洲影院在线观看| se01亚洲视频 | 亚洲人成毛片在线播放女女| 91精品国产成人观看| 国产精品久久久久久久久妇女| 91精品一区| 日韩视频一二区| 国产欧美成人| 日本不卡一区二区三区| 久久国内精品视频| 中文字幕一区二区三区四区久久| 中文字幕人成乱码在线观看 | 一区福利视频| 在线 亚洲欧美在线综合一区| 大香伊人久久精品一区二区| 久久99影视| 精品三区视频| 国产在视频一区二区三区吞精| 亚洲伦乱视频| 91精品一区国产高清在线gif| 欧美日韩在线观看首页| www.com.cn成人| 国产精品亚洲四区在线观看| 国产91在线播放精品| 日本精品黄色| 美女网站视频一区| 尹人成人综合网| 国产精品伊人| 日韩中文首页| 亚洲免费中文| 国产精品99精品一区二区三区∴ | 亚洲91在线| 免费看黄色91| 日韩一区二区三区免费播放| 国产精品99久久精品| 日韩精品1区| 欧美日韩精品免费观看视完整| 亚洲www啪成人一区二区| 亚洲欧美日韩国产综合精品二区| 亚洲理论在线| 激情综合婷婷| 国产精品毛片| 日韩精品影视| 欧美片网站免费| 久久青草久久| 欧美三级第一页| 亚洲精品成人一区| 欧美aa一级| 欧美视频精品全部免费观看| 成人午夜精品| 国产美女高潮在线观看| 伊人久久亚洲影院| 国产福利资源一区| 亚洲精品欧美| 久久国产精品久久w女人spa| 麻豆国产一区| 免费在线播放第一区高清av| 亚洲欧洲av| 日韩黄色大片网站| 欧美日本二区| 国产一卡不卡| 视频一区在线播放| 成人看片网站| 韩日一区二区| 日韩av在线播放网址| 日韩av电影一区|