react-35-触底加载思路

简介: 触底加载思路也是常见的特效,记得最早的时候做iOS开发 那个时代,微博经常见上拉刷新,和下拉刷新,其实这个 触底加载,也类似可以借鉴图片懒加载思路本节代码是在组件封装 基础上进行的,不过只看 思路也行,代码都不是事,完全可以自己搞

1.前言


触底加载思路也是常见的特效,记得最早的时候做iOS开发 那个时代,微博经常见上拉刷新,和下拉刷新,其实这个 触底加载,也类似

可以借鉴图片懒加载思路

本节代码是在组件封装 基础上进行的,不过只看 思路也行,代码都不是事,完全可以自己搞


2. 触底加载思路分析


2.1 分析

  1. 既然是触底加载 那就是在触底的时候调用请求

2.所以 如何判断触底是关键

  1. 我们需要三个值来进行辅助判断
  2. 滚动条的高度:也叫卷起来的高度
    滚动条卷去部分高度即可视顶端距离整个对象顶端的高度。


document.body.scrollTop || document.documentElement.scrollTop
  1. 所有内容高高度:
    浏览器整个框架的高度,包括滚动条卷去部分+可视部分+底部隐藏部分的高度总和。


document.body.scrollHeight
  1. 窗口高度


window.innerHeight


2.2核心伪码

只需要判断
内容盒子的高度+滚动条的scrollTop = 盒子内容的高度
即为触底。


3. 具体代码实现


触底 肯定是滚动的时候 触底,所以需要监听滚动事件

3.1 简要分析

componentDidMount里面获取数据,添加滚动监听

触底需要在将要触底的时候 调用数据请求,所以需要一定的冗余,这个数值根据自己的实际场景来定

3.2 代码实现


componentDidMount() {
        this.getData()
        window.addEventListener("scroll", () => {
            // 网页滚动高度 
            var scrollTopHeight = document.body.scrollTop || document.documentElement.scrollTop
            // 文档显示区域的高度
            var showHeight = window.innerHeight
            // 所有内容的高度
            var allHeight = document.body.scrollHeight
            // 只需要判断内容盒子的高度+滚动条的scrollTop = 盒子内容的高度即为触底
            if (allHeight - 66 < scrollTopHeight + showHeight) {
                console.log("触底了:",)
                this.getData()
            }
        })
    }



4. 请求修改


4.1 简要分析

  1. 因为既然是触底加载,那么需要 之前的列表数据 + 当前请求的数据合起来 整合成新的列表,所以这里新旧数据的合并方式比较多,
    这里选用 展开运算符来合并


this.setState({
                list: [...this.state.list, ...res.data],
                pageNum: this.state.pageNum + 1
            })

而且这个应该具备分页请求的功能,触底加载的数据,应该是新的,所以每次请求成功需要修改页码


pageNum: this.state.pageNum + 1

4.2  具体代码


//**********************************  自定义函数
    getData() {
        const shopsUrl = "/shop/rs"
        let params = {
            latitude: 31.22967,
            longitude: 121.4762,
            offset: this.state.pageNum * this.state.pageSize,
            limit: this.state.pageSize
        }
        axios.get(shopsUrl, { params }).then(res => {
            // console.log("商铺列表数据",res)
            this.setState({
                list: [...this.state.list, ...res.data],
                pageNum: this.state.pageNum + 1
            })
        }).catch(err => {
            console.log("商铺列表失败:", err)
        })
    }


4.3 小插曲

这里的赋值有可能赋值不上去


// set数据是异步的
      this.setState(() => {
      pageNum:this.state.pageNum+1
      })
      // 方式2 
      let pageNum2 = this.state.pageNum + 1
      this.setState(() => {
      pageNum:pageNum2
      })



5. 优化 请求时机


5.1 简要分析

  1. 上述的逻辑,只要一触底就会进行数据请求
  2. 但是这个触底操作,因为是滑动,只要移动一点点就会调用请求,所以会造成请求次数过多的问题
  3. 这里做一个 flag标记,只要当前请求完成才能进行下一次请求

5.2  简要代码

  1. 构造函数里面 state定义变量


constructor() {
        super()
        this.state = {
            list: [],
            pageNum: 0,
            pageSize: 6,
            flag: true,
        }
    }

设置为 true,是因为首次进界面需要进行加载

  1. 请求里面变量的修改


getData() {
        // 请求不完成不进行下次请求 ,直接 return
        if (!this.state.flag) return;
        //下次请求开始之前 先把 flag设置为 false
         this.setState({
            flag: false
        })
      axios.get().then().catch()..finally(() => {
            this.setState({
                flag: true,
            })
        })
}
  1. 进行请求之前 先判断 flag 标记 ,false 直接 return
  2. 可以进行请求的话,把  flag 标记 为false,避免,当前请求还没完成,进行多次请求的叠加
  3. 请求完成改为  true
  4. 变量的 修改 ,尤其是这种标记类的变量,一定要形成闭环,有true的地方,就有false的地方


6. 加载提示


想要实现,触底加载 下方有那种 加载中的提示,可以自己写写

这里不在扩展


