网站首页 > web开发 > JavaScript 正文
目录
效果
我们先看一下效果,大概就是希望点击左边按钮 或者右边按钮将元素以 每一个 子选项卡长度单位进行精准偏移。
设计考虑的问题
在这之前,大家不妨思考一下这个需求给到你,你应该怎么去设计这个东西?
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(null) return ( ) }) export default ScrollView 左边{children}右边
逻辑处理
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(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 ( ) }) export default ScrollView handelIconClick(false)}>左边{children}handelIconClick(true)}>右边
在这里我们通过 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(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 ( ) }) export default ScrollView handelIconClick(false)}>左边{children}handelIconClick(true)}>右边
外部使用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 () }) export default Login{ list.map((item, index) => { return ( setCurrentIndex(index)}>) }) }{item}
ok 到这里 scrollView 组件就简单的封装完成了 , 当然你还可以集成 点击某个选项时 再进行偏移也是可以的,额可以拓展一下。
问题
为什么 用 tranform 而不是定位 ?
答案很简单 : 定位移动的回引发视图重绘,而transform 不会触发重回,出于这一点可以在性能上做优化,当然 掘友在上一张 弹幕的文章中也讲到 这一点,谢谢大家
总结
总结下来,这个组件 我们主要做的就是它的transform ,当然还有更多的功能大家可以拓展一下,如果你觉得还有哪些可以补充的,欢迎评论区留言。
以上就是用react实现一个简单的scrollView组件的详细内容,更多关于react实现scrollView组件的资料请关注开源网www.osweb.cn其它相关文章!
- 上一篇: js获取url参数值的几种方式详解
- 下一篇: vue3实现多层级列表的项目实践
猜你喜欢
- 2023-10-16 vue3组件TS类型声明实例代码
- 2023-10-12 react实现记录拖动排序
- 2023-10-11 React在Dva项目中创建并引用页面局部组件的方式
- 2023-10-10 IntersectionObserver实现加载更多组件demo
- 2023-10-10 react16.8.0以上MobX在hook中的使用方法详解
- 2023-10-10 react中使用better-scroll滚动插件的实现示例
- 2023-10-09 一文带你搞懂react hooks的类型声明
- 2021-07-16 如何在Laravel之外使用illuminate组件详解
你 发表评论:
欢迎- 12-06如何自定义Excel2003散点图的数据标志
- 12-06excel2007的sheet不见了怎么办
- 12-06Excel2010中进行设置取消密码的操作方法
- 12-06excel怎样使用IMSUM函数
- 12-06EXCEL快速输入数据
- 12-06excel中设置次要坐标轴的教程
- 12-06excel2003冻结窗格的教程
- 12-06Excel如何输入上标下标
- 开源分类
- 最近发表
- 开源网标签
本文暂时没有评论,来添加一个吧(●'◡'●)