关于滚动容器内的触发元素滚动到容器可视区顶部

大概结构如下

<Container>
    <Item>xxxx</Item>
    <Item>xxxx</Item>
    <Item>xxxx</Item>
    <Item>xxxx</Item>
    <Item>
        <div>
            <A />
        </div>
    </Item>
    .....
</Container>

注意: 目标元素的父元素不是滚动容器,中间隔了好几层;

A组件提供了一个onClick方法,参数是e,
需求是,点击A组件的时候,希望将A组件滚动到容器可视区的顶部

思路:

  1. 获取到A组件点击时,距离容器顶部的距离, 记录为等待滚动的距离top1;
  2. 获取Container组件已经滚动了的距离,记录为已滚动的记录 top0;
  3. 那么只要Container.scrollTo(0, top0+top1),就可以完成需求
  4. top1的获取思路:通过A组件click时的e参数,可以获取到点击时,点击位置距离浏览器页面顶部的y坐标,同方法可以获取到container距离浏览器页面顶部的y坐标,相减就可以得到top1,代码如下
const top1 = e.target.getBoundingClientRect().y - 
 containerRef.current.getBoundingClientRect().y

containerRef.current是React中容器的dom实例,可以等效于 document.getElementById获取到的dom

  1. top0的获取思路
const top0=containerRef.current.scrollTop
  1. 所以A组件的onClick函数为
onClick = e =>{
  xxx计算top0和top1的操作
  containerRef.current.scrollTo(0, top0+top1);
}
  1. 还有个问题,这个A组件点开后,可能会有展开dom的操作,可能是个折叠面板,所以需要等到展开后再去计算新的top,所以需要加个timeout来延迟触发(原理可以去看js执行宏任务与微任务的区别)
onClick = e =>{
  setTimeout(() => {
      xxx计算top0和top1的操作
      containerRef.current.scrollTo(0, top0+top1);
  })
}
  1. 后面发现不对,会报错,还突然拿不到实例了


    image.png

这意思是说,这onClick是react的合成事件,在调用后,e就直接销毁了,在settimeout里面根本拿不到e,如果不想让他销毁,就调用 e.persisit()
参考文档: https://reactjs.org/docs/legacy-event-pooling.html

所以最终代码如下

onClick = e =>{
  e.persisit();
  setTimeout(() => {
      xxx计算top0和top1的操作
      containerRef.current.scrollTo(0, top0+top1);
  })
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容