render() {
        return (
            <div>
                <NavBar> 懂得都懂 </NavBar>
                <List list={this.state.list} />
                <div className="tip">{this.state.msg}</div>
            </div>
        )
    }



7. 完成代码


和上面的代码略有不同,做了些许优化

7.1 state


constructor() {
        super()
        this.state = {
            shopList: [],
            pageSize: 6 ,//这个可以根据自己的屏幕一屏能显示几条数据来定
            pageNum:0,  //当前页码
            flag:true,  //因为首次进页面的肯定需要请求1次 所以是 true
        }
    }


7.2 render


render() {
let {shopList } = this.state
return(
 <div>
               {/* 父子组件传值 */}
                <List shopList = {shopList}/>
                {/* ***************** 商铺列表 end*/}
 </div>)
}


7.4 getData


async getData() {
        // 触底加载的时候 ,请求不完成 不进行下一次请求
        // 不然会造成这个 请求叠加 稍微触底滑动了一点距离,就加载了 好几次请求
        // 这是没有必要的,只请求1次就行,本次请求完成,下次再触底,再发请求就行
        //我们做一个标识 来标记当前的 请求是否完成
        // 其实和 loading动画类似的概念
        let {pageSize,pageNum,flag,shopList} = this.state
        if(!flag)return
        // true进来 首先改为 false 
        // 直到本次请求完成再改为 true
        // 这样就保证了 在一次请求完成的过程当中 不会进行请求叠加
        // 其实也和定时器嵌套 类似
        this.setState({
            flag:false
        })
        let params = {
            offset:shopList.length,// 已经有的数据条数 shopList.length 实际情况实际分析
            // offset: pageNum*pageSize,// 已经有的数据条数  回顾 分页思想
            limit: pageSize
        }
        try {
            let shopListRes = (await axios.get("/shop/list",{params})).data
        //    赋值
        // this.state.shopLis 之前的/ 上一次的数据
        // shopListRes  当前这次的数据  触底加载的数据
        //  offset怎么变 回想我们的分页加载
            this.setState({
                shopList:[...shopList,...shopListRes],
                pageNum:pageNum+1
             })
            return shopListRes
        } catch (error) {
            console.log("列表:", error)
        }finally{
            this.setState({
                flag:true
            })
        }
    }


7.5 componentDidMount


async componentDidMount() {
        this.getData()
        // 触底加载 监听滚动事件
       window.addEventListener("scroll",()=>{
           //网页滚动的高度
           let htmlScrollTopHeight = document.body.scrollTop || document.documentElement.scrollTop
           //文档显示区域的高度
           let showHeight = window.innerHeight
           // 所有内容的高度
           let allHeight = document.body.scrollHeight
           if(allHeight - 100 < htmlScrollTopHeight +showHeight){
               console.log("触底了----------")
                this.getData()
           }
       })
}




相关文章
|
3月前
|
前端开发 JavaScript
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
本文介绍了在React项目中实现路由懒加载的方法,使用React提供的`lazy`和`Suspense`来优化项目首次加载的速度。通过将路由组件改为懒加载的方式,可以显著减少初始包的大小,从而加快首次加载速度。文章还展示了如何使用`Suspense`组件包裹`Switch`来实现懒加载过程中的fallback效果,并提供了使用前后的加载时间对比,说明了懒加载对性能的提升作用。
212 2
React项目路由懒加载lazy、Suspense,使第一次打开项目页面变快
|
2月前
|
JavaScript 前端开发 Java
vue2知识点:Vue封装的过度与动画
vue2知识点:Vue封装的过度与动画
15 0
|
4月前
|
前端开发
|
4月前
Vue3使用createVNode和render函数实现仿 Antd 加载动效
本文展示了如何在Vue3项目中使用`createVNode`和`render`函数实现一个仿Ant Design加载动效的自定义组件,并提供了详细的实现代码和使用示例。
172 0
Vue3使用createVNode和render函数实现仿 Antd 加载动效
|
7月前
|
JavaScript 前端开发
在React和Vue中实现锚点定位功能
在React和Vue中实现锚点定位功能
176 1
|
JavaScript 前端开发 开发者
Vue3使用hook封装媒体查询和事件监听,使Vue的开发更加丝滑🚀🚀🚀
Vue3使用hook封装媒体查询和事件监听,使Vue的开发更加丝滑🚀🚀🚀
|
前端开发 JavaScript
React render 的原理和触发时机
React render 的原理和触发时机
160 0
|
前端开发 JavaScript
react如何实现数据渲染
react如何实现数据渲染
167 0
|
前端开发 JavaScript
使用React Hooks实现无限滚动加载列表
React Hooks是React 16.8版本中新增的特性,它提供了一种函数式的编程方式,使得组件的逻辑更加清晰、易于维护。在这篇文章中,我们将使用React Hooks来实现一个无限滚动加载列表的功能,这个功能可以用于大数据量的列表展示,同时也能提高用户的交互体验。
2094 0
|
JavaScript 前端开发
Vue3 组件,一点也不难
5.动态 Prop 类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:
155 1
Vue3 组件,一点也不难