一、项目的需求描述

不停的请求后端日志,输出到页面上,当用户不做任何操作时,动态显示日志,即放日志的盒子里面内容滚动到最底部;当用户触发了滚动事件查看历史日志时,盒子不再滚动到最底部,随着用户的滚动显示对应的日志,且确保不会中断请求日志,当用户再次滚动到页面最底部并且不再做任何操作时候,再次实现盒子里面内容动态滚动到最底部(类似聊天界面,只要你不翻看聊天记录,就会滚动显示最新消息)

二、设置scrollTop的方法

1. 原生 HTML 中使用 JS 直接修改

方法一:使用scrollTo函数来设置滚动条的高度

	let list = document.querySelector("#mylist");
    list.scrollTo(0, 500);

方法二:使用元素.scrollTop = 元素.scrollHeight来设置滚动条的高度

	let list = document.querySelector("#mylist");
    list.scrollTop = list.scrollHeight;
//scrollHeight是只读的属性,所有等号左右的顺序不能改变

方法三:使用scrollBy函数来设置滚动条的高度

let list = document.querySelector("#mylist");
list.scrollBy(0, 100);  // 等同于window.scrollBy({left: 0, top: 100 }); 

2、 用 Ref 获取元素对象并利用scrollIntoView()函数修改(有兼容问题)

该scrollIntoView()方法将调用它的元素滚动到浏览器窗口的可见区域。
PS:根据其他元素的布局,元素可能无法完全滚动到顶部或底部。
element.scrollIntoView(alignToTop)
在这里插入图片描述
如果不传参数element.scrollIntoView(); // 等同于element.scrollIntoView(true)

class test extends PureComponent {
  constructor(props) {
    super(props)
    this.messagesEnd = React.createRef()
  }
  // 在组件更新时,滚动到该空 div 的位置
  scrollToBottom = () => {
    this.messagesEnd.scrollIntoView({ behavior: "auto" });//this.messagesEnd.scrollIntoView(false);
  }

  componentDidMount() {
    this.scrollToBottom();
  }

  componentDidUpdate() {
    this.scrollToBottom();
  }
  render() {
    return (
      <div>
        <div className="Container" >
          <div className="List">
            {this.renderMessages()}
          </div>
          <div style={{ float: "left", clear: "both" }}
            ref={(el) => { this.messagesEnd = el; }}>
          </div>
        </div>
      </div>
    )
  }
}

三、以上设置不起效果的原因

可能的原因一: 因为层级的问题

设置的css: overflow: scroll; 的层级,必须要是在你元素map的上一级才可以。

<div id="bottomlist" ref={this.myRef} className={styles.demo_infinite_container}>
                    {bottomStorsgeResultOne.length > 0 && <List
					 dataSource={[...bottomStorsgeResultOne]}
                     renderItem={item => {
                            return <List.Item key={item.date}></List.Item>}
                    }
                    ></List>}
 </div>

给外层div设置 overflow,子元素List去map接收的数据

可能的原因二: 异步请求时间延迟导致无法准确设置
这个是我真是项目中遇到的,需求在页面刚进去的时候需求实现页面滚动在最底部,在生命周期函数componentDidMount中我们需要获取到元素并设置scrollTop,问题是后端打日志需要时间,所以mylist.scrollTop = mylist.scrollHeight并木有执行,当页面加载后,List中所需要的数据还没从后端返回,无法获取到List的高度(设置scrollTop前提必须是存在滚动条)但是加了定时器之后,后端数据返回并写入dom中,设置scrollTop值才能生效。

componentDidMount() {
    const mylist = document.getElementById('bottomlist')
    if (mylist) {
        mylist.addEventListener('scroll', this.watchListScroll, true);
        setTimeout(() => {
                mylist.scrollTop = mylist.scrollHeight
            }, 200)
        }
    }

五、总结小知识

1、通常,设置滚动高度可以通过设置元素的 scrollTop 属性,使内容滚动到最底部通过将 scrollTop 设置成该元素的 scrollHeight 值;
2、在 React 中,修改元素的样式并没有那么容易,因为原生元素的对象属性是只读的。所以可以使用 Ref 获取元素;
3、querySelector与getElementBy等的区别
常见的获取元素的方法有3种,分别是通过元素ID(getElementById)、通过标签名字(getElementsByTagName)和通过类名字(getElementsByClassName)来获取;
querySelector() 方法返回匹配指定 CSS 选择器元素的第一个子元素 。 该方法只返回匹配指定选择器的第一个元素。如果要返回所有匹配元素,需要使用 querySelectorAll() 方法替代;
query选择符选出来的元素及元素数组是静态的,而getElement这种方法选出的元素是动态的。静态的就是说选出的所有元素的数组,不会随着文档操作而改变;
在使用的时候getElement这种方法性能比较好,query选择符则比较方便。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