整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

仅用18行JavaScript实现一个倒数计时器



有时,您将需要构建一个JavaScript倒数时钟。您可能有活动,销售,促销或游戏。您可以使用原始JavaScript构建时钟,而不用寻找最近的插件。虽然有很多很棒的时钟插件,但是使用原始JavaScript可以带来以下好处:

  • 您的代码将是轻量级的,因为它将具有零依赖性。
  • 您的网站将表现更好。您无需加载外部脚本和样式表。
  • 您将拥有更多控制权。您将构建时钟,使其行为完全符合您希望的方式(而不是尝试将插件弯曲到您的意愿)。

因此,事不宜迟,这里介绍了如何仅用18行JavaScript来制作自己的倒计时时钟



基本时钟:倒数到特定的日期或时间

以下是创建基本时钟所涉及步骤的快速概述:

  • 设置有效的结束日期。
  • 计算剩余时间。
  • 将时间转换为可用格式。
  • 将时钟数据输出为可重复使用的对象。
  • 在页面上显示时钟,并在时钟为零时停止时钟。

设定有效的结束日期

首先,您需要设置一个有效的结束日期。这应该是JavaScript的Date.parse()方法可以理解的任何格式的字符串。例如:

在ISO 8601格式:

const deadline = '2015-12-31';

简短格式:

const deadline = '31/12/2015';

或者,长格式:

const deadline = 'December 31 2015';

这些格式中的每一种都允许您指定确切的时间和时区(对于ISO日期,则为UTC的偏移量)。例如:

const deadline = 'December 31 2015 23:59:59 GMT+0200';

您可以在本文中阅读有关JavaScript中日期格式的更多信息。

计算剩余时间

下一步是计算剩余时间。我们需要编写一个函数,该函数需要一个表示给定结束时间的字符串(如上所述)。然后,我们计算该时间与当前时间之间的时差。看起来像这样:

function getTimeRemaining(endtime){
  const total = Date.parse(endtime) - Date.parse(new Date());
  const seconds = Math.floor( (total/1000) % 60 );
  const minutes = Math.floor( (total/1000/60) % 60 );
  const hours = Math.floor( (total/(1000*60*60)) % 24 );
  const days = Math.floor( total/(1000*60*60*24) );

  return {
    total,
    days,
    hours,
    minutes,
    seconds
  };
}

首先,我们创建一个变量total,以保留剩余时间直到截止日期。该Date.parse()函数将时间字符串转换为毫秒值。这使我们可以相减两次,并获得两者之间的时间量。

const total = Date.parse(endtime) - Date.parse(new Date());

将时间转换为可用格式

现在,我们要将毫秒转换为天,小时,分钟和秒。让我们以秒为例:

const seconds = Math.floor( (t/1000) % 60 );

让我们分解一下这里发生的事情。

  1. 将毫秒除以1000可转换为秒: (t/1000)
  2. 将总秒数除以60,然后取余数。您不希望所有的秒数,仅需要计算分钟数之后剩下的秒数:(t/1000) % 60
  3. 四舍五入到最接近的整数。这是因为您需要完整的秒数,而不是几分之一秒:Math.floor( (t/1000) % 60 )

重复此逻辑,将毫秒转换为分钟,小时和天。

输出时钟数据作为可重用对象

准备好几天,几小时,几分钟和几秒钟之后,我们现在可以将数据作为可重用的对象返回:

return {
  total,
  days,
  hours,
  minutes,
  seconds
};

该对象允许您调用函数并获取任何计算值。这是如何获取剩余时间的示例:

getTimeRemaining(deadline).minutes

方便吧?

显示时钟并在达到零时停止

现在,我们有了一个可以花费剩余的天,小时,分钟和秒的功能,我们可以构建时钟了。首先,我们将创建以下HTML元素来保存时钟:

<div id="clockdiv"></div>

然后,我们将编写一个在新div中输出时钟数据的函数:

