手动实现基于vue构建移动触摸滑动组件——简易的swiper

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

手动实现基于vue构建移动触摸滑动组件——简易的swiper_第1张图片

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

  • touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发。
  • touchmove事件:当手指在屏幕上滑动的时候连续地触发。在这个事件发生期间,调用preventDefault()事件可以阻止滚动。
  • touchend事件:当手指从屏幕上离开的时候触发。

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

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

手动实现基于vue构建移动触摸滑动组件——简易的swiper_第2张图片

      视窗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的样式。

第一页
第二页
第三页

      二、 如何触发滑动:

     每个触摸事件的触发都会获取到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效果的需求,有多个地方使用这样的页面,我们可继续抽象出公共组件,页面可以直接使用。

// 页面中引入滑动组件

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

// weiper组件  视窗a + 容器b
//wiperitem组件  内容c

具体slot的使用可以参照vue官方文档:https://cn.vuejs.org/v2/guide/components-slots.html
完整代码见:https://github.com/chenjycm/myswiper

你可能感兴趣的:(vue,vue,滑动翻页,swiper,触摸,移动端)