zoukankan      html  css  js  c++  java
  • rax学习(四):实现微信消息长列表(LongList)之无限滚动

    仓库地址:rax-longlist

    简单介绍一下

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

    需求

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

    解决方案

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

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8" />
            <title>getBoundingClientRect</title>
            <style>
                .list{
                    100%;
                    height:300px;
                    border:solid 1px #ff4747;
                    overflow:auto;
                }
                .item{
                  background-color:#f2f2f2;
                  height:50px;
                  100%;
                  margin-top:50px;
                }
                
            </style>
        </head>
        <body>
            <section id='list' class='list'>
                <div class='item' >1</div>
                <div class='item'>2</div>
                <div class='item'>3</div>
                <div class='item'>4</div>
                <div class='item'>5</div>
                <div class='item'>6</div>
                <div class='item'>7</div>
                <div class='item'>8</div>
                <div class='item'>9</div>
                <div class='item' id='lastItem'>10</div>
            </section>
            <script>
                const list = document.getElementById('list');
                const last=document.getElementById('lastItem');
                list.addEventListener('scroll',()=>{
                  const target = last.getBoundingClientRect()
                  console.log('top:',target.top,'bottom:',target.bottom,'left:',target.left,'right:',target.right);
                })
            </script>
        </body>
    </html>
    

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

    关键代码展示

    • 目录结构

    • 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 <View className='wrapper'>
        <View className='message'>
          <Text className='message-text'>微信</Text>
          <Image className='more' source={{uri:'../../public/images/more.jpg'}}/>
        </View>
        <ScrollView className='list-wrapper'  ref={scrollRef}>
            {/* 搜索框 */}
            <View className='search-wrapper' >
              <View className='search' >
                <Image className='search-img' source={{uri:'../../public/images/search.png'}} />
                <Text className='search-text'>搜索</Text>
              </View>
            </View>
            {/* 消息列表 */}
            {list&&list.map(item=>(
              <View className='list-item' key={item.id} >
                <View className='avatar'>
                  <Image className='avatar-img' source={{uri:item.image}}/>
                </View>
                <View className='info'>
                  <View className='info-msg'>
                    <Text className='info-msg-label'>{item.label}</Text>
                    <Text className='info-msg-value'>{item.value}</Text>
                  </View>
                  <View className='info-time'>
                    <Text className='info-time-label'>{item.time}</Text>
                  </View>
                </View>
              </View>
            ))}
          <View className='bottom' ref={lastRef}>到底了~</View>
        </ScrollView>
    
        {/* 底部导航 */}
        <View className='nav-wrapper'>
            {
              mock.nav.map(item=>(
              <View className='nav' key={item.id}>
                <Image className='nav-img' source={{uri:item.image}}></Image>
                <Text className='nav-text' style={{color:item.active?'#56ba6a':'#000000'}}>{item.name}</Text>
              </View>
              ))
            }
        </View>
      </View>
    }
    
    • LongList/index.css
    .wrapper{
      display:flex;
      height:100%;
    }
    
    .message{
      100vw;
      height:15vw;
      background-color:#ebebeb;
      display:flex;
      justify-content: center;
      align-items: center;
      z-index:999;
    }
    .message-text{
      font-weight: bolder;
    }
    .more{
      7vw;
      height:7vw;
      position: absolute;
      right:5vw;
      top:5vw;
    }
    .search-wrapper{
      100%;
      background-color:#ebebeb;
      display:flex;
      flex-direction: row;
      justify-content: center;
      padding:3vw 1vw;
    }
    .search{
      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{
      5vw;
      height:5vw;
    }
    .search-text{
      color:#ccc;
      margin-left:1vw;
    }
    .list-wrapper{
      flex:1;
      100%;
      background-color:#fff;
    }
    .list-item{
      display:flex;
      flex-direction: row;
      height:20vw;
    }
    
    .avatar{
      20vw;
      height:20vw;
      display:flex;
      flex-direction: row;
      justify-content: center;
      align-items: center;
    }
    
    .avatar-img{
      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;
      80vw;
      height:20vw;
    }
    .info-msg{
      60vw;
      height: 15vw;
      display: flex;
      justify-content: space-around;
    }
    .info-msg-label{
      font-size:4.5vw;
    }
    
    .info-msg-value{
      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;
      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{
      8vw;
      height:8vw;
    }
    .nav-text{
      font-size:3vw;
    }
    
    .bottom{
      100%;
      height:10vw;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    

    效果展示

    • example1

    • example2

    参考

  • 相关阅读:
    Oracle学习笔记<5>
    Oracle学习笔记<4>
    fabric动态获取远程目录列表
    fabric查看本地与远程主机信息
    fabric安装使用
    pexpect实现远程操作
    pexpect的pxssh类实现远程操作
    Most Distant Point from the Sea
    Art Gallery
    Rotating Scoreboard(半平面交模板题)
  • 原文地址:https://www.cnblogs.com/xingguozhiming/p/13493891.html
Copyright © 2011-2022 走看看