function initializeClock(id, endtime) {
  const clock = document.getElementById(id);
  const timeinterval = setInterval(() => {
    const t = getTimeRemaining(endtime);
    clock.innerHTML = 'days: ' + t.days + '<br>' +
                      'hours: '+ t.hours + '<br>' +
                      'minutes: ' + t.minutes + '<br>' +
                      'seconds: ' + t.seconds;
    if (t.total <= 0) {
      clearInterval(timeinterval);
    }
  },1000);
}

该函数有两个参数。这些是包含我们时钟的元素的ID,以及倒计时的结束时间。在函数内部,我们将声明一个clock变量并将其用于存储对我们的时钟容器div的引用。这意味着我们不必继续查询DOM。

接下来,我们将使用setInterval每秒执行一个匿名函数。此功能将执行以下操作:

  • 计算剩余时间。
  • 将剩余时间输出到我们的div。
  • 如果剩余时间为零,请停止计时。

此时,剩下的唯一步骤是像这样运行时钟:

initializeClock('clockdiv', deadline);

恭喜你!现在,您仅用18行JavaScript就拥有了一个基本时钟。

准备显示时钟

在设置时钟样式之前,我们需要进行一些细化。

  • 消除初始延迟,使您的时钟立即显示。
  • 提高时钟脚本的效率,以免持续重建整个时钟。
  • 根据需要添加前导零。

消除初始延迟

在时钟中,我们习惯于setInterval每秒更新一次显示。多数情况下,这很好,除非在开始时会有一秒钟的延迟。要消除此延迟,我们必须在间隔开始之前更新一次时钟。

让我们将要传递给setInterval它的匿名函数移到其自己的独立函数中。我们可以命名这个函数updateClock。在updateClock外部调用该函数setInterval,然后在内部再次调用setInterval。这样,时钟显示就没有延迟了。

在您的JavaScript中,替换为:

const timeinterval = setInterval(() => { ... },1000);

有了这个:

function updateClock(){
  const t = getTimeRemaining(endtime);
  clock.innerHTML = 'days: ' + t.days + '<br>' +
                    'hours: '+ t.hours + '<br>' +
                    'minutes: ' + t.minutes + '<br>' +
                    'seconds: ' + t.seconds;
  if (t.total <= 0) {
    clearInterval(timeinterval);
  }
}

updateClock(); // run function once at first to avoid delay
var timeinterval = setInterval(updateClock,1000);

避免持续重建时钟

我们需要使时钟脚本更高效。我们只想更新时钟中的数字,而不是每秒重新构建整个时钟。实现此目的的一种方法是将每个数字放在span标签中,然后仅更新这些跨度的内容。

这是HTML:

<div id="clockdiv">
    Days: <span class="days"></span><br>
    Hours: <span class="hours"></span><br>
    Minutes: <span class="minutes"></span><br>
    Seconds: <span class="seconds"></span>
</div>

现在让我们参考这些元素。在clock定义变量的位置之后添加以下代码

const daysSpan = clock.querySelector('.days');
const hoursSpan = clock.querySelector('.hours');
const minutesSpan = clock.querySelector('.minutes');
const secondsSpan = clock.querySelector('.seconds');

接下来,我们需要更改updateClock功能以及更新数字。新代码如下所示:

function updateClock(){
    const t = getTimeRemaining(endtime);

    daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = t.hours;
    minutesSpan.innerHTML = t.minutes;
    secondsSpan.innerHTML = t.seconds;

    ...
}

添加前导零

现在时钟不再每秒都在重建,我们还有另一件事要做:添加前导零。例如,不是让时钟显示7秒,而是显示07秒。一种简单的方法是在数字的开头添加字符串“ 0”,然后切掉最后两位数字。

例如,要在“ seconds”值上添加前导零,您可以对此进行更改:

secondsSpan.innerHTML = t.seconds;

对此:

secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

如果需要,您也可以在分钟和小时中添加前导零。如果您走了这么远,恭喜!您的时钟现在可以显示了。

注意:您可能需要在CodePen中单击“重新运行”才能开始倒计时。

更进一步

