上拉加载和下拉刷新

96 阅读3分钟

1.上拉加载

三个dom属性:

clientHeight:不包含边框的元素可视区高度

scrollTop:元素滚动时卷上去的距离

scrollHeight: 元素实际高度,包含卷上去的高度

根据这个三个属性可以得到一个公式:clientHeight + scrollTop <= scrollHeight - 触底的指定距离

上拉加载的原理

通过监听元素的滚动事件(scroll)判断元素是否滚动到了距离底部指定距离时触发加载数据

知道了原理和三者之间的关系后,我们就知道只需要判断这个公式即可知道滚动条有没有进入触底距离

实现代码

html部分

<section class="container">
    <section class="list">
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
    </section>
</section>

CSS部分

 * {
    margin: 0;
    padding: 0;
    list-style: none;
}

.container {
    height: 100vh;
    overflow-y: scroll;
}

.container .list {
    border: 1px solid #666;
}

.container .list li {
    line-height: 80px;
}

.container .list li:nth-child(2n) {
    background-color: #ccc;
}

js部分

<script type="text/javascript" defer="defer">
    // 滚动容器
    const container = document.querySelector('.container');
    // 监听滚动事件
    container.addEventListener('scroll', _.debounce(function (e) {
        // 当元素的可视高度+滚入的距离>=元素真实高度-触底距离时,触发加载更多
        if ((this.clientHeight + this.scrollTop) >= this.scrollHeight - 50) {
            setTimeout(() => {
                // 异步加载
                console.log('加载更多')
            }, 1000);
        }
    }, 1000))
</script>

重点:

需要在head标签中引入<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

2.下拉刷新

移动端触屏事件:touchstart(手指按下) touchmove(手指移动) touchend(手指离开)

手指在页面上的坐标: pageXpageY

注意:

  1. 手指按下时记录按下的位置
  2. 在手指下滑时(touchmove)计算手指的坐标离手指按下时初始位置的差值得出下滑的距离,让容器顺应手指下滑的方向移动(translateY)对应差值的距离,对应的给一个允许用户下滑的最大距离,避免页面下拉过长.
  3. 在手指松开时(touchend)判断下滑的差值是否达到预期的值来进行对应的刷新数据和回弹loading.

实现代码

html代码

<section class="container">
    <section class="loading">
        <span>下拉刷新</span>
    </section>
    <section class="list">
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
        <li>内容</li>
    </section>
</section>

CSS代码

*{
    margin: 0;
    padding: 0;
    list-style: none;
}
.container{
    position: relative;
    top: -105px;
}
.container .loading{
    text-align: center;
    height: 105px;
    line-height: 105px;
}
.container .list{
    border: 1px solid #666;
}
.container .list li{
    line-height: 80px;
}
.container .list li:nth-child(2n){
    background-color: #ccc;
}

js代码

<script>
    // 容器
    const container = document.querySelector('.container');

    const span = document.querySelector('.loading span');
    let start = 0; //开始位置
    let end = 0; //结束位置
    // 手指按下
    container.addEventListener('touchstart',function(e){
        span.textContent = '下拉刷新'

        // 获取开始位置
        start = e.touches[0].pageY
    })

    // 手指移动
    container.addEventListener('touchmove',function(e){
        // 计算下拉差值
        const current = e.touches[0].pageY;
        // 计算差值
        end = current - start;
        // 下拉值达到,提示松手
        if(end > 100){
            span.textContent = '松手刷新'
        }

        // 限制下拉的最大值,超过不能下拉
        if(end < 120){
            this.style.transition = 'transform 0s'
            this.style.transform = `translateY(${end}px)`
        }
    })

    // 手指离开
    container.addEventListener('touchend',function(e){
        // 回弹
        this.style.transition = 'transform 0.5s'
        if(end > 0 && end < 120){
            this.style.transform = `translateY(0px)`
            return 
        }
        if(end > 100){
            this.style.transform = `translateY(100px)`
            span.textContent = '刷新中...'
            setTimeout(()=>{
                span.textContent = '刷新成功'
                setTimeout(()=>{
                    this.style.transform = `translateY(0px)`
                },1000)
            },2000)
        }
        end = 0
    })
</script>