实现打字机特效

该案例学习自B站UP主xiao-high

打印多条文段可以参考一下这里:传送门。案例见博客个人简介的应用,点这里看效果。(打印一段文字后,再打印一段,覆盖前边的内容)

介绍

文本一个一个的显示,同时有光标闪烁效果。

点击这里查看效果:传送门

动手制作

新建一个HTML文件。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>qsdbl</title>
</head>
<body>
  
</body>
</html>

body

添加一个div,class名为text,用于控制文本和光标的大小。div内部添加两个span,分别作为文本和光标的容器。光标为符号|

<div class="text">
  <span class="word"></span><span class="gbiao">|</span>
</div>

css

去除浏览器默认的margin、padding值。

* {
  margin: 0;
  padding: 0;
}

body设置让div居中显示,设置一个径向渐变背景。

body {
  height: 100vh;
  /*让文本居中*/
  display: flex;
  align-items: center;
  justify-content: center;
  /*径向渐变*/
  background: radial-gradient(#000000, rgb(31, 77, 20));
}

设置div内的字体颜色为白色,字体大小在后边js代码中设置。

.text {
  color: #fff;
  text-align:center;
}

实现光标闪烁

制作光标闪烁动画:动画设置两帧,透明度从0到100。

@keyframes flash {
			from {
				opacity: 0;
			}

			to {
				opacity: 1;
			}
}

光标应用该动画,动画播放时间为0.5秒,线性播放,循环播放。同时设置左外边距为5px。

.text .gbiao {
			margin-left: 5px;
			animation: flash 0.5s linear infinite;
			/*让光标闪烁*/
}

script

参数说明:

  • fontSize,字体大小
  • word,显示文本的span标签
  • str,文本

在进行绘制之前,我们需要确定打开HTML文件的设备是pc还是手机。从而指定不同的fontSize。

var ua = navigator.userAgent.toLowerCase();
if(/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|ZTE/.test(navigator.userAgent)) || ua.match(/MicroMessenger/i) == "micromessenger"){
  var fontSize = 50;//手机字体大小
}else{
  var fontSize = 28;//pc字体大小
}

设置文本大小

//设置文本大小
		let textSize = document.querySelector('.text');
		textSize.style.fontSize = fontSize + "px";

上边的js代码可以使用CSS中的@media 查询来实现,具体代码如下:

在前边css的.text中添加字体大小:(PC端)

font-size: 28px;

在前边的css后边再添加一个style标签,指定移动端的字体大小。代码如下:

<style type="text/css">
@media(max-width: 500px) {
	.text{
		font-size: 50px;
	}
}
</style>

判断设备类型的js代码和设置文本大小的js代码就可以删掉了。

添加要显示的文本

let str = "你好,我是轻率的保罗!很高兴见到你!"; //要显示的文本

通过class名选择显示文本的span标签

//获取文本显示的span
let word = document.querySelector('.word');

实现打字机效果

有了str和word我们就可以实现打字机效果了。将实现打字机效果封装在一个方法内,方法名showText

//实现打字机效果
function showText() {
  
}

我们定义几个变量:

  • myflag,布尔值,用于后边的正倒放中
  • time,每个字符显示的时间长度
  • timewait,正倒放等待时间
let myflag = true;
let time = 300; //每个字符显示的时间
let timewait = 2000; //正倒放等待时间

实现正放

我们规定,正放就是从没有显示字符到显示出全部的文本的过程。反之为倒放。

正放思路:使用一个for循环,循环次数为要显示的文本的个数,每进入一个循环就截取要显示的文本的一部分显示在页面上。例如第一次进入for循环,截取“你”;第二次进入for循环,截取“你好”;第三次进入for循环,截取“你好,”;第四次进入for循环,截取“你好,我”;。。。代码实现如下:

for (let n = 1; n <= str.length; n++) { //正放
		word.innerHTML = str.substr(0, n);
}
//substr(start,length)方法可在字符串中抽取从 start 下标开始的指定数目的字符。

可是电脑运行速度都是很快的,一瞬间for循环就执行完了,也就是说我们看不到文本一个一个的显示出来。我们需要控制每一次截取文本显示到页面的时间。

我们可以使用一个定时器,隔指定时间执行定义在其内部的函数。前边我们定义了每个字符显示的时间为time=300毫秒,前一个字符等待显示的时间为0,前两个字符等待显示的时间为time,前三个字符等待显示的时间为两个time,前四个字符等待显示的时间为三个time,。。。所以越往后时间越长。代码实现如下:

setTimeout(function (){
	word.innerHTML = str.substr(0, n);
},(n - 1) * time);//单位是毫秒

所以实现正放代码应该为:

for (let n = 1; n <= str.length; n++) { //正放
  setTimeout(function() { //定时器
    word.innerHTML = str.substr(0, n);
  }, (n - 1) * time);
}

实现倒放

倒放与正放刚刚好相反。正放是先显示前一个字符,再显示前两个字符,。。。倒放是先显示全部的字符,然后少显示一个,再然后少显示两个,。。。所以j的初始值为字符的长度str.length。时间变成了str.length - j ,j越来越小,str.length不变,所以越往后时间越长,跟前边正放一样。代码实现如下:

for (let j = str.length; j >= 0; j--) { //倒放
  setTimeout(function() { //定时器
    word.innerHTML = str.substr(0, j);
  }, (str.length - j) * time);
}

正/倒放结合

实现的效果是先正放,然后倒放,再然后是正放一直循环下去。这里我们需要用到一个周期定时器,每隔一定的时间(正放或倒放结束后),就执行一次倒放或正放。

setInterval(function (){

},毫秒数);

每隔一定的时间,这个时间我们可以通过str.length * time来计算,str.length * time为一次正放或倒放所用的时间,如果想让正放倒放相隔一定的时间,我可以再添加一个等待时间,即前边定义的timewait

setInterval(function (){
  
}, str.length * time + timewait);

要实现一次正放一次倒放交替执行,我们需要用到在前边定义的布尔类型变量myflag,配合if-else语句即可实现。代码如下:

if(myflag){
  //正放
}else{
  //倒放
}
myflag = !myflag;

所以正/倒放结合完整代码如下:

setInterval(function(myflag) {
  if (this.myflag) {
    for (let i = 1; i <= str.length; i++) { //正放
      setTimeout(function() { //定时器
        word.innerHTML = str.substr(0, i);
      }, (i - 1) * time);
    }
  } else {
    for (let j = str.length; j >= 0; j--) { //倒放
      setTimeout(function() { //定时器
        word.innerHTML = str.substr(0, j);
      }, (str.length - j) * time);
    }
  }
  this.myflag = !this.myflag;
}, str.length * time + timewait);

到这里,实现打字机效果的函数showText,貌似就已经完成了。不过我在实际的测试中发现有一个bug,与传递到周期定时器内的参数myflag有关。导致第一次正放没有显示,到了倒放才开始显示文本。这个bug目前我修复不了,不过我在周期定时器的前边添加了一个正放,可以掩盖掉那个bug。如果你解决了这个bug请一定要跟我分享一下解决方法。函数showText未掩盖bug的完整代码如下:

//实现打字机效果
function showText() {
  let myflag = true;
  let time = 300; //每个字符显示的时间
  let timewait = 2000; //正倒放等待时间
  setInterval(function(myflag) {
    if (this.myflag) {
      for (let i = 1; i <= str.length; i++) { //正放
        setTimeout(function() { //定时器
          word.innerHTML = str.substr(0, i);
        }, (i - 1) * time);
      }
    } else {
      for (let j = str.length; j >= 0; j--) { //倒放
        setTimeout(function() { //定时器
          word.innerHTML = str.substr(0, j);
        }, (str.length - j) * time);
      }
    }
    this.myflag = !this.myflag;
  }, str.length * time + timewait);
}

函数showText掩盖bug后的完整代码如下:

//实现打字机效果
function showText() {
  let myflag = true;
  let time = 300; //每个字符显示的时间
  let timewait = 2000; //正倒放等待时间
  for (let n = 1; n <= str.length; n++) { //正放
    setTimeout(function() { //定时器
      word.innerHTML = str.substr(0, n);
    }, (n - 1) * time);
  }
  setInterval(function(myflag) {
    if (this.myflag) {
      for (let i = 1; i <= str.length; i++) { //正放
        setTimeout(function() { //定时器
          word.innerHTML = str.substr(0, i);
        }, (i - 1) * time);
      }
    } else {
      for (let j = str.length; j >= 0; j--) { //倒放
        setTimeout(function() { //定时器
          word.innerHTML = str.substr(0, j);
        }, (str.length - j) * time);
      }
    }
    this.myflag = !this.myflag;
  }, str.length * time + timewait);
}

最后,我们需要调用一下这个函数,才能使打字机效果生效。我这里是添加了一个定时器,页面加载完成之后过1s再调用实现打字机效果的函数。代码如下:

//打开页面1s后显示文本
setTimeout(showText, 1000);

源码

