zoukankan      html  css  js  c++  java
  • 小程序图片轮播特效swiper(纯手打)

    前言

    一个月前还是用vue做微信H5,后面公司业务发展,入坑小程序,做了几款小程,跑了不少坑, 也会陆续在后面几节跟大家分享。
    在这节给大家分享这个 小程序图片轮播实现方案

    初步的实现思路

    我要实现的效果

    能看到 左右两边如果有图,会显示一部分出来,本来也想用 小程序自带的swiper 组件,无法达到,左右两边 看到上(下)图片的效果,无法改变他组件原来的设置(坑)

    图片描述

    在开始之前,先想想h5是怎么实现的,用原生写,可以在某个固定框的盒子里,再用一个div 包住 x 张图,然后改变 ontouchmove 时改变 left(或者translateX) ,判断用户手指滑动足够距离,就滑到下(上)一张,
    最后判断到最后一张或者第一张,不滑动就好(在这里不做无缝滚动)。
    jquery,vue 很多库都能够实现

    我们只要 实现了第一张图的滑动,记录这个偏移量 tranX1 = 0 + offsetX, 第二张的滑动距离 tranX2 = tranX1 + offsetX ,第三张的滑动距离 tranX3 = tranX2 + offsetX ...
    相反方向 也就 递减  tranX1 = tranX2 - offsetX ...
    然后判断临界值就OK了
    了解了大概的滑动过程现在就可以掀起袖子干了~

    具体技术实现

    写了个 swiper 的方法,用原形链继承的方式,与小程序的page({})里面代码尽量分开, 用惯了Vue的双向绑定,特别讨厌小程序的 this.setData 而且是异步的(坑),this有时候要用变量保留,
    先定义了几个变量,初始化一些必要参数,
    记录 touch 过程中 滑动开始的坐标,滑动过程中,和滑动结束时的坐标,

    构造 swiper 函数里面

    opt 配置
    swiperIndex 用于记录 滑动到的图片索引,默认值为0
    singleOffsetX 滑一张的tranX 偏移量
    boxTranslateX 盒子容器总偏移量 默认0
    _x_start (单位px)记录touchstart里的e.touchs[0].pageX
    _y_start (单位px)记录touchstart里的e.touchs[0].pageY
    _x_move (单位px)记录touchsmove里的e.touchs[0].pageX
    _x_offset 临时变量,记住 _x_move-_x_start 手指移动距离
    _x_end (单位px)记录touchend里的 e.changedTouches[0].pageX
    _x_realOffset (单位px)临时变量,根据临界值 图片真实移动
    screenWidth = 750 屏幕宽度默认 iphone6 750rpx
    screenHeight = 1210 屏幕高度默认 iphone6 1210rpx
    pixelRatio 根据微信api里 systemInfo设备屏幕宽度 计算比例
    maxTranX 根据图片的数量计算最大偏移量,用于临界判断图片描述
    width 盒子的总宽度(用于view 上面绑定 单位:rpx )根据图片数量计算盒子的总宽度 = 首末两边(100)x 2+ 图片与图片之间的间距(60)* (图片数量 -1)+ 图片宽度 x 图片数量

    (this.width = 100 2 + (this.opt.imgLength - 1) 60 + 550 * this.opt.imgLength)

    然后执行函数 computedScreenRatio 根据宽转换比例

    代码如下

    'use strict';
    var swiper = function(opt){
      // 保存设置
      this.opt =opt
      // 当前 移动块停留索引
      this.swiperIndex = 0
      // 盒子容器总偏移量
      this.boxTranslateX = 0 
      // 每移动一张图会增加的偏移量
      this.singleOffsetX = -610
      // 触摸
      this._x_start = 0 
      this._y_start = 0 
      // 移动
      this._x_move = 0 
      // 离开
      this._x_end = 0 
      // 偏移量
      this._x_offset = 0
      // move 过程中真实偏移
      this._x_realOffset = 0
    
      this.screenWidth = 750
      this.screenHeight = 1210
      this.pixelRatio = 2
      // rpx
      this.maxTranX = this.singleOffsetX * (this.opt.imgLength -1  ) 
      // 容器宽度 width 100 是两边靠墙
      this.width = 100 * 2 + (this.opt.imgLength - 1) *60 + 550 * this.opt.imgLength
    
      // 计算宽转换比例
      this.computedScreenRatio(opt.systemInfo)
    }
    

    rpx(responsive pixel): 可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6

    上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

    iphone6 1rpx = 0.5px , iphone5 1rpx = 0.42px 根据宽度做兼容

    // 计算宽转换比例
    swiper.prototype.computedScreenRatio = function (systemInfo){
      this.pixelRatio = systemInfo.pixelRatio
      this.screenWidth = systemInfo.screenWidth
      this.screenHeight = systemInfo.screenHeight  
      //this.singleOffsetX = -610
      // 奇怪的i5 按照算法会 多偏移2 px
      if (systemInfo.model.indexOf('iPhone 5') > -1 ){
        this.singleOffsetX = -(610 * (this.screenWidth / 750) -2  ).toFixed()
      }
      else{
        this.singleOffsetX = -610 * (this.screenWidth / 750)
      }
      this.maxTranX = this.singleOffsetX * (this.opt.imgLength - 1) 
      // 回调绑定vm ,渲染盒子宽度
      this.opt.success && this.opt.success(this.width)
    }

    扯一下小程序

    • bindtouchstart : ontouchstart
    • bindtouchmove: ontouchmve
    • bindtouchend : ontouchend 一样是有e.touches e.changedTouches

    下面是从滑动开始到结束的处理过程代码分析

    keepStartX(touchstart): 记录开始状态 比较简单就不讲了

    moveBox (touchend)是一个手指滑动,所有图片(盒子)跟着手指滑动的过程

    • 1.手指向右滑,_x_offset > 0 ,滑向上一张图
    • 2.手指向左滑,_x_offset < 0 ,滑向下一张图
    • 按逻辑来说,手指水平方向上pageX 的距离, 图片盒子就应该跟着向(左)或者向右偏移一样的量, 但是 从最后一张 开始 向左滑,后面已经没有图了,(或者 从第一张图开始已经向右滑,前面已经没有图了 ),这时候就要做临界值判断了,结果就有手指滑动距离 _x_offset ,还有盒子滑动应该滑的准确距离 lastTranX

    touchEnd

    computedTranX:

    • 根据 滑动方向,临界值 计算出 手指滑动时,盒子的应该滑动的方向与距离 tranX (注: 这里tranX 从第一张开始是0 ,偏移量是负数,所以_x_realOffset永远是 <0 )

    计算最后手指离开的坐标,_x_realOffset用来保存计算 真实的在x方向上的距离R

    // bindtouchstart
    swiper.prototype.keepStartX = function(e, callback){
      this._x_start = e.touches[0].pageX
      this._y_start = e.touches[0].pageY
      callback && callback()
    }
    // bindtouchmove
    /*
      函数说明 moveBox
      @params e  事件
      @params {function} callback 图片盒子的偏移量改变,绑定到vm 上面,视图发生变化
    */
    swiper.prototype.moveBox = function (e, callback) {
      this._x_move = e.touches[0].pageX 
      this._x_offset = this._x_move - this._x_start 
      var lastTranX = this.computedTranX(this._x_offset)
      this._x_realOffset = lastTranX
      callback && callback(lastTranX)
    }
    /* 
        函数说明 根剧移动偏移量临界值计算出真实位移用
        滑下一张 判断是否超出临界值,超出则等于临界值
         若不超过则偏移量 = 手指(touch)移动距离 + 当前盒子偏移量
    */
    swiper.prototype.computedTranX = function ( offsetX ){
        // 滑向上一张
        if( offsetX > 0  ){
          return offsetX + this.boxTranslateX 
        }
        // 滑动下一张
        else if (offsetX < 0 ){ 
          if ( Math.abs(offsetX - this.boxTranslateX) > Math.abs(this.maxTranX - 50) ){
            return this.maxTranX
          }else{
            return offsetX + this.boxTranslateX 
          }
        }
    }
    
    // bindtouchend 
    swiper.prototype.ontouchEnd = function(e, callback){
    
      // 记录手指离开屏幕的坐标
      this._x_end = e.changedTouches[0].pageX
      this._x_realOffset = this._x_end - this._x_start
      // 判断滑动距离超过 指定值 轮播一张图
      var canExchangeImgFromOffset = Math.abs(this._x_realOffset) >= 50 ? true : false
      // 滑动距离达到 换图的要求
      if ( canExchangeImgFromOffset ){
        // 变量说明 计算总偏移
        var lastTotalTranlateX ;
        //  滑向上一张
        if (this._x_offset > 0) {
          console.log('//  滑向上一张')
          // 判断是否已经在第一张图,若不是,则滑动上一张
          if (Math.abs(this.boxTranslateX) > 0) {
            // lastTotalTranlateX 递增
            // this.singleOffsetX 为负数 -- 得 +
            this.swiperIndex -= 1
            lastTotalTranlateX = this.boxTranslateX - this.singleOffsetX
          } 
          else {
            // 已在第一张图 ,动画恢复原位
            this.swiperIndex = 0
            lastTotalTranlateX = 0
          }
        }
        //  滑向下一张
        else {
          console.log('//  滑向下一张')
          if ( Math.abs(this.boxTranslateX) < Math.abs(this.maxTranX) ) {
            // lastTotalTranlateX 递增
            this.swiperIndex += 1
            lastTotalTranlateX = this.boxTranslateX + this.singleOffsetX
          } else {
            console.log('到底图了')
            this.swiperIndex = this.opt.imgLength -1
            lastTotalTranlateX = this.maxTranX 
          }  
        }
        this.boxTranslateX = lastTotalTranlateX
        /* callback 说明
          @参数1  是否执行动画
          @参数2  若参数1为true, 则盒子的tranX 应该变成 lastTotalTranlateX,动画飞到对应的图 
           小程序 执行 wx.createAnimation 
        */
        callback && callback(true, lastTotalTranlateX)
        // reset 所有 与touch 相关参数
        this.resetParams()
      }
      else{
        callback && callback(false)
        // reset 所有 与touch 相关参数
        this.resetParams()
      }
    }
    源码地址 https://gitee.com/adfasdfasdfas/XiaoChengXu-swiper-LunBodemo
    
    

    本文转载于:猿2048⇒https://www.mk2048.com/blog/blog.php?id=h0i2cbh0cib

  • 相关阅读:
    方法参数个数最多不宜超过4个
    避免方法中使用大量局部变量
    JQuery学习备忘
    CSS学习备忘
    解析Path方法备忘
    获取差集合的一种实现思路
    前台JSP页面独立化
    requireJs的使用
    handlebar
    移动端h5<a>标签点击样式去除
  • 原文地址:https://www.cnblogs.com/10manongit/p/12723336.html
Copyright © 2011-2022 走看看