纯js实现图片无缝循环走马灯效果支持拖拽和惯性滑动

要求实现一个无缝循环的图片滚动公告,支持上下,左右模式。

要求 1,不可有卡顿图片无缝轮播

         2 ,手指拖拽暂停轮播,用户可左右(或上下)拖拽,快速滑动有惯性效果。

         3, 用户拖拽完成后3秒继续播放循环滚动。

         4,页面上可以存在多个走马灯。

这种需求和轮播图类似,但效果区别是轮播图是一张张切换,有切换的效果,我们要求更接近滚动公告效果。

 

 

 

实现逻辑 1 视窗设置overflow:hidden,复制dom结构追加到父元素上,让父元素总宽度超过视窗宽度(代码里paetPiiic为视窗,piiic_region为父元素,piiic_item为要求轮播的元素)

                2 设置定时器,修改父元素piiic_region的left(或top)值,处理边界

                3 touch start touchmove touchend事件绑定,touchmove的时候piiic_region跟手指左右(上下)移动,处理边界。

                4 touchend的时候,获取手指滑动速度,给元素继续设置惯性移动,直至速度为0,每次移动要处理边界。

代码实现:我们的需求是要求上下和左右以及轮播速度可在后台配置的,所有有些属性写在dom上取用。

<!--上下方向图片-->
<div class="partPiiic" style="position: absolute;width: 3.75rem;height: 3.75rem;top: 0rem;left: 0rem;overflow:hidden" slidespeed="10">
      <div class="piiic_region" slidedirection="UD" slidespeed="10" style="position: relative; width: 100%;">
        <div class="piiic_item" style="position:relative;width:100%">
          < img style="width:100%;display:block;" src="test.jpg">
        </div>
      </div>
    </div>
<!--左右方向-->
<div class="partPiiic" style="position: absolute;width: 3.75rem;height: 1.81rem;top: 3.88rem;left: 0rem;overflow:hidden" slidespeed="10">
      <div class="piiic_region" slidedirection="LR" slidespeed="10" style="display: flex; position: relative; height: 100%; ">
        <div class="piiic_item" style="position:relative;height:100%" >
          < img style="height:100%" src="test1.jpg">
        </div>
      
      </div>
    </div>

js代码:

