最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2023年07月10日 10:00:07   作者:前端小張同學(xué)  
這篇文章主要給大家介紹一下如何用 react 實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 scrollView組件,文中有詳細(xì)的代碼示例,具有一定的參考價(jià)值,需要的朋友可以參考下

效果

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

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

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

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

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

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

好,帶著以下幾個(gè)問題,我們一起來思考一下這個(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 : 接下來 我們分別給兩個(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

在這里我們通過 ref 綁定了 一個(gè) 內(nèi)容元素 ,然后 初始化的時(shí)候 ,我們?nèi)ビ?jì)算了元素最大可滾動(dòng)的距離, 然后當(dāng)我們點(diǎn)擊了 按鈕時(shí) 我們獲取了 contentRef 下所有 綁定 類名為 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ì)選擇器 做不同類型處理
      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)行偏移也是可以的,額可以拓展一下。

問題

為什么 用 tranform 而不是定位 ?

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

總結(jié)

總結(jié)下來,這個(gè)組件 我們主要做的就是它的transform ,當(dāng)然還有更多的功能大家可以拓展一下,如果你覺得還有哪些可以補(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)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • react koa rematch 如何打造一套服務(wù)端渲染架子

    react koa rematch 如何打造一套服務(wù)端渲染架子

    這篇文章主要介紹了react koa rematch 如何打造一套服務(wù)端渲染架子,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • react 生命周期實(shí)例分析

    react 生命周期實(shí)例分析

    這篇文章主要介紹了react 生命周期,結(jié)合實(shí)例形式分析了react 生命周期基本原理、操作步驟與注意事項(xiàng),需要的朋友可以參考下
    2020-05-05
  • Docker部署SpringBoot項(xiàng)目到云服務(wù)器的實(shí)現(xiàn)步驟

    Docker部署SpringBoot項(xiàng)目到云服務(wù)器的實(shí)現(xiàn)步驟

    Docker作為一種輕量級(jí)的容器化技術(shù),為開發(fā)者提供了快速、便捷的部署方案,本文主要介紹了Docker部署SpringBoot項(xiàng)目到云服務(wù)器,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 手動(dòng)用webpack搭建第一個(gè)ReactApp的示例

    手動(dòng)用webpack搭建第一個(gè)ReactApp的示例

    本篇文章主要介紹了手動(dòng)用webpack搭第一個(gè) ReactApp的示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04
  • 一起來了解React的Hook

    一起來了解React的Hook

    這篇文章主要為大家詳細(xì)介紹了React的Hook,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • ReactRouterV6如何獲取當(dāng)前路由參數(shù)

    ReactRouterV6如何獲取當(dāng)前路由參數(shù)

    這篇文章主要介紹了ReactRouterV6如何獲取當(dāng)前路由參數(shù)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • 你知道怎么基于?React?封裝一個(gè)組件嗎

    你知道怎么基于?React?封裝一個(gè)組件嗎

    這篇文章主要為大家詳細(xì)介紹了React如何封裝一個(gè)組件,使用antd的divider組件來講解,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • React-Router6版本的更新引起的路由用法變化

    React-Router6版本的更新引起的路由用法變化

    本文主要介紹了React-Router6版本的更新引起的路由用法變化,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 解決react中useState狀態(tài)異步更新的問題

    解決react中useState狀態(tài)異步更新的問題

    本文主要介紹了react中useState狀態(tài)異步更新的問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • React實(shí)現(xiàn)預(yù)覽展示docx和Excel文件

    React實(shí)現(xiàn)預(yù)覽展示docx和Excel文件

    這篇文章主要為大家詳細(xì)介紹了如何使用React實(shí)現(xiàn)預(yù)覽展示docx和Excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02

最新評(píng)論

瑞昌市| 栖霞市| 仪征市| 耒阳市| 油尖旺区| 康平县| 县级市| 山西省| 仙游县| 汉源县| 师宗县| 陇南市| 寿阳县| 隆子县| 本溪市| 彩票| 女性| 安阳市| 博野县| 靖西县| 隆安县| 吉林省| 改则县| 汶上县| 若尔盖县| 孝感市| 鹿邑县| 共和县| 航空| 陇西县| 乌拉特前旗| 奉节县| 临潭县| 绿春县| 定州市| 玛纳斯县| 来安县| 绍兴县| 海宁市| 耿马| 陆川县|