chenxiaochun / blog

🖋️ChenXiaoChun's blog
181 stars 15 forks source link

Chrome69 新特性介绍 #63

Open chenxiaochun opened 6 years ago

chenxiaochun commented 6 years ago

image

Chrome69 刚刚发布,翻了一下它的官方文档。所以,这篇文章就是向大家介绍一下它新支持的一些有趣功能特性。

写这篇文章的目的也仅仅是对新技术的一种了解和探索,各位也不要看完之后,就急着应用到自己的项目中去;或者看完之后,就开始纠结各种浏览器的兼容性问题。我个人认为,在项目中使用技术要保守一点,尽量选择那些比较熟悉的技术方案,但是,学习新技术还是应该尽量激进。

CSS Scroll Snap

CSS Scroll Snap 用来创建平滑的滚动体验,并且还可以控制元素每次滚动操作之后的停止位置。这个新特性非常合适用在图片轮播和滚动分页的操作效果。

拿图片轮播举例,我需要给滚动的容器添加scroll-snap-type: x mandatory;mandatory的意思就是“强制的”,也就是强制里面的元素以水平方向滚动。然后给里面滚动的每一张图片添加scroll-snap-align: center;。然后当用户滚动轮播的时候,每一张图片就能恰好顺滑的滚动到完美的位置上。

#gallery {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
  display: flex;
}

#gallery img {
   scroll-snap-align: center;
}

即使每一张图片的尺寸都不一样或者超出了滚动容器的大小,这个功能依然能工作的很好。

查看示例:https://codepen.io/sjzcxc/pen/PdKrzv?editors=1100
查看 google 官方提供的示例:https://snap.glitch.me/carousel.html
源代码:https://glitch.com/edit/#!/snap?path=carousel.html:186:0

手机“刘海儿”区域显示

现在越来越多的手机都有那个“刘海儿”。于是浏览器添加了一些额外的外边距以处理这个区域。

默认显示效果:

viewport-fit=cover告诉浏览器展开预留的那个“刘海儿”区域。但是你会发现有些内容会被遮挡,并且下面的导航条也会变得非常难用。

<meta name='viewport' content='initial-scale=1, viewport-fit=cover'>

那怎么才能在加上上面的元标签之后,也能防止内容不被遮挡呢?

为了实现这个效果,需要使用 css 函数:env(),以及四个内置的环境变量:

safe-area-inset-left
safe-area-inset-right
safe-area-inset-top
safe-area-inset-bottom
.post {
    padding: 12px;
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
}

web locks api

可以用这个 api 以异步的方式获得一个锁,然后直到你的任务完成之后,再去释放它。当其它任务占用这把锁的时候,获得这把锁的其它任务,只能是等待上一个任务释放这把锁之后,再能继续执行。这个特性非常适合用于管理公共资源的使用。

注意:这个 api 只能在 https 协议中才能获取到。

例如,当一个应用在多个 tab 页运行的时候,可以用来确保当前只有一个 tab 页在获取数据.

navigator.locks.request("network_sync_lock", async lock=>{
  await new Promise(resolve => {
    setTimeout(() =>{
      console.log('我正在获取一个数据!')
      resolve();
    }, 3000);  
  })
})

navigator.locks.request('network_sync_lock', async lock => {
   await new Promise(resolve => {
       setTimeout(() => {
           console.log('等第一个任务完成之后,我才能继续!');
           resolve();
       }, 3000)
   })
});

第一个 tab 页获得一把锁之后,开始异步的请求数据。如果另一个 tab 页也想获得相同的锁,它就必须排队。当第一个任务把锁释放之后,后面排队的任务才会被授权使用锁,并被执行。查看示例:https://codepen.io/sjzcxc/pen/GXMJzX?editors=1010

可以给request传递一个对象参数,用来控制锁的执行状态。

navigator.locks.request("network_sync_lock",{mode: 'shared'}, async lock=>{
  await new Promise(resolve => {
    setTimeout(() =>{
      console.log('我正在获取一个数据!')
      resolve();
    }, 3000);  
  })
})

