Skip to content

文字滚动效果

一个类似于新闻播报的效果。

思路

实现一个效果,应该从以下方面切入:

  1. 页面初始化的时候需要做什么?(init)
  2. 页面存在什么交互,分别需要做什么?(交互函数)

js动画思路:

  1. 起始位置start 结束位置end
  2. 多长时间执行完此动画total 动画间隔时间duration
  3. 计算出该段时间需要移动次数 计算出每次需要移动的距离
  4. 执行动画

必要时刻回调函数是可以出奇迹的

案例

html
<!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>
    <link rel="stylesheet" href="./index.css" />
    <!-- <script src="./index.js" defer></script> -->
     <script src="./myScroll.js" defer></script>  
  </head>
  <body>
    <div class="container">
      <h1 class="title">最新公告</h1>
      <ul class="list">
        <!-- 乱数假文 -->
        <li>把大象装冰箱总共分几步?</li>
        <li>1. 邓哥打开冰箱门</li>
        <li>2. 邓哥把大象放进去</li>
        <li>3. 邓哥关上冰箱门</li>
      </ul>
    </div>
  </body>
</html>
css
.container {
  background: #bfedfc;
  overflow: hidden;
  padding: 20px 0;
}
/* .container::after {
  content: '';
  display: block;
  clear: both;
} */
.title {
  float: left;
  font-size: 16px;
  font-weight: normal;
  margin: 0;
  margin-left: 20px;
  margin-top: 5px;
  border-right: 2px solid #ccc;
  padding-right: 30px;
}
.list {
  float: left;
  list-style: none;
  padding: 0;
  height: 30px;
  overflow: hidden ;
  margin: 0;
  margin-left: 50px;
  
}
.list li {
  height: 30px;
  line-height: 30px;
}
js
(function () {
  // 初始化:一开始做什么
  var list = document.querySelector('.list');
  // 1. 将列表中的第一个元素,克隆到列表的最后一个
  function cloneFirstItem() {
    var firstItem = list.children[0];
    var newItem = firstItem.cloneNode(true);
    list.appendChild(newItem);
  }
  cloneFirstItem();

  // 2. 滚动:每隔一段时间,将列表滚动到下一个位置
  var duration = 2000; // 滚动的间隔时间
  setInterval(moveNext, duration);
  var itemHeight = 30; // 每一项的高度
  var curIndex = 0; // 目前展示的是第几项
  // 将列表滚动到下一个位置
  function moveNext() {
    var from = curIndex * itemHeight; // 开始的滚动高度
    curIndex++;
    var to = curIndex * itemHeight; // 下一项的滚动高度
    // 让list的scrollTop,从from慢慢变为to
    // 慢慢变为:在一段时间内,每隔一小段时间,变化一点
    var totalDuration = 300; // 变化的总时间
    var duration = 10; // 变化的间隔时间
    var times = totalDuration / duration; //变化的次数
    var dis = (to - from) / times; // 每次变化的量
    var timerId = setInterval(function () {
      from += dis;
      if (from >= to) {
        // 到达目标值了
        clearInterval(timerId); // 停止计时器
        // 滚动完成后,如果是最后一项
        if (curIndex === list.children.length - 1) {
          from = 0;
          curIndex = 0;
        }
      }
      list.scrollTop = from;
    }, duration);
  }
})();
js
const list = document.querySelector('.list');//获取到ul

/* 1. 页面初始的时候做什么 */
// 克隆第一个元素
function cloneFirst() {
    const first = list.children[0];
    const clone = first.cloneNode(true);
    list.appendChild(clone);
}

cloneFirst();


/* 2. 页面有什么交互 */
let currentIndex = 0;//当前的索引
let distance = 0;//向上滚动的距离
const itemHeight = 30;//每个列表项的高度
const duration = 1000;//滚动的间隔时间

// 移动列表滚动
function moveNext() {
    // JS动画
    const start = currentIndex * itemHeight;
    currentIndex++;
    const to = currentIndex * itemHeight;

    easeAnimation(start, to, 500, (offset, isEnd) => {
        let dy = offset;
        const isExceed = currentIndex === list.children.length - 1;

        //边界判断
        if (isEnd && isExceed) {
            currentIndex = 0;
            dy = 0;
        }

        list.scrollTop = dy;
    });
}

/**
 * 
 * @param {*} start 起始位置
 * @param {*} end  结束位置
 * @param {*} totalDuration 动画执行总时长
 * @param {*} cb 回调函数
 */
function easeAnimation(start, end, totalDuration, cb) {
    const duration = 10;//动画间隔时间,越小越平滑
    const times = totalDuration / duration;//算出该段距离动画需要执行多少次
    const distance = (end - start) / times;//计算每次移动的距离
    let timer;
    let isEnd = false;//动画是否结束

    timer = setInterval(() => {
        start += distance;
        if (start >= end) {
            clearInterval(timer);
            isEnd = true;
        }
        cb && cb(start, isEnd);
    }, duration)
}

setInterval(() => {
    moveNext(distance);
}, duration);

MIT License