下面的示例演示如何针对某些用例扩展时钟。它们都是基于上面看到的基本示例。

自动安排时钟

假设我们希望时钟显示在某些日子,而不是其他日子。例如,我们可能会发生一系列事件,并且不想每次都手动更新时钟。这是提前安排事情的方法。

通过在CSS中将其display属性设置为隐藏时钟none。然后将以下内容添加到initializeClock函数中(以开头的行之后var clock)。一旦initializeClock调用此函数,这将导致时钟仅显示:

clock.style.display = 'block';

接下来,我们可以指定显示时钟的日期。这将替换deadline变量:

const schedule = [
    ['Jul 25 2015', 'Sept 20 2015'],
    ['Sept 21 2015', 'Jul 25 2016'],
    ['Jul 25 2016', 'Jul 25 2030']
];

schedule数组中的每个元素代表一个开始日期和一个结束日期。如上所述,可以包括时间和时区,但是我在这里使用了简单的日期来保持代码的可读性。

最后,当用户加载页面时,我们需要检查是否在指定的时间范围内。该代码应替换先前对该initializeClock函数的调用。

// iterate over each element in the schedule
for (var i=0; i<schedule.length; i++) {
  var startDate = schedule[i][0];
  var endDate = schedule[i][1];

  // put dates in milliseconds for easy comparisons
  var startMs = Date.parse(startDate);
  var endMs = Date.parse(endDate);
  var currentMs = Date.parse(new Date());

  // if current date is between start and end dates, display clock
  if (endMs > currentMs && currentMs >= startMs ) {
    initializeClock('clockdiv', endDate);
  }
}

schedule.forEach(([startDate, endDate]) => {
  // put dates in milliseconds for easy comparisons
  const startMs = Date.parse(startDate);
  const endMs = Date.parse(endDate);
  const currentMs = Date.parse(new Date());

  // if current date is between start and end dates, display clock
  if (endMs > currentMs && currentMs >= startMs ) {
    initializeClock('clockdiv', endDate);
  }
});

现在,您可以提前安排时钟,而无需手动更新。您可以根据需要缩短代码。为了便于阅读,我让我变得冗长。

从用户到达起将计时器设置为10分钟

用户到达或开始特定任务后,有必要在给定的时间内设置倒计时。我们将在此处将计时器设置为10分钟,但是您可以使用任意时间。

我们需要做的就是deadline用这个替换变量:

const timeInMinutes = 10;
const currentTime = Date.parse(new Date());
const deadline = new Date(currentTime + timeInMinutes*60*1000);

该代码将花费当前时间,并增加十分钟。这些值将转换为毫秒,因此可以将它们加在一起并变成新的截止日期。

现在,我们有了一个时钟,可以从用户到达时开始倒数十分钟。随意玩耍,尝试不同的时间长度。

跨页面保持时钟进度

有时,有必要将时钟状态保留的时间不仅限于当前页面。如果我们想在整个网站上设置10分钟的计时器,则我们不希望在用户转到其他页面时将其重置。

一种解决方案是将时钟的结束时间保存在cookie中。这样,导航到新页面不会将结束时间重置为现在的十分钟。

这是逻辑:

  1. 如果Cookie中记录了截止日期,请使用该截止日期。
  2. 如果不存在该cookie,则设置一个新的截止日期并将其存储在cookie中。

要实现这一点,请用deadline以下内容替换变量:

let deadline;

// if there's a cookie with the name myClock, use that value as the deadline
if(document.cookie && document.cookie.match('myClock')){
  // get deadline value from cookie
  deadline = document.cookie.match(/(^|;)myClock=([^;]+)/)[2];
} else {
  // otherwise, set a deadline 10 minutes from now and 
  // save it in a cookie with that name

  // create deadline 10 minutes from now
  const timeInMinutes = 10;
  const currentTime = Date.parse(new Date());
  deadline = new Date(currentTime + timeInMinutes*60*1000);

  // store deadline in cookie for future reference
  document.cookie = 'myClock=' + deadline + '; path=/; domain=.yourdomain.com';
}

