基于vue封装移动触摸滑动组件——简易的swiper

27 篇文章 0 订阅

在web或移动端开发中,有时候我们需要做一个可滚动显示的banner、轮播、滑动翻页显示内容等,常用的插件就数swiper。当然如果我不想因为一个小的页面去引入一个库,那么我们就手动写一个简易版的swiper。因为正做的项目是vue中需要用到滑动翻页效果,就用vue来实现一个垂直方向滑动翻页的效果咯!

核心触摸事件:touchstart、touchmove和touchend。(还有touchcancel事件,这里我们就不考虑了)

touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。

touchmove事件:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用preventDefault()事件可以阻止滚动。

touchend事件:当手指从屏幕上离开的时候触发。

核心动画效果: 使用CSS3的transition属性。

一、如何实现展示页面内容:

接下来我们要如何实现页面能向上或向下活动,我们可以把节点分为两层,第一层为页面上显示内容的视窗a,比如,这个窗口占满整个屏幕;第二层为内容容器b,容器b的大小由多页内容c组成。每页c的大小与视窗a相等,这样只要控制内容容器b的位置就可以让每一个c全部呈现在视窗a中。如下图所示(只有视窗a大小的内容是可以显示的)。

视窗a大小等于内容c 大小,容器b是内容c的整数倍。容器b采用position: absolute,控制属性top为视窗a的整数倍,就可以控制页面显示了。再用transition: top 1s 控制过渡效果,只要给一个状态显示第几页,控制top值就可以自由滚动了。如何控制呢,接下来再看看第二部分用滑动事件来如何触发的向下/向上指令状态改变。

我们构建DOM结构,.wiper-container为视窗a,.wiper-list为容器b,wiper-item为内容c。通过this.refs.wiperbox.offsetHeight获取a的大小,然后通过listStyle 和 itemStyle计算出合适的b、c的样式。

<div class="wiper-container" 
    ref="wiperbox"
    @touchstart="handleTouchStart"
    @touchend="handleTouchEnd"
    @touchmove="handleTouchMove">
    <div class="wiper-list" :style="listStyle">
        <div class="wiper-item" :style="itemStyle">第一页</div>
        <div class="wiper-item" :style="itemStyle">第二页</div>
        <div class="wiper-item" :style="itemStyle">第三页</div>
    </div>
</div>

二、 如何触发滑动:

每个触摸事件的触发都会获取到touch对象包含的属性:

clientX:触摸目标在视口中的x坐标。

clientY:触摸目标在视口中的y坐标。

identifier:标识触摸的唯一ID。

pageX:触摸目标在页面中的x坐标。

pageY:触摸目标在页面中的y坐标。

screenX:触摸目标在屏幕中的x坐标。

screenY:触摸目标在屏幕中的y坐标。

target:触目的DOM节点目标

那么我们可以分别在touchstart 和 touchend事件中记录触摸的初始位置和结束位置,如pageY的值,两者之差我们就可以计算出手指是向上滑动还是向下滑动,这样我们就可以控制内容滑动是向上翻页还是向下翻页,我们也可以设置一个阈值才出发滑动翻页,避免小幅度触摸导致的翻页。

 
handleTouchStart: function(e){
    this.startPoint = e.touches[0].pageY;
}
 
handleTouchEnd: function(e){
    let end = e.changedTouches[0].pageY;
    let start = this.startPoint;
    let delta = start - end;
    let goDown = 0;
    if(delta > 10){
        goDown = 1;
    }else if(delta < -10){
        goDown = -1;
    }
    this.changeItem(goDown);
}

三、提升效果

实现前面两部分内容,向下滑动,页面就向下滑动,向上滑动,页面就向上滑动。但是,如果手指不松开,页面不会跟随手指滑动,而是等手指松开后才滑动。这时我们需要前面未用到的touchmove事件来实现手指跟随效果。手指不断滑动tochmove就会不断触发,我们还是获取pageX值,计算tochmove的值与tochstart记录的初始值进行比较,并在容器b的当前位置上实时修改top值,同时禁用过渡效果,跟随效果就可以实现了。

handleTouchMove: function(e){
    let poChange = e.changedTouches[0].pageY - this.startPoint;
    this.pointChange = poChange
}

四、以此类推

以上原理可以实现手动触发上下滑动效果,稍加修改可以扩展更多:

如果我们将height切换为width,top切换为left,那么我们也就可以实现左右滑动的效果。

如果我们再设置定时器控制页面的切换,那么我们就可以实现轮播图跑马灯banner。

如果我们抽象成组件,再通过传入参数控制组件就可以拓展以上的如果,构造为可复用的组件了。

五、抽象公共组件

到第三部分已经可以满足初步的建议swiper效果的需求,有多个地方使用这样的页面,我们可继续抽象出公共组件,页面可以直接使用。

// 页面中引入滑动组件
<template>
    <div class="hello">
        <wiper>
            <wiperitem color="#90F7EC">
                <div>第一页</div>
            </wiperitem>
            <wiperitem color="#7CAAFF">
                <span>第二页</span>
            </wiperitem>
            <wiperitem>
                <span>第三页</span>
            </wiperitem>
        </wiper>
    </div>
</template>

我把视窗和内容容器都定义在wiper组件中,wiperitem接收每个内容页的内容,两个组件中用到了vue中的插槽slot,wiper组件中可以根据 this.$slots.default 计算出通过slot传入的组件个数来计算有多少页、并控制容器大小,在wiper中处理页面触摸事件和动画效果;在wiperitem中获取wiper对slot传入的参数计算每个页面大小。

// weiper组件  视窗a + 容器b
<template>
    <div class="wiper-container" 
        ref="wiperbox"
        @touchstart="handleTouchStart"
        @touchend="handleTouchEnd"
        @touchmove="handleTouchMove"
    >
        <div class="wiper-list" :style="listStyle" >
            <slot :itemHeight="itemHeight"></slot>
        </div>
    </div>
</template>
//wiperitem组件  内容c
<template>
    <div class="wiper-item" :style="itemStyle">
        <slot></slot>
    </div>
</template>

具体slot的使用可以参照vue官方文档:https://cn.vuejs.org/v2/guide/components-slots.html

完整代码见:https://github.com/chenjycm/myswiper

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值