window.onload = function () { 
 //初始化图片走马灯
longPicInit(); 
}
function longPicInit() {
    var container = document.querySelector("body");
    var partPiiicList = container.querySelectorAll(".partPiiic");
    if (partPiiicList.length > 0) {
        for (var index = 0; index < partPiiicList.length; index++) {
            var partPiiicNode = partPiiicList[index];
               //存在其他业务逻辑,删除后只保留走马灯逻辑
               //根据你自己的实际情况,获取到所有走马灯元素即可
                //执行循环动画              
                loopLongPic(partPiiicNode);         
        }
    }
}
//主方法
function
loopLongPic(partPiiicNode) {
//timeflag标志位 offspeed走马灯每次移动距离 copynum需要复制的子元素数量
var timeFlag = 1, offSpeed = 1, copyNum = 1, picTimer; var piiic_region = partPiiicNode.querySelector(".piiic_region"); var speed = piiic_region.getAttribute("slidespeed"); //走马灯速度 var deraction = piiic_region.getAttribute("slidedirection");//走马灯方向 上下还是左右 var piiic_item = piiic_region.querySelector(".piiic_item");//走马灯元素 if (deraction == "LR") {
//根据视图宽度除子元素宽度计算需要复制几个子元素 copyNum
= Math.ceil(partPiiicNode.offsetWidth / piiic_item.offsetWidth); var text = $(piiic_region).html(); for (var i = 0; i < copyNum; i++) {
//复制后追加 $(piiic_region).append(text); } piiic_region.style.width
= piiic_item.offsetWidth * (copyNum + 1) + "px"; } else {
//上下方向上的复制,逻辑同理 copyNum
= Math.ceil(partPiiicNode.offsetHeight / piiic_item.offsetHeight); var text = $(piiic_region).html(); for (var i = 0; i < copyNum; i++) { $(piiic_region).append(text); } piiic_region.style.height = piiic_item.offsetHeight * (copyNum + 1) + "px"; }
//复制后,开启跑马灯 picTimer
= setInterval(LoopMove, speed) function LoopMove() { if (timeFlag == 0) { clearInterval(picTimer) picTimer = null; return false; } if (deraction == "LR") {
//边界处理函数,到头拉回 criticalX() piiic_region.style.left
= piiic_region.offsetLeft - offSpeed + "px"; } if (deraction == "UD") { criticalY(); piiic_region.style.top = piiic_region.offsetTop - offSpeed + "px"; } }

//添加touch事件
var touchStartX = 0,touchStartY = 0, moveStartY = 0, starttime = 0,restart, animateMoveTimer; piiic_region.addEventListener("touchstart", function (e) { if (picTimer) { clearInterval(picTimer); picTimer = null; } if (restart) { clearTimeout(restart); restart = null; } if (animateMoveTimer) { clearInterval(animateMoveTimer) } timeFlag = 0 //暂停定时器 手动拖拽上下左右距离 var ev = e || window.event; var touch = ev.targetTouches[0];
//记录touch初始位置 touchStartX
= touch.pageX; touchStartY = touch.pageY;
//记录元素初始位置 moveStartX
= piiic_region.offsetLeft; moveStartY = piiic_region.offsetTop; starttime = Date.now(); piiic_region.addEventListener("touchmove", preventDefault, false); }) piiic_region.addEventListener("touchmove", picImgMove) function picImgMove(e) { timeFlag = 0; if (timeFlag == 0) { var ev = e || window.event; var touch = ev.targetTouches[0] if (deraction == "LR") {//左右移动
//根据当前位置-初始位置计算手指移动距离 改变元素left
var moveX = touch.pageX - touchStartX; piiic_region.style.left = moveStartX + moveX + "px"; criticalX() } if (deraction == "UD") {//上下移动 var moveY = touch.pageY - touchStartY; piiic_region.style.top = moveStartY + moveY + "px"; criticalY() } } } piiic_region.addEventListener("touchend", function (e) { piiic_region.removeEventListener("touchmove", preventDefault); //获取最总结束位置 var ev = e || window.event; var touch = ev.changedTouches[0] var time = Date.now() - starttime;
//获取手指滑动速度 设置参数 可以根据自己想要的效果设置不同值
var endeSpeed = 0, rationSpeed = 40; //执行惯性移动 if (deraction == "LR") { var distanceX = touch.pageX - touchStartX; endeSpeed = (distanceX / time) * rationSpeed; animateMove(endeSpeed) } if (deraction == "UD") { var distanceY = touch.pageY - touchStartY; endeSpeed = (distanceY / time) * rationSpeed; animateMove(endeSpeed) } }) function animateMove(endeSpeed) { if (animateMoveTimer) { clearInterval(animateMoveTimer) } //endeSpeed是结束时的初速度,a为加速度,每隔1ms速度递减执行当前速度*1ms时间的距离,如果速度接近0,则清除计时器 var a = endeSpeed < 0 ? 2 : -2; animateMoveTimer = setInterval(function () { if (Math.abs(endeSpeed) < 1) { clearInterval(animateMoveTimer); if (picTimer) {clearInterval(picTimer); picTimer = null;} if (restart) {clearTimeout(restart); restart = null;} restart = setTimeout(function () { timeFlag = 1; picTimer = setInterval(LoopMove, speed); }, 3000); return; } endeSpeed += a; if (deraction == "LR") { piiic_region.style.left = piiic_region.offsetLeft + endeSpeed + "px"; criticalX(); } if (deraction == "UD") { piiic_region.style.top = piiic_region.offsetTop + endeSpeed + "px"; criticalY(); } },1) } //边界处理函数 function criticalX() { if (piiic_region.offsetLeft < -piiic_region.offsetWidth / (copyNum + 1)) {
//拖到最右边 循环 piiic_region.style.left
= 0; } else if (piiic_region.offsetLeft >= 0) {
//拖到最左边 循环 piiic_region.style.left
= -piiic_region.offsetWidth / (copyNum + 1) + "px"; } } function criticalY() { if (piiic_region.offsetTop < -piiic_region.offsetHeight / (copyNum + 1)) { piiic_region.style.top = 0 } else if (piiic_region.offsetTop >= 0) { piiic_region.style.top = -piiic_region.offsetHeight / (copyNum + 1) + "px"; } } }

 



 

posted @ 2023-03-02 15:15  喵~喵  阅读(1526)  评论(0编辑  收藏  举报