这段代码利用了cookie和正则表达式,它们本身就是单独的主题。因此,我在这里不再赘述。需要注意的一件事是,您需要更改.yourdomain.com为实际域。

有关客户端事件的重要警告

JavaScript日期和时间是从用户计算机中获取的。这意味着用户可以通过更改计算机上的时间来影响JavaScript时钟。在大多数情况下,这无关紧要。但是,在某些超级敏感的情况下,有必要从服务器获取时间。可以使用一些PHP或Ajax来完成,这两者都超出了本教程的范围。

从服务器获取时间后,我们可以使用本教程中的相同技术来使用它。

加起来

阅读完本文中的示例之后,您现在知道如何仅用几行原始JavaScript代码创建自己的倒数计时器!我们已经研究了如何制作基本的倒数时钟并有效显示它。我们还介绍了添加一些有用的附加功能,包括计划,绝对时间和相对时间,以及使用Cookie保留页面和站点访问之间的状态。

完整代码

<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Countdown Clock</title>
<style type="text/css">
  body{
    text-align: center;
    background: #00ECB9;
  font-family: sans-serif;
  font-weight: 100;
}

h1{
  color: #396;
  font-weight: 100;
  font-size: 40px;
  margin: 40px 0px 20px;
}

#clockdiv{
    font-family: sans-serif;
    color: #fff;
    display: inline-block;
    font-weight: 100;
    text-align: center;
    font-size: 30px;
}

#clockdiv > div{
    padding: 10px;
    border-radius: 3px;
    background: #00BF96;
    display: inline-block;
}

#clockdiv div > span{
    padding: 15px;
    border-radius: 3px;
    background: #00816A;
    display: inline-block;
}

.smalltext{
    padding-top: 5px;
    font-size: 16px;
}
  </style>
</head>
<body>
    <h1>Countdown Clock</h1>
<div id="clockdiv">
  <div>
    <span class="days"></span>
    <div class="smalltext">Days</div>
  </div>
  <div>
    <span class="hours"></span>
    <div class="smalltext">Hours</div>
  </div>
  <div>
    <span class="minutes"></span>
    <div class="smalltext">Minutes</div>
  </div>
  <div>
    <span class="seconds"></span>
    <div class="smalltext">Seconds</div>
  </div>
</div>
<script type="text/javascript">
  function getTimeRemaining(endtime) {
  const total = Date.parse(endtime) - Date.parse(new Date());
  const seconds = Math.floor((total / 1000) % 60);
  const minutes = Math.floor((total / 1000 / 60) % 60);
  const hours = Math.floor((total / (1000 * 60 * 60)) % 24);
  const days = Math.floor(total / (1000 * 60 * 60 * 24));
  
  return {
    total,
    days,
    hours,
    minutes,
    seconds
  };
}

function initializeClock(id, endtime) {
  const clock = document.getElementById(id);
  const daysSpan = clock.querySelector('.days');
  const hoursSpan = clock.querySelector('.hours');
  const minutesSpan = clock.querySelector('.minutes');
  const secondsSpan = clock.querySelector('.seconds');

  function updateClock() {
    const t = getTimeRemaining(endtime);

    daysSpan.innerHTML = t.days;
    hoursSpan.innerHTML = ('0' + t.hours).slice(-2);
    minutesSpan.innerHTML = ('0' + t.minutes).slice(-2);
    secondsSpan.innerHTML = ('0' + t.seconds).slice(-2);

    if (t.total <= 0) {
      clearInterval(timeinterval);
    }
  }

  updateClock();
  const timeinterval = setInterval(updateClock, 1000);
}

const deadline = new Date(Date.parse(new Date()) + 15 * 24 * 60 * 60 * 1000);
initializeClock('clockdiv', deadline);
</script>
</body>
</html>

推荐JavaScript经典实例学习资料文章

《图文细说JavaScript 的运行机制》

节课让我们来一起做一个常见的网页效果——无缝滚动。

