天天看点

JavaScript——滑动翻页功能(缓慢移动+无缝衔接)1. 需求+效果 展示2. 实现代码(带标注)3. 原理解析4.自适应场景5. 在vue中的应用

1. 需求+效果 展示

最近做开发时有这样一个需求,滚动播放列表,数据有限,当这些数据滚动播放结束后再重头开始,做完之后的效果是这样的

JavaScript——滑动翻页功能(缓慢移动+无缝衔接)1. 需求+效果 展示2. 实现代码(带标注)3. 原理解析4.自适应场景5. 在vue中的应用

2. 实现代码(带标注)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>翻页功能</title>
</head>

<body>
    <script>
        let intervalTimer;  // 不断执行的定时器
        let intervalDelay = 1000;  //  定时器执行时间
        let scrollSpeed = 10; // 移动速度
        let scrollHeight = 22; // 移动距离,一页/一行的高度
        const rollContent = [
            {
                name: '第一条',
                data: 1,
            },
            {
                name: '第二条',
                data: 2,
            },
            {
                name: '第三条',
                data: 3,
            },
            {
                name: '第四条',
                data: 4,
            },
            {
                name: '第五条',
                data: 5,
            },
            {
                name: '第六条',
                data: 6,
            },
            {
                name: '第七条',
                data: 7,
            },
            {
                name: '第八条',
                data: 8,
            },
            {
                name: '第九条',
                data: 9,
            },
            {
                name: '第十条',
                data: 10,
            }
        ]
        // 开始令动画运行
        function initAnimation() {
            // 将所有内容渲染在页面中

            // 创意一个div,将内容ul放置其中,div设置滚动
            const div = document.createElement('div');
            // 创建一个ul,用于放置li
            const ulList = document.createElement('ul');
            div.appendChild(ulList)
            // 获取外部容器body
            const body = document.getElementsByTagName('body')[0]
            // 将ul动画插入页面中
            body.appendChild(div)
            // 插入li,li循环展示rollContent中的内容
            for (let i = 0; i < rollContent.length; i++) {
                const listItem = document.createElement('li');
                listItem.style = "padding:0 4px;"
                listItem.innerText = rollContent[i].name + '---' + rollContent[i].data
                ulList.appendChild(listItem)
            }
            // 两次循环插入循环内容的两倍,为了在切换时效果更好,理论上加上一页的数据即可,不用插入两倍,但若加上一页的数据,下面处理回到顶部的距离需要重新计算
            for (let i = 0; i < rollContent.length; i++) {
                const listItem = document.createElement('li');
                listItem.innerText = rollContent[i].name + '---' + rollContent[i].data
                ulList.appendChild(listItem)
            }
            // 开启定时器,令内容动起来
            setTimeout(() => {
                moveContent();
            }, intervalDelay)
        }

        function moveContent() {
            // 移动
            const moveDiv = document.getElementsByTagName('div')[0]
            const ul = document.getElementsByTagName('ul')[0]
            ul.style="padding-left:0;margin:0;"
            // 设置样式,令其overflow:scroll;
            moveDiv.style = "height:22px;overflow:scroll;background:lightblue;border-radius:8px";
            // 设置移动距离
            moveDiv.scrollTop ++;
            // 移动时并判断是不是要返回顶部
            intervalTimer = setInterval(() => {
                moveTop();
            }, scrollSpeed);
        }

        // 判断是否返回到顶部
        function moveTop() {
            const moveDiv = document.getElementsByTagName('div')[0]
            const mul = document.getElementsByTagName('ul')[0]
            // 若当前移动距离,与ul高度求余时所得结果为0,表示翻了一页,此时清空定时器,走第二个
            if (moveDiv.scrollTop % scrollHeight === 0) {
                // 清除判断移动距离定时器
                clearInterval(intervalTimer)
                setTimeout(() => {
                    moveContent()
                }, intervalDelay);
            }else{
                // 一点点移动,才有平滑滚动的效果
                moveDiv.scrollTop++;
                if(moveDiv.scrollTop >= mul.offsetHeight/2){
                    moveDiv.scrollTop = 0;
                }
            }
        }
        window.onload = function () {
            initAnimation();
        }
    </script>
</body>

</html>
           

3. 原理解析

  • 实现翻页效果,看上去有两个滚动,一个是外部容器的scrollTop,一个是每一条数据移动,但实际上是通过两个定时器根据不同的条件判断得来
  1. 我们需要一个最外部容器div,设置内容展示的宽高、样式等
  2. 我们需要一个循环数据的容器ul,用于包裹内部li内容,最后在根据他的offsetHeight属性决定何时返回顶部
  3. 开启动画,因为是翻页效果,所以当一页移动完成后,我们需要停顿一段时间,再进行下一次的翻页
  4. 翻页过程要求平滑过渡,所以我们可以设置当前div属性的scrollTop++,令其平滑移动
  5. 在每次平滑移动的过程中,我们需要增加一个定时器进行判断,当前滑动的距离求余每一页的固定距离是否为0,若为0表示一页内容结束,清除定时器,重新进行scrollTop++;若一页内容未结束,我们继续scrollTop++
  6. 判断是否为一页,是否继续scrollTop++时我们要记得进行判断,因为我们是两倍的当前内容,所以当scrollTop的值 >= 当前ul的offsetHeight的一半时,就可以令scrollTop回到顶部继续执行。

4.自适应场景

我们可以通过改变延迟时间、移动速度、移动高度来实现自己所需的效果

5. 在vue中的应用

<div class="applyAnimation-scroll">
      <ul class="applyAnimation-list">
        <ApplyAnimationItem   // 自定义组件,将所需内容传入
          v-for="(item,index) in latestCustomers"
          :key="index" :applyItem="item"/>
      </ul>
    </div>
    
ref: latestCustomers = [];	// 定义循环播放数组 vue3 script setup写法
let interval = null;  // 定时器

// 获取数据
async function getLatestCustomers() {
  const {data} = await tGet(`aaaa/bbbb`, {
    count: 20
  })
  latestCustomers = data;
}

let itemHeight = 34;
let delay = 1000;
let speed = 10;
let time;

async function initScrollAnimation() {
  let area = document.getElementsByClassName('applyAnimation-scroll')[0];
  let list = document.getElementsByClassName('applyAnimation-list')[0];
  let finalHeight = list.offsetHeight;
  area.innerHTML += area.innerHTML;
  area.scrollTop = 0;
  setTimeout(() => {
    starMove(area, finalHeight)
  }, delay);
}

async function starMove(area, finalHeight) {
  area.scrollTop++;
  time = setInterval(() => {
    scrollUp(area, finalHeight)
  }, speed);
}

async function scrollUp(area, finalHeight) {
  if (area.scrollTop % itemHeight === 0) {
    clearInterval(time);
    setTimeout(() => {
      starMove(area, finalHeight)
    }, delay);
  } else {
    area.scrollTop++;
    if (area.scrollTop >= finalHeight) {
      area.scrollTop = 0;
    }
  }
}

onMounted(async () => {
  await getLatestCustomers();
  await initScrollAnimation();
})
           

总结用法,希望可以帮助到你,

我是Ably,你无须超越谁,只要超越昨天的自己就好~

继续阅读