js实现字符串动画轮播效果代码实例

2017-3-13 15:53| 作者: antzone| 查看: 699| 评论: 0|来自: 蚂蚁部落

分享一段代码实例,它利用js实现了字符串动画轮播效果。

代码实例如下:

[HTML] 纯文本查看 复制代码
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="author" content="http://www.softwhy.com/" />
<title>蚂蚁部落</title>
<style>
html, body {
  background: #212121;
  height: 100%;
}
.container {
  height: 100%;
  width: 100%;
  justify-content: center;
  align-items: center;
  display: flex;
}
.text {
  font-weight: 100;
  font-size: 50px;
  color: #FAFAFA;
}
.dud {
  color: #757575;
}
</style>
<script>
class TextScramble {
  constructor(el) {
    this.el = el;
    this.chars = '!<>-_\\/[]{}—=+*^?#________';
    this.update = this.update.bind(this);
  }
  setText(newText) {
    const oldText = this.el.innerText;
    const length = Math.max(oldText.length, newText.length);
    const promise = new Promise((resolve) => this.resolve = resolve);
    this.queue = [];
    for (let index = 0; index < length; index++) {
      const from = oldText[index] || '';
      const to = newText[index] || '';
      const start = Math.floor(Math.random() * 40);
      const end = start + Math.floor(Math.random() * 40);
      this.queue.push({ from, to, start, end });
    }
    cancelAnimationFrame(this.frameRequest);
    this.frame = 0;
    this.update();
    return promise;
  }
  update() {
    let output = '';
    let complete = 0;
    for (let index = 0, n = this.queue.length; index < n; index++) {
      let { from, to, start, end, char } = this.queue[index];
      if (this.frame >= end) {
        complete++;
        output += to;
      } else if (this.frame >= start) {
        if (!char || Math.random() < 0.28) {
          char = this.randomChar();
          this.queue[index].char = char;
        }
        output += `<span class="dud">${char}</span>`;
      } else {
        output += from;
      }
    }
    this.el.innerHTML = output;
    if (complete === this.queue.length) {
      this.resolve();
    } else {
      this.frameRequest = requestAnimationFrame(this.update);
      this.frame++;
    }
  }
  randomChar() {
    return this.chars[Math.floor(Math.random() * this.chars.length)];
  }
}
 
window.onload=function(){
  const phrases = [
    '蚂蚁部落',
    'css教程',
    'js教程',
    'softwhy.com',
    '努力奋斗',
    'json教程'
  ];
 
  const el = document.querySelector('.text');
  const fx = new TextScramble(el);
 
  let counter = 0;
  const next = () => {
    fx.setText(phrases[counter]).then(() => {
      setTimeout(next, 800)
    })
    counter = (counter + 1) % phrases.length;
  }
  next()
}
</script>
</head>
<body>
<div class="container">
  <div class="text"></div>
</div>
</body>
</html>

上面的代码实现了我们的要求,下面介绍一下它的实现过程。

代码注释:

(1).class TextScramble {}创建一个类。

(2).constructor(el) {

  this.el = el;

  this.chars = '!<>-_\\/[]{}—=+*^?#________';

  this.update = this.update.bind(this);

},类的构造函数,能够初始化一些值。

this.update = this.update.bind(this),这个的目的是为了固定函数的this指向,不管其他地方怎么调用update()方法,  update()内部的this都是指向当前的那个实例对象。

(3).setText(newText) {},声明一个原型上的方法,参数是一个语句。

(4).const oldText = this.el.innerText,获取当前元素的文本内容。

(5).const length = Math.max(oldText.length, newText.length),获取当前元素字符串和新传入字符串的最大长度。

(6).const promise = new Promise((resolve) => this.resolve = resolve),创建一个promise对象实例,后面会用到,之所以将resove方法赋值给this.resolve,是为了在可以在其他地方用实例对象来调用此方法。

(7).this.queue = [],创建一个数组,后面会用到。

(8).for (let index = 0; index < length; index++) {

  const from = oldText[index] || '';

  const to = newText[index] || '';

  const start = Math.floor(Math.random() * 40);

  const end = start + Math.floor(Math.random() * 40);

  this.queue.push({ from, to, start, end });

}通过for循环来为数组添加元素,下面分步介绍一下:

const from = oldText[index] || '';

const to = newText[index] || '';

原来的文本和新传入的不一定哪个更长,index有可能会超出,所以如果超出就赋值给空字符。

(9).const start = Math.floor(Math.random() * 40);

const end = start + Math.floor(Math.random() * 40);

40这个数字没有特别的逻辑,也可以是其他数字,生成一个起始值和结束值。

(10).this.queue.push({ from, to, start, end }),将对象压入数组。

(11).cancelAnimationFrame(this.frameRequest),取消上一个动画的执行。

(12).this.frame = 0,赋值为0,后面会用到。

(13).this.update(),调用update()方法。

(14).return promise,返回promise对象。

(15).update() {},此函数是实现动画变换的核心。

(16).let output = '',声明一个变量,用存储输出新显示的语句。

(17).let complete = 0,声明一个变量并赋初值为0,后面会用到。

(18).for (let index = 0, n = this.queue.length; index < n; index++) {  

  let { from, to, start, end, char } = this.queue[index];

  if (this.frame >= end) {

    complete++;

      output += to;

    } else if (this.frame >= start) {

      if (!char || Math.random() < 0.28) {

        char = this.randomChar();

        this.queue[index].char = char;

      }

      output += `<span class="dud">${char}</span>`;

    } else {

      output += from;

    }

}

虽然代码看起来比较多,其实逻辑很简单。

this.frame刚开始是0并且能够累加,刚开始有很大的概率是小于end,所以就会执行后面两个if语句分支的代码,于是就会出现展现原来字符串内容和chars所规定的特殊的字符效果;随着this.frame累加,最终会大于等于end,那么output中的字符只有新的数组字符。

(19).this.el.innerHTML = output,在文档中显示指定字符串。

(20).if (complete === this.queue.length) {

  this.resolve();

} else {

  this.frameRequest = requestAnimationFrame(this.update);

  this.frame++;

},如果if (complete === this.queue.length)成立,那么说明新字符串组合完毕,比如"蚂蚁部落"连接完整。

那么就执行this.resolve()方法,改变promise的状态。

否则继续动画的执行。


鲜花

握手

雷人

路过

鸡蛋

最新评论

返回顶部