在制作无缝滚动前,我们需要解决的最基础的问题是——要如何让一个页面上的物体动起来?JS有很多复杂的运动,我们今天要做的是通过我们前面所学的基础知识来制作一些运动效果。

实际上,让一个元素动起来,我们目前能想到的最简单的方法就是修改一个元素的位置,在JS里我们通过定时器让元素定位的值(例如)不断变化,这样就实现了运动的效果。

在这里,我们先介绍一个属性:offsetLeft,用于获取元素的左边值(返回类型为数值型):

<html>
<head>
 <meta charset="utf-8" />
 <title>无标题文档</title>
 <style>
 #div1 {width:200px; height:200px; background:red; position:absolute; left:200px; top:150px; margin:50px;}
 </style>
</head>
<body>
 <div id="div1" onclick="alert(this.offsetLeft);">
 </div> 
</body>
</html>

结果如下:

offsetLeft的最大优点在于可以综合考虑所有影响物体位置的因素,在这个例子里如果我们仅仅只取元素的left属性那么margin对元素位置的影响将被忽略掉。当然,相对的,也有offsetTop属性用于获取元素的顶边值,以及offsetWidth和offsetHeight获取元素的宽度和高度。

现在我们来使用定时器和offsetLeft来做一个物体的基础运动:

<html>
 <head> 
 <meta charset="utf-8" /> 
 <title>无标题文档</title> 
 <style>
#div1 {width:200px; height:200px; background:red; position:absolute; left:0; top:50px;}
</style> 
 <script>
 setInterval(function (){
 var oDiv=document.getElementById('div1');
 
 oDiv.style.left=oDiv.offsetLeft+10+'px';
 }, 30);
</script> 
 </head> 
 <body> 
 <div id="div1"> 
 </div> 
 </body>
</html>

计时器每运行一次,oDiv的left属性就会增加10,因此在计时器的作用下oDiv就运动了起来。效果如下:

现在,我们就可以着手开始制作我们的无缝滚动了。

首先,我们需要准备几张大小相同的图片,并用ul列表的形式放入html中。为了实现我们的滚动效果,我们将ul放在一个div,并将该div的position属性设置为relative,将ul的position属性设置为absolute,这样我们在制作运动效果时移动ul就可以了。

但我们思考一下,如果只是这么制作的话,仅仅只是实现了图片的移动,并没有做到无缝衔接,因此我们需要将布局进行修改:

如上图所示,实际上我们是将两份相同的图片组合拼接到了一起这样当图片移动,第一张图片在左侧消失时,又会在右侧出现。

这样离我们想实现的效果就很接近了。但试想一下,当两组图片全部滚动完毕后,依然没有后续内容出现,因此这里我们需要使用一个小小的障眼法:因为我们需要显示的图片只有四张,所以当第一组图片全部消失,第二组图片全部出现的时候(也就是滚动到一半的时候),其效果和页面刚刷新时是一致的,所以我们考虑当图片滚动到这个地方的时候,直接回到拉回到开头,这样就可以达到无缝滚动的效果了。 完整代码如下:

<html>
 <head> 
 <meta charset="utf-8" /> 
 <title>无标题文档</title> 
 <style>
 * {margin:0; padding:0;}
 #div1 {width:712px; height:108px; margin:100px auto; position:relative; background:red; overflow:hidden;}
 #div1 ul {position:absolute; left:0; top:0;}
 #div1 ul li {float:left; width:178px; height:108px; list-style:none;}
 </style> 
 <script>
 window.onload=function ()
 {
 var oDiv=document.getElementById('div1');
 var oUl=oDiv.getElementsByTagName('ul')[0];
 var aLi=oUl.getElementsByTagName('li');
 
 oUl.innerHTML=oUl.innerHTML+oUl.innerHTML;
 oUl.style.width=aLi[0].offsetWidth*aLi.length+'px';
 
 setInterval(function (){
 if(oUl.offsetLeft<-oUl.offsetWidth/2)
 {
 oUl.style.left='0';
 }
 oUl.style.left=oUl.offsetLeft-2+'px';
 }, 30);
 };
 </script> 
 </head> 
 <body> 
 <div id="div1"> 
 <ul> 
 <li><img src="img2/1.jpg" /></li> 
 <li><img src="img2/2.jpg" /></li> 
 <li><img src="img2/3.jpg" /></li> 
 <li><img src="img2/4.jpg" /></li> 
 </ul> 
 </div> 
 </body>