navigator.locks.request('network_sync_lock',{mode: 'exclusive'}, async lock => {
   await new Promise(resolve => {
       setTimeout(() => {
           console.log('等第一个任务完成之后,我才能继续!');
           resolve();
       }, 3000)
   })
});

实验发现,只要第一个任务把锁置为shared的状态,那么第二个任务是否需要等待上一个任务释放锁,完全是由自己决定的。

var controller = new AbortController();
var signal = controller.signal;

navigator.locks.request("network_sync_lock",{signal: signal}, async lock=>{
  await new Promise(resolve => {
    setTimeout(() =>{
      console.log('执行第一个任务!')
      resolve();
    }, 3000);  
  })
})

navigator.locks.request('network_sync_lock', async lock => {
   await new Promise(resolve => {
       setTimeout(() => {
           console.log('执行第二个任务!');
           resolve();
       }, 3000)
   })
});

signal.onabort = () => {
  if(signal.aborted){
    console.log('任务被中止!');
  }
}

controller.abort();

如下示例所示,我们给第二个任务设置了ifAvailable: true,经过 3 秒钟之后,会同时看到两条 log 信息。

navigator.locks.request("network_sync_lock", async lock => {
  await new Promise(resolve => {
    setTimeout(() => {
      console.log('执行第一个任务!')
      resolve();
    }, 3000);
  })
})

navigator.locks.request('network_sync_lock', { ifAvailable: true }, async lock => {
  await new Promise(resolve => {
    setTimeout(() => {
      console.log('执行第二个任务!');
      resolve();
    }, 3000)
  })
});

圆锥渐变

查看示例:conic-gradient。另外,之前写过一篇关于线性渐变和放射性渐变的文章,可以点击链接查看。

属性开关切换

<input value="text">
<button>toggleAttribute</button>
var button = document.querySelector("button"); 
var input = document.querySelector("input"); 

button.addEventListener("click", function(){
  input.toggleAttribute("readonly");
});

toggleAttribute的第二个参数是一个布尔值。设置为true时表示给当前元素添加属性,为false时表示删除属性。

新增两个 array 方法

const array = [1, [2, [3]]];
array.flat();
// → [1, 2, [3]]
[2, 3, 4].flatMap((x) => [x, x * 2]);
// → [2, 4, 3, 6, 4, 8]

OffscreenCanvas

以前在 worker 中是无法使用 canvas 的,因为无法在 worker 中操作 DOM 元素。现在OffscreenCanvas的出现,就是为了实现无需依赖于 DOM 操作的在 worker 中绘制 canvas。

大家都知道,浏览器的执行时是单线程的,如果一个任务耗时过长,就会使页面出现卡顿,影响用户体验。因此将那些复杂的 canvas 绘制工作从主线程移到一个 worker 里面,不影响主线程的程序运行,可以极大提高执行效率和用户体验。

worker.js:

function getGradientColor(percent) {
  const canvas = new OffscreenCanvas(100, 1);
  const ctx = canvas.getContext("2d");
  const gradient = ctx.createLinearGradient(0, 0, canvas.width, 0);
  gradient.addColorStop(0, "red");
  gradient.addColorStop(1, "blue");
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, ctx.canvas.width, 1);
  const imgd = ctx.getImageData(0, 0, ctx.canvas.width, 1);
  const colors = imgd.data.slice(percent * 4, percent * 4 + 4);
  return `rgba(${colors[0]}, ${colors[1]}, ${colors[2]}, ${colors[3]})`;
}

postMessage(getGradientColor(40));

主文件:

<body>
  <script>
    var worker = new Worker('worker.js');

    worker.onmessage = event => {
      console.log(event.data);
    }
  </script>
</body>

关闭地址栏默认隐藏 www 字符

你在地址栏中输入www.a.www.b.com回车之后,它显示的是a.b.com。这明显是有问题的,例如钓鱼网站就可能利用这个漏洞欺骗用户。今天测试发现Chrome 已经默认修复了这个问题,所以,大家只要知道有这么个开关就可以了。

chrome://flags#omnibox-ui-hide-steady-state-url-scheme-and-subdomains

相关资源链接