至此全部的代码都完成了。下边是全部代码整合:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>qsdbl</title>
	</head>
	<body>
		<div class="text">
			<span class="word"></span><span class="gbiao">|</span>
		</div>
	</body>
	<style>
		* {
			margin: 0;
			padding: 0;
		}

		body {
			height: 100vh;
			/*让文本居中*/
			display: flex;
			align-items: center;
			justify-content: center;
			/*径向渐变*/
			background: radial-gradient(#000000, rgb(31, 77, 20));
		}

		.text {
			color: #fff;
		}

		.text .gbiao {
			margin-left: 5px;
			animation: flash 0.5s linear infinite;
			/*让光标闪烁*/
			font-weight: bold;
		}

		@keyframes flash {
			from {
				opacity: 0;
			}

			to {
				opacity: 1;
			}
		}
	</style>
	<script>
		var ua = navigator.userAgent.toLowerCase();
		if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (
				/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|ZTE/
				.test(navigator.userAgent)) || ua.match(/MicroMessenger/i) == "micromessenger") {
			var fontSize = 50; //手机字体大小
		} else {
			var fontSize = 28; //pc字体大小
		}
		//设置文本大小
		let textSize = document.querySelector('.text');
		textSize.style.fontSize = fontSize + "px";
		
		let str = "你好,我是轻率的保罗!很高兴见到你!"; //要显示的文本
		
		//获取文本显示的span
		let word = document.querySelector('.word');
		//打开页面1s后显示文本
		setTimeout(showText, 1000);
		
		//实现打字机效果
		function showText() {
			let myflag = true;
			let time = 300; //每个字符显示的时间
			let timewait = 2000; //正倒放等待时间
			for (let n = 1; n <= str.length; n++) { //正放
				setTimeout(function() { //定时器
					word.innerHTML = str.substr(0, n);
				}, (n - 1) * time);
			}
			setInterval(function(myflag) {
				if (this.myflag) {
					for (let i = 1; i <= str.length; i++) { //正放
						setTimeout(function() { //定时器
							word.innerHTML = str.substr(0, i);
						}, (i - 1) * time);
					}
				} else {
					for (let j = str.length; j >= 0; j--) { //倒放
						setTimeout(function() { //定时器
							word.innerHTML = str.substr(0, j);
						}, (str.length - j) * time);
					}
				}
				this.myflag = !this.myflag;
			}, str.length * time + timewait);
		}
	</script>
</html>

修复bug

使用闭包来解决bug,详细笔记访问这里。(这里的也是使用了闭包,不过定时器内并没有使用到外边定义的标志位myflag,函数定义的问题。定时器内的this.myflag不是外边定义的myflag,而是匿名函数传递进来的空值重新被后边的this.myflag = !this.myflag;语句赋值了的定时器内的局部变量,所以第一次没有执行if中的正放代码是因为其值为null。解决方法是把定时器内的匿名函数拿出来,定时器内调用函数名即可。)

打字机效果案例源码:https://cloud.189.cn/t/MbYraiArERrq(访问码:hzj6)

修复bug

下边的方法已经废弃,有了更好的实现方法。已放到上边。这里的方法也可以实现效果,但是过于凌乱。

其实bug并没有修复,而是使用了另一种方法来实现打字机效果。将正、倒放单独作为一个函数,不过在正放的函数结束后调用倒放的函数。再使用一个函数调用正放的函数。

  • 正、倒放函数,positive(element,str, time, timewait)、reverse(element,str, time, timewait)

    • 各形参分别为:显示文本的容器,显示的文本,一个字符显示时间,正倒放间隔时间

    • 正、倒放函数都是在正、倒放操作的基础上加一个定时器,添加等待时间

      //倒放
      setTimeout(function() {
      
      
        //内部的实现代码与前边的一样,并未修改
        for (let j = str.length; j >= 0; j--) { //倒放
          setTimeout(function() { //定时器
            element.innerHTML = str.substr(0, j);
          }, (str.length - j) * time);
        }
      
      
      }, timewait);//使用定时器增加等待时间
      
    • 正放函数的后边调用倒放函数,计算好正放时间加等待时间后使用定时器调用

      //正放
      setTimeout(function() {
        for (let i = 1; i <= str.length; i++) { //正放
          setTimeout(function() { //定时器
            element.innerHTML = str.substr(0, i);
          }, (i - 1) * time);
        }
        
        
        //调用倒放
        setTimeout( 调用倒放 , 正放所用时间+等待时间 );
        
        
      
      }, timewait);//播放前的等待时间
      
      
  • 调用正放的函数,showText02(element, str, num,time,timewait),形参有:显示文本的容器,显示的文本,播放次数(正+倒为一次),一个字符显示时间,正倒放间隔时间

    • 使用for循环,实现指定的播放次数。不过在调用正放函数时需要使用定时器。
    • 可以将正放的函数看作是一次正放加倒放(正放后边调用了倒放),所以定时器的时间可以设置为一次正放的时间+一次倒放的时间+两个等待时间,即:str.length * time * 2 + timewait*2
    • showText02有四个参数,但是我们可以内置字符显示时间(200ms)、等待时间(2000ms)和播放次数 (1次),使用时如果不想频繁设置这些参数,只需要给显示文本的容器要显示的文本两个参数即可。

