rax学习(四):实现微信消息列表(LongList)之无限滚动

仓库地址:rax-longlist

简单介绍一下

本节接着上一节,实现微信消息的无限滚动。

需求

  • 修改单位,统一使用vw vh
  • 无限加载滚动列表
  • 滚动到底加载下一页的值

解决方案

无限滚动加载,主要是如何检测到某个item是否到底了,可以转化成某个div距离屏幕上下左右的距离的问题,即可以使用getBoundingClientRect来实现它,除了这个还需要获取屏幕的高度,浏览器中可以使用document.documentElement.clientHeight来获取可视高度。关于getBoundingClientRect我们可以写个小例子来熟悉一下,代码如下:



    
        
        getBoundingClientRect
        
    
    
        
1
2
3
4
5
6
7
8
9
10

由上面的例子可以看到getBoundingClientRect()的top和bottom之差等于当前div的高度,这就代表top表示div顶部到屏幕顶端的距离,bottom表示div底部到屏幕顶端的距离。同理left和right也是一样的。有了上面的热身,我们可以开始继续我们的开发,长列表的无限滚动其实很简单:只需要在列表的父盒子里监听滚动,在最后一项加上ref这样我们就可以知道最后一项什么时候在屏幕的底部了。

关键代码展示

  • 目录结构

  • image
  • LongList/index.jsx
import {createElement,createRef, useEffect, useState} from 'rax';
import View from 'rax-view';
import Text from 'rax-text';
import Image from 'rax-image';
import ScrollView from 'rax-scrollview'
import mock from './mock'
import './index.css'

const scrollRef = createRef();
const lastRef = createRef();
export default ()=>{
  const [list,setList]=useState(mock.list(0))
  let page=0
  useEffect(()=>{
    scrollRef.current._nativeNode.addEventListener('scroll',()=>{
      let y=lastRef.current.getBoundingClientRect().bottom
      // 最底部item的底部到屏幕最上方的距离比上屏幕的距离,我们已知底部导航的高度占屏幕高度的10%
      const distance=y/document.documentElement.clientHeight
      // 计算比率,检测是否到底了
      if(distance<0.91 ){
        page++
        list.push(...mock.list(page))
        setList([...list])
      }
    })
  },[])


  return 
    
      微信
      
    
    
        {/* 搜索框 */}
        
          
            
            搜索
          
        
        {/* 消息列表 */}
        {list&&list.map(item=>(
          
            
              
            
            
              
                {item.label}
                {item.value}
              
              
                {item.time}
              
            
          
        ))}
      到底了~
    

    {/* 底部导航 */}
    
        {
          mock.nav.map(item=>(
          
            
            {item.name}
          
          ))
        }
    
  
}
  • LongList/index.css
.wrapper{
  display:flex;
  height:100%;
}

.message{
  width:100vw;
  height:15vw;
  background-color:#ebebeb;
  display:flex;
  justify-content: center;
  align-items: center;
  z-index:999;
}
.message-text{
  font-weight: bolder;
}
.more{
  width:7vw;
  height:7vw;
  position: absolute;
  right:5vw;
  top:5vw;
}
.search-wrapper{
  width:100%;
  background-color:#ebebeb;
  display:flex;
  flex-direction: row;
  justify-content: center;
  padding:3vw 1vw;
}
.search{
  width:96%;
  padding-top:1vw;
  padding-bottom:1vw;
  background-color:#fff;
  border-radius:1px;
  display:flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
.search-img{
  width:5vw;
  height:5vw;
}
.search-text{
  color:#ccc;
  margin-left:1vw;
}
.list-wrapper{
  flex:1;
  width:100%;
  background-color:#fff;
}
.list-item{
  display:flex;
  flex-direction: row;
  height:20vw;
}

.avatar{
  width:20vw;
  height:20vw;
  display:flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}

.avatar-img{
  width:15vw;
  height:15vw;
  border-radius:2vw;
}

.info{
  border-bottom:0.1vw solid #f2f2f2;
  display:flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  width:80vw;
  height:20vw;
}
.info-msg{
  width:60vw;
  height: 15vw;
  display: flex;
  justify-content: space-around;
}
.info-msg-label{
  font-size:4.5vw;
}

.info-msg-value{
  width:60vw;
  overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  font-size:3.5vw;
  color:#ccc;
}

.info-time{
  height:15vw;
  margin-right:5vw;
}

.info-time-label{
  color:#ccc;
  font-size:3.5vw;
}

/* 底部导航 */
.nav-wrapper{
  bottom:0vw;
  height:10vh;
  width:100vw;
  background-color:#f8f8f8;
  color:#111;
  display:flex;
  flex-direction: row;
  justify-content: space-around;
  align-items: center;
}
.nav{
  display:flex;
  justify-content: center;
  align-items: center;
}
.nav-img{
  width:8vw;
  height:8vw;
}
.nav-text{
  font-size:3vw;
}

.bottom{
  width:100%;
  height:10vw;
  display: flex;
  justify-content: center;
  align-items: center;
}

效果展示

  • example1
  • example2

参考

  • MDN getBoundingClientRect
  • 关于js获取屏幕高度和宽度( window.document.body,window.screen)(PC端和移动端)
  • getBoundingClientRect小例子

你可能感兴趣的:(rax学习(四):实现微信消息列表(LongList)之无限滚动)