zoukankan      html  css  js  c++  java
  • 前端页面如何实现下拉刷新

    页面的滚动区域本来是用的插件vue-scroller,但是由于在一些低端安卓机中页面略有卡动,可能是GPU不给力造成的,这里尝试用原生的overflow: auto; 来测试一下滚动效果,发现效果不错,但是在ios设备中就发现了了滚动没有惯性很死板的体验,这里可以在滚动容器中写一行css属性-webkit-overflow-scrolling: touch;,这样就有原生的滚动体验啦,接下来就差一个下拉刷新的效果了,没有找到现成的轮子,这里就自己开撸

    如何实现

    1. 当容器的scrollTop为0的时候,使用transform: translateY来模拟
    2. 检测下拉的高度当达到某一固定值的时候,释放手指,调用回调函数实现下拉刷新

    着手实现

    既然是下拉我们肯定需要监听touchstarttouchmovetouchend三个dom事件

    touchstart

    el.addEventListener('touchstart', e => {
        if (el.scrollTop !== 0) {
            return
        }
        beginPagY = e.touches[0].pageY
        e.preventDefault()
    })
    

    用于记录手指点按屏幕时候的位置,为了后续translateY的值计算做准备

    touchstartmove

    el.addEventListener('touchmove', e => {
        if (el.scrollTop !== 0) {
            return
        }
        const pageY = e.touches[0].pageY
        const distance = currentPos = pageY - beginPagY
        if (distance < 0 || distance > maxTranslateY) {
            // 上拉的和超过最大限定高度时候不做任何处理
            return;
        }
        if (distance > 60) {
            iconEl.classList.add('active')
        } else {
            iconEl.classList.remove('active')
        }
        e.preventDefault()
        el.style.transform = `translateY(${distance}px)`
    })
    

    touchmove主要是根据手指下拉的距离不断的修改container的translate的值来达到效果, 同时记录当前下拉的distance,用于松手是判断是否触发下拉刷新的效果; 同时在模拟下拉效果的时候要阻止系统默认事件e.preventDefault()

    touchend

    let clear = () => {
        this.isShowLoading = false
        el.style.transform = `translateY(0)`
        setTimeout(() => {
            el.style.transition = ``
        }, 200)
    }
    el.addEventListener('touchend', () => {
        el.style.transition = `.2s`
        if (currentPos >= 60) {
            this.isShowLoading = true
            el.style.transform = `translateY(30px)`
            callback && callback(() => {
                clear()
            })
            return
        }
        clear()
    })
    

    touchend 主要是用来松手时是否执行下拉刷新的效果, 当currentPos达到预先设定的值的时候就触发回调函数,这里设置transition来增加动画效果

    最终效果

    所有代码

    <!doctype html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            #app {
                height: 100vh;
                overflow: hidden;
                display: flex;
                flex-direction: column;
            }
            header {
                 100%;
                height: 44px;
                background: teal;
                z-index: 10;
            }
            main {
                height: calc(100% - 44px);
                overflow: auto;
                -webkit-overflow-scrolling: touch;
                flex: 1;
            }
            .item {
                font-size: 12px;
                line-height: 30px;
                color: #aaa;
            }
            .item + .item {
                border-top: 1px solid;
            }
        </style>
        <style>
            .css-icon {
                display: inline-block;
                height: 1em;  1em;
                font-size: 20px;
                box-sizing: border-box;
                text-indent: -9999px;
                vertical-align: middle;
                position: relative;
            }
            .css-icon::before,
            .css-icon::after {
                content: '';
                box-sizing: inherit;
                position: absolute;
                left: 50%; top: 50%;
                -ms-transform: translate(-50%, -50%);
                transform: translate(-50%, -50%);
            }
    
    
            .icon-upward::before {
                height: .65em;  .65em;
                border-style: solid;
                border- 2px 0 0 2px;
                -ms-transform: translate(-50%, -50%) rotate(45deg);
                transform: translate(-50%, -50%) rotate(45deg);
            }
            .icon-upward::after {
                height: .8em;
                border-left: 2px solid;
                top: 55%;
            }
    
            .icon-upward.active {
                transform: rotate(180deg);
                transition: transform .3s;
            }
    
    
            .pull-to-refresh-layer {
                height: 60px;
                margin-top: -60px;
                font-size: 12px;
                text-align: center;
                color: #aaa;
                line-height: 30px;
            }
        </style>
    </head>
    <body>
    <div id="app">
        <header></header>
        <main>
            <div ref="container">
                <div class="pull-to-refresh-layer">
                    <div v-show="!isShowLoading">
                        <i ref="icon" class="css-icon icon-upward"></i>
                        <p>下拉刷新</p>
                    </div>
                    <div v-show="isShowLoading" style="padding-top: 30px;">
                        假装是个loading图标
                    </div>
                </div>
                <div class="item" v-for="item in list" :key="item">{{item}}</div>
            </div>
        </main>
    </div>
    <script src="./vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                isShowLoading: false
            },
            computed: {
                list() {
                    return new Array(100).fill(0).map((item, index) => index)
                }
            },
            mounted() {
                this.pullRefresh(this.$refs.container, (done) => {
                    setTimeout(() => {
                        done()
                    }, 1000)
                })
            },
            methods: {
                pullRefresh(el, callback) {
                    let beginPagY = 0
                    let currentPos
                    const maxTranslateY = 150
                    const iconEl = this.$refs.icon
                    el.addEventListener('touchstart', e => {
                        if (el.scrollTop !== 0) {
                            return
                        }
                        beginPagY = e.touches[0].pageY
                        e.preventDefault()
                    })
                    el.addEventListener('touchmove', e => {
                        if (el.scrollTop !== 0) {
                            return
                        }
                        const pageY = e.touches[0].pageY
                        const distance = currentPos = pageY - beginPagY
                        if (distance < 0 || distance > maxTranslateY) {
                            // 上拉的时候不做任何处理
                            return;
                        }
                        if (distance > 60) {
                            iconEl.classList.add('active')
                            console.log(iconEl.classList);
                        } else {
                            iconEl.classList.remove('active')
                        }
                        e.preventDefault()
                        el.style.transform = `translateY(${distance}px)`
                    })
                    let clear = () => {
                        this.isShowLoading = false
                        el.style.transform = `translateY(0)`
                        setTimeout(() => {
                            el.style.transition = ``
                        }, 200)
                    }
                    el.addEventListener('touchend', () => {
                        el.style.transition = `.2s`
                        if (currentPos >= 60) {
                            this.isShowLoading = true
                            el.style.transform = `translateY(30px)`
                            callback && callback(() => {
                                clear()
                            })
                            return
                        }
                        clear()
                    })
                }
            }
        })
    </script>
    </body>
    </html>
    
    
  • 相关阅读:
    Verilog HDL刷题笔记(06)(Circuit-Combinational Logic-Arithmetic Circuit)
    Verilog HDL刷题笔记(05)(Circuit-Combinational Logic-Multiplexers)
    Verilog HDL刷题笔记(04)(Circuit-Combinational Logic-Basic Gates)
    Verilog HDL刷题笔记(03)
    Verilog HDL刷题笔记(02)
    Verilog HDL刷题笔记(01)
    某点评 手机验证码自动登录
    线程锁实现多线程读取mongo 数据库库
    Python mongo 快速读取
    正方教務管理系統RSA 加密
  • 原文地址:https://www.cnblogs.com/songbw/p/11662783.html
Copyright © 2011-2022 走看看