美文网首页让前端飞Web前端之路前端开发技巧
h5实现下拉刷新,模拟原生下拉刷新,封装组件

h5实现下拉刷新,模拟原生下拉刷新,封装组件

作者: 一个写前端的姑娘 | 来源:发表于2019-07-16 13:48 被阅读3次

    上一篇,我们实现了h5 实现向左平滑,出现按钮操作,封装组件,模拟购物车左滑删除,现在我们将要实现一个下拉刷新的组件,模拟原生下拉刷新的操作。这对h5手势的要求也是蛮高的,接下来,我们就一步一步的实现下拉刷新的操作。

    需求背景

    在原生app中嵌入h5页面,有些页面需要下拉刷新操作,一般比较简单的方法就是使用其他框架封装的下拉刷新,比如说mint-ui框架中的loadmore组件就可以实现下拉刷新操作,但是样式上可能就和整个app的风格不一致了。既然都是封装好的组件,那为什么我们不能自己封装一个组件,并且样式风格由我们自己来定了。

    基础知识

    touchstart事件:事件对象event,包含手指触摸的位置
    touchmove事件:事件对象event,包含手指滑动的位置
    touchend事件:事件对象event,包含手指离开屏幕的位置

    封装组件

    1. 首先我们先考虑下拉刷新的html结构

    <div class="pull-refresh" ref="scrollBox">
          <!-- 下拉刷新文字,下拉状态 -->
        <div class="pull-refreshing-text"></div>
          <!-- 页面内容 -->
        <slot/>
      </div>
    
    • 下拉刷新的文字有三种状态,下拉刷新=>释放刷新=>加载中,下面代码中刷新距离是自己定义的。
      下拉即可刷新:页面下拉距离 < 刷新的距离
      释放即可刷新:页面下拉距离 >= 刷新的距离
      加载中:页面下拉距离 >= 刷新距离 && 手指释放

    2. css样式

    • 首先,下拉刷新的文字部分,一开始隐藏的,下拉出现
    • 其次,slot部分的样式,我们可以忽略
    .pull-refresh {
        height: calc(~'100vh - 50px');
        .pull-refreshing-text {
            margin-top: -50px;
            line-height: 50px;
            height: 50rem;
            font-size:14px;
            color: #5a5a5a;
            text-align: center;
        }
    }
    
    • 最后下拉刷新的三种状态,我们定义一个下拉状态的变化moveState,0:初始状态(下拉即可刷新),1:释放即可刷新,2:加载中。所以我们的css样式和html结构可以根据moveState来变化
    <!-- 下拉刷新文字,下拉状态 -->
    <div class="pull-refreshing-text">
        <!-- moveState为0和1的时候   下拉即可刷新,释放即可刷新 --> 
        <div v-if="moveState < 2">
            <!-- 下拉刷新 箭头图片 moveState从0变成1的时候箭头图片旋转180度,这个由css实现-->
            <img class="pull_icon" src="箭头图片" :class="{'pull_icon-rotate': moveState === 1}"  alt>
            {{ moveState === 0 ? '下拉即可刷新...' : '释放即可刷新...' }}
        </div>
        <!-- 加载中 moveState=2 -->
        <div v-else>
              <!-- loading状态的图片+文字 -->
             <i class="pull_loading"></i> 加载中...
        </div>
    </div>
    

    html结构增加下拉三种状态

    .pull-refreshing-text {
        margin-top: -50px;
        line-height: 50px;
        height: 50px;
        font-size: 14px;
        color: #5a5a5a;
        text-align: center;
        // 下拉即可刷新
        .pull_icon {
            height: 30px;
            display: inline-block;
            margin-right: 10px;
            transition: transform 0.28s;  // 箭头旋转动画时间
            vertical-align: middle;
            // 释放即可刷新
            &.pull_icon-rotate {
                transform: rotate(-180deg);  // 箭头旋转180度
            }
        }
        // 加载中
        .pull_loading {
            display: inline-block;
            width: 20px;
            height: 20px;
            background-image: url('./loading.gif');  // loading动画
            background-size: 20px 20px;
            vertical-align: middle;
        }
    }
    

    3. 绑定触摸滑动事件

    • 绑定事件
      在mounted钩子函数中绑定事件
    let el = this.$refs.scrollBox
    el.addEventListener('touchstart', e => {
        this.touchStart(e)
    })
    el.addEventListener('touchmove', e => {
        this.touchMove(e)
    })
    el.addEventListener('touchend', e => {
        this.touchEnd(e)
    })
    
    • 触摸处理函数
      在处理函数之前,我们首先要考虑好这个组件需要哪些全局变量,首先是移动的距离moveDistance,其次是触摸开始的起始y轴位置startY(为了在touchmove触发时候,计算y轴滑动距离),动画持续时间duration(手指离开屏幕之后,页面要回归到原始位置,这个动画的持续时间),下拉的三种状态moveState(0:下拉即可刷新,1:释放即可刷新,2:加载中)
      在methods中处理相对应的绑定事件
    touchStart(e) {
        // 如果正在加载 则阻住触发
        if (this.moveState === 2) return
        // 触摸开始时,动画时间,移动距离归0
        this.distance = 0
        this.moveDistance = 0
        // 获取初始y轴位置
        this.startY = e.targetTouches[0].clientY
    },
    touchMove(e) {
        // 如果正在加载 则阻止触发
        if (this.moveState === 2) return
        // 首先计算当前页面是否有滚动条,有滚动条,那么触摸滑动就是页面简单的上下滚动
        let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
        if (scrollTop > 0) return
        let move = e.targetTouches[0].clientY - this.startY
        // 判断手指滑动的距离,只有为正数才代表用户下拉了。
        if (move > 0) {
            // 阻止默认事件
            e.preventDefault()
            // 增加滑动阻力的感觉
            this.moveDistance = Math.pow(move, 0.8)
            if (this.moveDistance > 50) {
                // 如果滑动距离大于50 ,moveState状态更新为释放即可刷新
                if (this.moveState === 1) return
                this.moveState = 1
            } else {
                // 否则 恢复原样
                if (this.moveState === 0) return
                this.moveState = 0
            }
        }
    }
    touchEnd(e) {
        // 如果正在加载 则阻住触发
        if (this.moveState === 2) return
        // 只要手指拿开,加上结束时的动画
        this.duration = 300
        if (this.moveDistance > 50) {
            // 手指松开之后,就开始变成加载中的状态了
            this.moveState = 2 
            this.moveDistance = 50
            // 在家中,开始刷新页面数据,刷新之后有一个回调函数
            this.$emit('refresh', () => {
                // 这里就是成功后的回调了,如果该函数被调用,那就以为着加载数据完成,所以状态要回到0,当然需要在父组件调用。
                this.moveState = 0
                this.moveDistance = 0
            })
        } else {
            // 否则 回到初始状态
            this.moveDistance = 0
        }
    }
    

    4. 下拉动画
    使用vue的钩子函数computed计算样式

    computed: {
        style() {
            return {
                transition: `${this.duration}ms`,
                transform: `translate3d(0,${this.moveDistance}px, 0)`
            }
        }
    }
    

    html加上style,形成动画

    <div class="pull-refresh" ref="scrollBox" :style="style">
    </div>
    

    至此,我们完成了基本的下拉刷新的功能组件,但是我们还可以进一步优化这个组件,比如说页面有个手势触发之后,下拉的手势就需要禁止掉,这个时候我们需要考虑到。阻止事件的触发stop属性由父组件传进来,根据这个stop值,我们控制事件的触发与否
    更改代码如下

    el.addEventListener('touchstart', e => {
        // 根据stop值阻止事件触发
        !this.stop && this.touchStart(e)
    })
    el.addEventListener('touchmove', e => {
        // 根据stop值阻止事件触发
        !this.stop && this.touchMove(e)
    })
    el.addEventListener('touchend', e => {
        // 根据stop值阻止事件触发
        !this.stop && this.touchEnd(e)
    })
    

    完整的下拉刷新的组件就全部完成了,下面就是怎么引用这个组件了

    使用组件

    import pullRefresh from '/pullRefresh.vue'
    components: {pullRefresh}
    // html
    <pull-refresh @refresh="refresh">
          ...
    </pull-refresh>
    // 方法
    refresh() {
      // 刷新页面,重新请求接口
    }
    

    相关文章

      网友评论

        本文标题:h5实现下拉刷新,模拟原生下拉刷新,封装组件

        本文链接:https://www.haomeiwen.com/subject/qdbgkctx.html