使用:

//获取文本显示的span(显示文本的容器)
let word = document.querySelector('.word');
showText02(word,str,4);//显示文本的容器、显示的文本,播放次数(正+倒为一次),一个字符显示时间,正倒放间隔时间

实现打字机效果的一些函数:

//实现方法2
function showText02(element,str, num,time,timewait) {
  //time,每个字符显示的时间,建议200毫秒
  //timewait,正倒放等待时间,建议2000毫秒
  //num,播放次数,默认一次
  if(time == null){
    time = 200;
  }
  if(timewait == null){
    timewait = 2000;
  }
  if(num == null){
    num = 1;
  }
  for (var i = 0; i < num; i++) {//for循环控制播放次数
    setTimeout(function() {
      positive(element,str, time, timewait);
    }, (str.length * time * 2 + timewait*2) * i);//括号内的时间为一次正加一次倒
  }
}
//正放
function positive(element,str, time, timewait) {
  setTimeout(function() {
    for (let i = 1; i <= str.length; i++) { //正放
      setTimeout(function() { //定时器
        element.innerHTML = str.substr(0, i);
      }, (i - 1) * time);
    }
    setTimeout(function() {
      reverse(element,str, time);
    }, str.length * time + timewait);//正放结束后再开始倒放,使用定时器增加正放时间和结束后的等待时间
  }, timewait);//播放前的等待时间
}
//倒放
function reverse(element,str, time, timewait) {
  setTimeout(function() {
    for (let j = str.length; j >= 0; j--) { //倒放
      setTimeout(function() { //定时器
        element.innerHTML = str.substr(0, j);
      }, (str.length - j) * time);
    }
  }, timewait);//使用定时器增加等待时间
}

完整源代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>qsdbl</title>
	</head>
	<body>
		<div class="text">
			<span class="word"></span><span class="gbiao">|</span>
		</div>
	</body>
	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}

		body {
			height: 100vh;
			/*让文本居中*/
			display: flex;
			align-items: center;
			justify-content: center;
			/*径向渐变*/
			background: radial-gradient(#000000, rgb(64, 204, 15));
		}

		.text {
			color: #fff;
			/*0f0*/
			text-align: center;
			font-size: 40px;
			font-weight: bold;
		}

		.text .gbiao {
			margin-left: 5px;
			animation: flash 0.5s linear infinite;
			/*让光标闪烁*/
		}

		@keyframes flash {
			from {
				opacity: 0;
			}

			to {
				opacity: 1;
			}
		}
	</style>
	<style type="text/css">
		/*当显示设备为手机时,字体大小设置为20px。(用于判断设备类型的500px是一个经验值)*/
		@media(max-width:500px) {
			.text {
				font-size: 20px;
			}
		}
	</style>
	<script>
		let str = "你好,我是轻率的保罗!很高兴见到你!"; //要显示的文本
		//获取文本显示的span(显示文本的容器)
		let word = document.querySelector('.word');
		//播放4次
		showText02(word,str,4);//显示文本的容器,显示的文本,播放次数(正+倒为一次),一个字符显示时间,正倒放间隔时间


		//实现打字机效果(下边为封装的函数)
		function showText02(element,str, num,time,timewait) {
			//time,每个字符显示的时间,建议200毫秒
			//timewait,正倒放等待时间,建议2000毫秒
			if(time == null){
				time = 200;
			}
			if(timewait == null){
				timewait = 2000;
			}
      if(num == null){
        num = 1;
      }
			for (var i = 0; i < num; i++) {//for循环控制播放次数
				setTimeout(function() {
					positive(element,str, time, timewait);
				}, (str.length * time * 2 + timewait*2) * i);//括号内的时间为一次正加一次倒
			}
		}
		//正放
		function positive(element,str, time, timewait) {
			setTimeout(function() {
				for (let i = 1; i <= str.length; i++) { //正放
					setTimeout(function() { //定时器
						element.innerHTML = str.substr(0, i);
					}, (i - 1) * time);
				}
				setTimeout(function() {
					reverse(element,str, time);
				}, str.length * time + timewait);//正放结束后再开始倒放,使用定时器增加正放时间和结束后的等待时间
			}, timewait);//播放前的等待时间
		}
		//倒放
		function reverse(element,str, time, timewait) {
			setTimeout(function() {
				for (let j = str.length; j >= 0; j--) { //倒放
					setTimeout(function() { //定时器
						element.innerHTML = str.substr(0, j);
					}, (str.length - j) * time);
				}
			}, timewait);//使用定时器增加等待时间
		}
	</script>
</html>

原文链接:实现打字机特效

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值