移动端轮播图实现

405 阅读4分钟

思路总结

  • 第一 因为我们用的是变换函数translate来移动ul ,为了方便我们获取和设置ul的位置,我们需要封装一个变换函数设值和获值的函数 来方便操作 不然我们就要用全局变量了
    • 首先我们用参数的个数来判断是设值还是获值
    • 因为我们知道变换函数的属性 一次可以设多个值 比如 transform: translateX(200px) rotate(60deg) scaleX(1.5)
    • 所以为了封装一个比较完美的函数 我们在其中给要变换的元素加一个属性,这个属性是一个对象
    • 把变换函数名作为属性名 变换函数值作为属性值 存入这个对象当中
    • 然后遍历这个对象,分不同的情况给定不同的单位
    • 在获值时我们也根据变换函数的情况设置默认值
(function (w) {


    w.transformCss = function (node, prop, value) {
        //用一个对象来 装所有的变换函数
        if (node.transformData == undefined) {
            node.transformData = {}
        }

        //先判断参数个数是设值还是获值
        if (arguments.length === 2) {
            //获值 返回变换函数的值
            let param = node.transformData[prop]

            if(param == undefined) {
                if(prop = 'scale' || 'scaleX' || 'scaleY'){
                    param = 1
                }else {
                    param = 0
                }
            }
              return param

        } else if (arguments.length === 3) {
            //设置变换函数的值

            //首先把所有的变换函数和值都放进对象中
            node.transformData[prop] = value

            //遍历对象
            let transformStr = ''
            for (const key in node.transformData) {
                //判断变换函数的类型
                switch (key) {
                    case 'translate':
                    case 'translateX':
                    case 'translateY':
                        transformStr += key + '(' + node.transformData[key] + 'px)'
                        break;
                    case 'scale':
                    case 'scaleX':
                    case 'scaleY':
                        transformStr += key + '(' + node.transformData[key] + ') '
                        break;
                    case 'rotate':
                    case 'skew':
                    case 'skewX':
                    case 'skewY':
                        transformStr += key + '(' + node.transformData[key] + 'deg) '
                        break;
                    default:
                        break;
                }              
            }
            node.style.transform = transformStr
        }
    }
})(window)
  • 第二 因为后面要无缝滚动 要改变ul中的li 所以我们ul和li的宽度 都用js来设置

  • 第三 让图片可以被滑动起来

    • touchstart中 我们获取两个值 一个是触点的初始位置 一个是ul初始的translateX值
    • touchmove中 我们需要获取触点当前的值
    • translateX = 触点当前值 - 触点初始值 + ul的translateX初始值
    • 注意这里的移动距离每时每刻都是在变换的 我们不能拿当前的translateX的值去算,那样就变成了累加 ,所以用原始值 ,也就是触点出现的位置
  • 第四 现在我们在通过滑动来实现切换图片

    • 这里有个很巧的算法 就是用 当前的translateX的值 / 轮播图的宽度 然后再四舍五入就是index了 也就是图片的索引值 为什么是这样呢? 是因为这个商可以表示 我们轮播图移动了几张 如果第二张划到一半 可以看到第三张的一半 这是这里的商就是-1.5 通过四舍五入 就是-2 把index转成正数 我们就得到要移动到哪一张的index啦

    • 然后限定范围 这个很简单

    • 最后根据得到的index来移动ul和切换小点

  • 第五 现在切换时会很生硬 所以我们加上过渡 ,但是加在哪呢 很简单 我们手指离开时 就要过渡 让图片自己完成接下来的动作 注意 我们需要在触点开始时取消过渡,因为当我们用手指滑动时,我们希望是实时的,不需要过渡

  • 第六 现在完成无缝轮播

    • 把整个ul都复制一份 要在设置 ul和li的宽度之前 ,这个很容易理解

    • 然后重新获取下ul里面的li

    • 接下来我们思考怎么去刷的一下来移动这个ul ,让他不露馅儿 箭头就是刷的一下

      第一组第一张 => 第二组的第一张 第二组最后一张 => 第一组最后一张

      • 我们看到需要第一组的数据 为了方便我们事先在没克隆之前 获取下li的length
//Itemlength 是原来的li个数   listItems.length是现在的li个数 
 if (index <= 0) {
                    index = Itemlength
                    //然后马上刷的一下改变位置
                    bannerList.style.transform = transformCss(bannerList, 'translateX', -index * banner
                        .clientWidth)
                } else if (index >= listItems.length - 1) {
                    index = Itemlength - 1
                    bannerList.style.transform = transformCss(bannerList, 'translateX', -index * banner
                        .clientWidth)
                }

  • 设置在startTouch中 ,刚好没有过渡 同时这样设置后 就不会超出限定的范围 范围限定可以不要了

  • 小点的样式切换 我们可以取余来做 这样很方便 用index % 本来的li的个数 0 % 5 = 0 5 % 5 = 0

  • 第七 实现快速滑动也能切换

    • 思路 时间间隔 = 触点结束时间 - 触点出现时间 new Date().getTime()
    • 接下来判断 时间间隔300ms的话,我们就直接用移动距离来判断 实现切换 index++ index--
    • 没有的话 还是用原来的那个算法 到一半我们才切换
    • 这里有个BUG 因为我们的移动距离一直被保存在整个轮播图元素的属性当中 这时我们先移动一次 再点一下 就会触发上一次的切换 所以我们再每次触点出现时 将存储移动距离的这个属性清0