</html>

现在我们为它增加一个效果:不仅可以向左滚动,也可以向右滚动。需要修改的地方有两个:首先是每次定时器启动的时候将oUl的left值由-2变为+2,其次需要进行一个判断:当ul的left值已经>0的时候,同样将其拉回去。

<html>
 <head> 
 <meta charset="utf-8" /> 
 <title>无标题文档</title> 
 <style>
 * {margin:0; padding:0;}
 #div1 {width:712px; height:108px; margin:100px auto; position:relative; background:red; overflow:hidden;}
 #div1 ul {position:absolute; left:0; top:0;}
 #div1 ul li {float:left; width:178px; height:108px; list-style:none;}
 </style> 
 <script>
 window.onload=function ()
 {
 var oDiv=document.getElementById('div1');
 var oUl=oDiv.getElementsByTagName('ul')[0];
 var aLi=oUl.getElementsByTagName('li');
 
 oUl.innerHTML=oUl.innerHTML+oUl.innerHTML;
 oUl.style.width=aLi[0].offsetWidth*aLi.length+'px';
 
 setInterval(function (){
 if(oUl.offsetLeft<-oUl.offsetWidth/2)
 {
 oUl.style.left='0';
 }
 if(oUl.offsetLeft>0)
 {
 oUl.style.left=-oUl.offsetWidth/2+'px';
 }
 oUl.style.left=oUl.offsetLeft+2+'px';
 }, 30);
 };
 </script> 
 </head> 
 <body> 
 <div id="div1"> 
 <ul> 
 <li><img src="img2/1.jpg" /></li> 
 <li><img src="img2/2.jpg" /></li> 
 <li><img src="img2/3.jpg" /></li> 
 <li><img src="img2/4.jpg" /></li> 
 </ul> 
 </div> 
 </body>
</html>

效果如下:

接下来我们再给这个程序增加一个功能:鼠标移入时暂停,鼠标移出时停止。远离很简单,使用onmouseover事件和onmouseout事件与定时器的开启与停止搭配就可以了,不过这里为了让代码更加简洁,我们使用一个move函数取代之前写在定时器里的匿名函数。

window.onload=function ()
{
	var oDiv=document.getElementById('div1');
	var oUl=oDiv.getElementsByTagName('ul')[0];
	var aLi=oUl.getElementsByTagName('li');

	oUl.innerHTML=oUl.innerHTML+oUl.innerHTML;
	oUl.style.width=aLi[0].offsetWidth*aLi.length+'px';

	function move(){
		if(oUl.offsetLeft<-oUl.offsetWidth/2)
		{
			oUl.style.left='0';
		}
		if(oUl.offsetLeft>0)
		{
			oUl.style.left=-oUl.offsetWidth/2+'px';
		}
		oUl.style.left=oUl.offsetLeft+2+'px';
	}
	var timer=setInterval(move, 30);

	oDiv.onmouseover=function ()
	{
		clearInterval(timer);
	};

	oDiv.onmouseout=function ()
	{
		timer=setInterval(move, 30);
	};
};

最后,我们还想通过按钮来控制图片的运动方向。向左和向右运动的程序我们都已经写好,因此我们只需要将两端代码合并简化即可。我们用一个变量speed来代替之前的+2/-2,根据点击不同的按钮给speed赋不同值,这样不仅可以改变运动的方向,还可以改变运动的速度。

1 月 18 日凌晨,Google 正式发布 Chrome 87,作为计划中 2020 最后的一次更新,Google 不仅在这个版本中为我们带来了一些实用的功能改进,此前一直在测试的性能提升和能耗优化本次也正式实装。

因此 Chrome 87 也被认为是近年来 Chrome 在性能表现上最大的一次改进,一起来看看。

又快又省电,标签页资源调度更聪明

关键更新点:

  • 更新后即默认开启
  • 后台标签页面功耗大幅降低
  • 多任务时浏览器整体资源调度更智能
  • Android 版页面导航加载速度更快

本次正式版更新带来的最大更新是针对后台标签页的性能消耗限制。

在我们使用浏览器的过程中,大部分网页几乎都会采用一种名为 JavaScript 计时器的东西来定时执行代码任务,以此实现各种各样的网页功能。Google 早前被吐槽过于耗电之后痛定思痛,一番调查研究发现那些被用户放在后台的标签页面的 JavaScript 计时器依然会占用了大量的系统资源来保持工作。解决方法应运而生。

在 Chrome 87 正式版之前,这项名为 Throttle Javascript timers in background 的技术(chrome://flags/#intensive-wake-up-throttling)已经在 Canary、Dev 和 Beta 版本 Chrome 中测试已久,通过将后台标签页面 JaveScript 计时器唤醒频率降低到 1 分钟一次的方法来减少后台标签页所需要的系统资源,但同时又能保证一些需要后台运行的任务(比如媒体播放)正常工作。

对应的功能标签

根据 Google 自己做的测试,这项改进最多可以降低 5 倍 CPU 使用率,带来将近 1.25 小时的额外使用时间,对于笔记本这类便携设备来说是绝对的利好。

这种优化后台页面保证前台工作的思路同样也被应用到了浏览器本身:针对 Windows 版本,Chrome 87 也正式引入了 Occlusion Tracking 技术,它可以帮助 Chrome 判断当前网页标签和浏览器窗口是否为用户焦点,进而优化浏览器的整体资源调度,根据 Google 的说法,这项改进能够在使用更少内存的前提下提高 25% 的浏览器启动速度和 7% 的标签页加载速度。

对应的功能标签

最后,针对 Android 版本的性能调整主要针对网页导航操作(前进和后退)。Google 表示大家在浏览网页时五分之一的操作都集中在前进、后退这两件事情上,本次加入的后退/前进缓存功能则可以让相关操作后的网页内容加载速度提高近 20%,未来这项改进还会提高到 50%,达到近乎即时加载页面一样的效果。

开启后与开启前的后退效果

如果你对相关的性能改进和技术细节感兴趣,不妨移步至 Chromium Blog 的 这篇文章 了解更多。

标签页功能再进步,现在还能搜索了

关键更新点:

  • Chrome OS 先行,桌面端后续推送
  • 多标签浏览更高效

在之前的几个版本更新中,Chrome 加入了固定标签页和分组标签页功能,你可以将经常打开的网页固定到 Chrome 的标签页栏的最左边,而针对多个标签页,还可以通过分组和颜色标记的方式进行归类。

在断了部分标签页管理扩展后路之后,本次 Chrome 87 继续发力,又宣布加入一项新的特性:标签页搜索。简而言之,当你打开多个标签页又希望可以快速定位到某一个标签页,直接点击浏览器顶部标题栏最右侧的箭头按钮就能呼出标签页搜索面板。对于日常工作中需要保持多个标签页面打开的用户来说,这个功能配合上面提到的后台标签页资源限制应该可以做到又高效又省电。

遗憾的是目前这项功能在桌面端尚未正式上线,Google 表示它将首先登录 Chrome OS,不久后将向桌面平台版本进行推送。

具有复合功能的地址栏来了

关键更新点:

  • 陆续推送中,可手动开启
  • 直接通过地址栏跳转至常用浏览器设置(例如「清除历史记录」)
  • 支持中文

地址栏可以玩的花样也非常多,尤其是 Chrome 的地址栏,既可以输入网址也可以执行搜索操作,而现在 Chrome 87 又有新的功能特性:多功能框。

这个多功能可以看作是一些终端命令的 Chrome 功能设置专版,其作用就是打开一系列的 Chrome 内置的功能页面,而不用在不同的 Chrome 位置中反复点击,比如说,你希望删除历史记录,那么只需要在 Chrome 的地址栏键入:delete my history,然后就会打开对应的操作页面。

​值得一提的是,这个功能虽然有那么点「自然语义」的味道(只是打个比方二者并不沾边),但根据我们的实际测试是完全支持中文的。如果你在更新后这个功能无法使用,可以手动开启 Omnibox suggestion button row (chrome://flags/#omnibox-suggestion-button-row) 和 Omnibox Pedal suggestions (chrome://flags/#omnibox-pedal-suggestions) 这两个功能标签来进行启用。

中文支持也是没问题的

目前 Google 也给出了部分已经 可以执行的命令,并表示未来这项功能中可以执行的命令还会继续增加。

新标签页面内容更丰富了

关键更新点:

  • 尚未实装,需要个人浏览数据积累
  • 从新标签页面直接进行话题页面回溯

网上搜索过的信息过一段时间后突然想再回顾或继续研究,除了翻找历史记录之外还有什么新的办法?Chrome 87 利用起了新标签页,通过新标签页面下方的卡片模组帮你「温故知新」。

根据 Google 的介绍,这些卡片会根据我们的浏览历史集中展示不同话题的历史页面和相关页面,主要应用场景包括礼物挑选、购物、菜谱等等,所以我们暂时应该不用担心什么奇奇怪怪的「精彩集锦」内容出现新标签页面……

使用功能标签中的模拟数据生成的卡片效果

PDF 阅读器迎头赶上

关键更新点:

  • 陆续推送,可手动开启
  • PDF 查看器功能更完善
  • 支持查看标注,但不支持编辑标注

一直以来我们都认为 Chrome 的 PDF 阅读器相比 Edge 而言过于简陋,但 Chrome 87 终于迎头赶上,带来了不少针对 PDF 阅读器的改进。

Chrome 87 中 PDF 阅读器最为直观的变化在于导航栏的加入:在浏览页面左侧新增的导航栏可以显示所有页面的缩略图预览,如果 PDF 文件本身有目录的话还可以切换到目录视图跳转查看,便利性和实用性都提升了不少。。​

另外,工具栏中还加入了缩放控件和新的视图控件,如果你的屏幕够大,完全可以设置并排查看两页 PDF 页面。唯一令人遗憾的是虽然该版本支持了 PDF 标注的查看,但依然不支持编辑。

目前新版 PDF 阅读器已经开始推送,更新后如果你看不到新界面,也可以前往功能标签页面中搜索​ PDF Viewer Update (chrome://flags/#pdf-viewer-updat) 手动开启。

最佳 Apple 开发者 & 一些技术细节

关键更新点:

  • 针对 macOS Big Sur 和 Apple M1 进行适配
  • 更完善的网络摄像头控制功能,网页版会议工具会用得上
  • Chrome OS 的新壁纸真好看

Apple 在近期正式发布了 macOS Big Sur 桌面操作系统,UI 大改的同时也带来新的应用图标适配问题,而本次 Chrome 87 的正式推出也加入了适用于新系统的图标,相比以往的图标加入了更多的留白。开发团队表示还在进一步优化从而让视觉上看更加统一。

​另外针对刚刚发布的基于 ARM 架构 Apple M1 处理器的 Mac 硬件,本次 Chrome 87 正式版推出了基于两种架构的版本:Intel 架构版本以及 Apple M1 架构版本,后者采用了原生编译效率会更高也更适合新硬件。

最后,Chrome 87 也带来了一系列针对网页功能的技术细节更新,比如现在我们可以直接在 Chrome 网页中控制带有缩放、倾斜、平移等功能的摄像头;另外,针对 Chrome OS 本次更新还加入了新的壁纸。

以上便是本次 Chrome 87 稳定版更新的全部内容。Chrome 的性能和功耗改进在你的设备上表现怎么样?欢迎在评论区留言分享。