MoreRSS

site iconZhangXinXu | 张鑫旭修改

出版《CSS选择器世界》,喜欢钓鱼、写作。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

ZhangXinXu | 张鑫旭的 RSS 预览

JS原生的深拷贝API structuredClone函数简介

2025-01-22 23:22:42

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11509
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

深拷贝示意图

一、开门即见山

目前,Web浏览器提供了原生的Object对象深度克隆方法structuredClone()函数。

使用方法很简单,JS代码如下所示:

// 创建一个具有值和循环引用的对象
const original = { name: "zhangxinxu" };
original.itself = original;

// 克隆
const clone = structuredClone(original);

// 两者对象是不相等的
console.assert(clone !== original);
// 两者的值是相等的
console.assert(clone.name === "zhangxinxu"); 
// 并且保留了循环引用
console.assert(clone.itself === clone);

语法

语法如下:

structuredClone(value, options)

其中:

value
需要被深拷贝的值
options
可选参数,支持一个名为transfer的参数值,其值为一组可转移的对象,它们将被移动而不是克隆到返回的对象中。

关于transfer

可选参数transfer多用在一些大数据传输中(转移相比克隆可以节约内存开销),这里有个案例供大家参考:

const original = new Uint8Array(1024);
const clone = structuredClone(original);
console.log(original.byteLength); // 1024
console.log(clone.byteLength); // 1024

original[0] = 1;
console.log(clone[0]); // 0

// 转移Uint8Array会引发异常,因为它不是可转移对象
// const transferred = structuredClone(original, {transfer: [original]});

// 我们可以转移Uint8Array.buffer
const transferred = structuredClone(original, { transfer: [original.buffer] });
console.log(transferred.byteLength); // 1024
console.log(transferred[0]); // 1

// Uint8Array.buffer转移后就无法使用了
console.log(original.byteLength); // 0

二、兼容性与Polyfill方法

window全局的structuredClone()方法兼容性还是不错的,目前所有常见浏览器都已经支持了,如下截图所示:

structuredClone兼容性截图

考虑到总会有一些用户手机舍不得或者忘记或者懒得升级,面对偏外部用户的产品,建议还是同时引入Polyfill。

structuredClone Polyfill

JS不同于CSS,要是JS某个方法不支持,然后你去运行他,很可能会导致整个页面白屏,这是Vue和React项目中是常有的事情(也包括各类小程序)。

所以,我们需要引入Polyfill,可以试试这个项目:https://github.com/ungap/structured-clone

使用示意:

import structuredClone from '@ungap/structured-clone';
const cloned = structuredClone({any: 'serializable'});

还是很easy的啦。

其实,上面的Polyfill还有不少其他的功能,就等大家自行去探索啦。

三、JSON等方法有什么问题

之前我深度拷贝一个Object对象会使用JSON.parse(JSON.stringify(obj))来实现,虽然可以满足绝大多数的场景,但有时候会出问题。

例如,当对象的属性值是Date()对象的时候,案例示意:

const originObj = {
  name: "zhangxinxu",
  date: new Date()
};

const cloneObj = JSON.parse(JSON.stringify(originObj));

// 结果是 'object'
console.log(typeof originObj.date);
// 结果是 'string'
console.log(typeof cloneObj.date);

可以看到,本应实时显示当下时间的属性值变成了固定死的字符串值(也可以看截图运行结果),这并不是我们希望看到的。

JSON方法变成字符串示意

而浏览器提供的structuredClone()方法则没有这个问题,使用示意:

const originObj = {
  name: "zhangxinxu",
  date: new Date()
};

const cloneObj = structuredClone(originObj);

// 结果是 'object'
console.log(typeof originObj.date);
// 结果是 'object'
console.log(typeof cloneObj.date);

Date复制示意

当然,还包括很多其他类型的对象也是如此,包括:Date, Set, Map, Error, RegExp, ArrayBuffer, Blob, File, ImageData等。

点点点或者Object方法的问题

如果需要复制的对象层级简单,那么我们使用点点点,或者Object.assign()Object.create()方法是没问题的,例如:

const originObj = {
  name: "zhangxinxu"
};
// ok没问题
const cloneObj = { ... originObj }
// ok没问题
const cloneObj = Object.assign({}, originObj)
// ok没问题
const cloneObj = Object.create(originObj)

可如果对象的属性值也是个对象,那么上面的方法就有问题,例如:

const originObj = {
  name: "zhangxinxu",
  books: ['CSS世界']
};
// ok没问题
const cloneObj = { ... originObj }
cloneObj.books.push('HTML并不简单');
// 结果原对象的books也一起变化了
console.log(originObj.books);

控制台运行结果不会骗人:

嵌套结构有问题示意

四、structuredClone不能的局限

当然,structuredClone方法也不是万能的,例如DOM对象是不能参与复制的。

// 会报错
structuredClone({ el: document.body })

DOM对象不能复制

函数也不能复制:

// 会报错
structuredClone({ fn: () => { } })

属性描述符、setter和getter

标题这些类型的东西也不会被深度复制,比方说像getter,克隆的会是其值,而不是getter函数本身。

structuredClone({ get foo() { return 'bar' } })
// 结果: { foo: 'bar' }

对象原型

原型链也是不会被复制的,因此,如果克隆MyClass的实例,克隆的对象将不再是该类的实例(但该类的所有有效属性都将被克隆)

class MyClass { 
  foo = 'bar' 
  myMethod() { /* ... */ }
}
const myClass = new MyClass()

const cloned = structuredClone(myClass)
// 结果 { foo: 'bar' }

cloned instanceof myClass // false

五、蛇年快乐

好,本文的内容就这些,应该是春节前的最后一篇文章了,本来以为内容不多,但写着写着,发现里面可讲的东西还不少。

我明天就请假回老家了,算算,可以连休12天,还真是富裕的假期。

就是过年很多鱼塘不开门,想要出去钓鱼,还有些困难。

唉,再说吧。

话不多说,祝大家蛇年快乐,万事如意。

在家要是无聊,可以看看技术书籍

HTML并不简单书封

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11509

(本篇完)

如何手搓SVG半圆弧,手把手教程

2025-01-14 23:10:19

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11545
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

手搓SVG半圆弧 封面占位图

一、还是先说说历史

SVG的曲线绘制在10多年前,我其实有撰文介绍过,也算是当时的热门文章了,见:“深度掌握SVG路径path的贝塞尔曲线指令”。

其中就有提到圆弧指令的绘制语法,不过这篇文章主要是讲贝塞尔曲线的,因此,圆弧指令并未多做介绍。

然后,最近遇到了一个需求,如下图所示,实现下图所示的渲染效果:

目标实现效果

由于其中有个动态尺寸的圆环,用来表示走过的百分比进度,因此,这里使用静态的图片是不合适的,而那个动态圆环本身就是需要使用SVG实现的(一是因为端点是圆角,二是因为有路径动画),既然都A了,那B岂不就可以顺便也实现下。

因此,最终决定,总计4个圆环全部都手搓。

而手搓SVG圆环的指令是M…A…组合,具体语法如下:

二、搞懂M…A圆弧指令

圆弧指令其实挺简单的。

如下所示:

M x1 y1 A rx ry x-axis-rotation large-arc-flag sweep-flag x2 y2

其中:

  • x1 y1是圆弧的起点坐标
  • x2 y2是圆弧的终点坐标
  • rx ry是圆弧的x半径和y半径,正圆的话这两个值是一样的,椭圆会不一样

再然后:

  • x-axis-rotation是x轴旋转值,这个值平常我们用不到,一般都是0
  • large-arc-flag表示是否是大弧。只这样的,再一个圆形上随便取两个点,是不是会有两段弧线?如下图所示:

    两段圆弧示意

    large-arc-flag的值为0表示使用的是小弧(上图红色实线),为1则是大弧(蓝色虚线)。

  • sweep-flag表示是否是顺时针,值为1则是顺时针,为0则表示逆时针。

而效果图里面的每段弧线都不超过1/2个圆,因此都是小圆弧,故而,我们需要确定的,其实就是起点和终点而已。

假设SVG的半径是40,则圆弧路径就是:

M x1 y1 A 40 40 0 0 1 x2 y2

具体转换可参见下面的GIF图片:

指令变化GIF示意

因此,弧线的path路径指令看似复杂,实际在开发过程中,只需要确定起点和终点坐标就可以了。

三、数学与几何坐标计算

坐标的计算就要用到高中知识了,高中还是初中的?记不清了,什么时候学的不重要,反正就是正弦余弦计算。

我还在小本本上画了画:

角度计算图示

然后就得到了如下所示的坐标计算方法:

/* angle: 数值,逆时针旋转的角度 */
const pathTogether = function (angle) {
  const r = 40;
  // 总角度
  const totalAngle = 360;

  // x y 是圆弧的点坐标
  let x = 0; 
  let y = 0;

  // 坐标计算
  if (angle 

只要给定角度大小(逆时针角度),就能返回对应的准确坐标点的。

然后就是套入就可以了,最后得到了如下的SVG路径:

<svg width="100" height="100" viewBox="0 0 100 100">
  <path d="M58.32 10.87A40 40 0 0 1 83.16 27.63" fill="none" stroke="#CDB9FF" stroke-width="16" stroke-linecap="round"></path>
  <path d="M89.39 43.05A40 40 0 0 1 35.02 87.09" fill="none" stroke="#B293FF" stroke-width="16" stroke-linecap="round"></path>
  <path d="M21.23 77.79A40 40 0 0 1 41.68 10.87" fill="none" stroke="#7D49FF" stroke-width="16" stroke-linecap="round"></path>
</svg>

实时渲染效果如下所示(非正版文章会看不到):

是不是发现还挺简单的。

四、文字环绕效果

至于图中的文字环绕效果,这个SVG自带此能力,使用<textPath>元素就可以了,将其href属性值锚定制定的路径元素即可。

这个之前已经撰文介绍过了,参见:“文字沿着不规则路径排版布局的实现

回到本例,使用代码如下所示:

<svg width="100" height="100" viewBox="0 0 100 100">
  <path id="pathCurrent" d="M21.23 77.79A44 44 0 0 1 41.68 10.87" fill="none" stroke="red"></path>
  <text font-size="9">
    <textPath href="#pathCurrent">
      我们一起走过的日子
    </textPath>
  </text>
</svg>

SVG真实代码的解析结果就是下面这图这样的(实际开发,红色路径线条是不显示出来的):

我们一起走过的日子

至于2022~2024文字的环绕对齐,也是类似的,就是需要一些偏移,可以使用transform属性,例如:

<text font-size="7" x="0" fill="#2B0095" transform="translate(-3, 2)" stroke="#CDB9FF" stroke-width="2" paint-order="stroke">
  <textPath href="#path2022">
    2022
  </textPath>
</text>

完整的效果,如下图所示:

我们一起走过的日子202220232024

五、结束语

一点工作心得总结,以后遇到类似的需求,知道去哪里找,开发效率就高,顺便帮助遇到类似需求的小伙伴。

下面是闲聊扯淡时间。

小朋友的期末考试成绩出来了,怪怪,都已经四年级了。

本来指望着能够进入前三十就好了。

结果不知道怎么回事,奇了怪了,这次期末考试,按分数排名第6,总排名第16名,居然一下子进入前20了。

数学成绩上了4年,头一次考到A+。

难以理解,我的心情就像下图这样。

美女看手机

我靠,要是稳定这个水平,我要考虑初中学区房了。

💸💷💶💵💴💰

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11545

(本篇完)

Broadcast Channel API简介,可实现Web页面广播通信

2025-01-12 23:53:31

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11507
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

Broadcast-Channel封面图

一、之前postMessage的局限

在12年的时候,乖乖,12年啊,都十几年前了,我有写过关于postMessage的跨页面通信的文章,见这里

结果这么多年下来,在生产环境使用上述postMessage通信的机会屈指可数,这种跨页面通信平常的交互式页面是鲜有机会接触的。

然后,现在有多了个Broadcast Channel API,也是实现页面见通信的。

和十多年前的这个通信区别在于,这个是广播式的,而非点对点。

所谓广播通信,就是所有域名相同的页面,A发送消息,其他所有页面都能接收到,这在需要数据实时同步的场合非常有用。

二、Broadcast Channel使用挺简单的

Broadcast Channel API看起来复杂,实际使用简单地出乎意料,我想,最复杂的应该就是这个API的拼写了。

是这样的,所有需要通信的页面都new一个相同的广播通道,就像这里:

const bc = new BroadcastChannel('zhangxinxu');

然后一个页面发送,就像这样:

bc.postMessage('欢迎支持正版书籍');

然后其他页面就能接收到这个信息:

const bc = new BroadcastChannel('zhangxinxu');
bc.onmessage = function (event) {
    console.log(event.data);
    // 输出'欢迎支持正版书籍'
};

就这样结束了。

结束了,回家吧

三、演示案例

为了演示方便,我使用iframe将数个页面击中在了一起,左侧是主页面,右侧分别是iframe-a.html和iframe-b.html。

这三个页面都创建了一个同名的BroadcastChannel对象。

主页面发送,两个iframe内嵌页接受,结果,当我们点击按钮的时候,如下图所示:

点击演示页面按钮示意

右侧的iframe页面就接受到了发送的信息,如下截图所示:

页面输出结果示意

我们还可以修改输入框的内容,查看发送不同信息的结果,例如,我们厂最近热播的《大奉打更人》和《国色芳华》

自定义post数据结果示意

Demo访问

您可以狠狠地点击这里:Broadcast Channel API使用示意demo

四、兼容性和其他

目前广播通信API的兼容性还是很不错的,caniuse网站截图:

BroadcastChannel兼容性

BroadcastChannel不仅可以用在window上下文环境中,在Web Worker中也是可以自如使用的。

不仅可以是iframe间广播通信,各个浏览器选项卡之间通信也是可以的,这里我就不重复演示了,肯定是支持的。

通道名字获取与关闭

通道名字可以使用name属性值获取,例如:

console.log(bc.name);
// 输出结果是:zhangxinxu

如果想要关闭通道,可以使用close()方法。

bc.close();

通道一旦关闭,你再使用postMessage()发送数据就会报错,或者使用message事件接收数据也不会成功,反而会触发messageerror事件。

在上面的demo中,通信讯息的接受用的是onmessage方法,实际上,使用addEventListener去绑定事件也是可以的,例如:

bc.addEventListener("message", (event) => {
  console.log(event.data);
})

五、结语点点点

说啥结语,想不到啥,小朋友放寒假了,时间过得好快,要过年了,明年40了。

哦,对了,年终总结忘记写了。

年前抽时间写一下吧,好好想想怎么写。

行吧,就这些吧,表达欲不是年轻的时候了。

感谢阅读,尤其这么多年还在关注我的小伙伴们。

如果可以,希望可以顺手下,比心。

比心

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11507

(本篇完)

一个新的CSS媒体查询prefers-reduced-transparency

2025-01-02 23:46:13

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11505
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

media与用户体验

一、为故而知新

三年前,我有介绍过渐弱动画的媒体查询prefers-reduced-motion,参见文章“你不知道的CSS media查询与用户体验”的第5小节。

使用示意:

@media (prefers-reduced-motion: reduce) {
  /* ⽤户希望减弱动画 */
}

目前Chrome浏览器新支持了一个名为prefers-reduced-transparency的媒体查询,其设计初衷和使用背景与上面提到的prefers-reduced-motion类似。

是这样的:

  • 在设备层面,不透明界面会增加渲染绘制的开销,在移动设备上会加速电量的流失。
  • 在用户层面,对于少部分用户,不透明界面会导致头痛,或者因为各种类型的视力缺陷而造成视觉障碍。

此时,用户就会考虑关闭操作系统的半透明设置选项。

二、如何使用降低透明度

目前,Windows、macOS 和 iOS 都提供了系统偏好设置,可降低或移除界面的透明度。

例如,在我的Windows 10操作系统下,在显示设置里,就有这么个开关选项,如下截图所示:

启用半透明与否

prefers-reduced-transparency的媒体查询就是为这种场景设计的。

使用示意:

.overlay {
  --opacity: .5;

  background: rgba(0 0 0 / var(--opacity));

  @media (prefers-reduced-transparency: reduce) {
    --opacity: .95;
  }
}

不过实际开发并不需要我们去系统层面进行自定义设置,Chrome的开发者工具就提供了相关的选项。

操作路径如下截图所示,首先,开启Rendering选项卡面板,如果没有,参照下图示意打开:

Chrome开发者工具渲染选项卡

其中就有prefers-reduced-transparency:reduce的下拉选项,截图如下:

截图所示

此时,我们就可以针对性地进行用户体验方面的处理的。

三、使用案例

我们通过一个简单的案例,开看一下prefers-reduced-transparency:reduce的执行效果。

点击按钮,显示模态对话框(浏览器原生的能力),然后通过CSS代码以及媒体查询,控制模态背景的半透明度,相关的HTML和CSS代码如下所示:

<button 
  onClick="dialog.showModal();"
>点击我</button>

<dialog 
  id="dialog" 
  onclick="this.close()"
>我是模态框,看看背景的半透明是多少?</dialog>
dialog::backdrop {
  --opacity: .5;

  background: rgba(0 0 0 / var(--opacity));

  @media (prefers-reduced-transparency: reduce) {
    --opacity: .95;
  }
}

在默认情况下,我们点击按钮,模态框的背景半透明度,大致是下图这般模样:

默认模态背景透明度示意

黑色半透明背景后面的文字和图形可谓是清晰可见。

当我们,Chrome控制台Rendering选项卡开启prefers-reduced-transparency:reduce选项后,会发现,背景一下子变得好黑,比包拯还黑。

降低透明度之后的表现

这种渲染对于有视力障碍的人来说,就会舒服很多。

眼见为实,您可以狠狠地点击这里:CSS prefers-reduced-transparency与模态半透明颜色demo

四、兼容性、结语等

来看下此@media媒体查询语句的兼容性,如下图所示,可以看到Chrome 118开始支持,而Firefox(实验支持)和Safari还是红灿灿的一片。

prefers-reduced-transparency兼容性截图

所以,目前,上面的demo演示页面只能在Chrome,或者版本比较高的Android手机下查看才有效果。

手机查看的话,需要去手机的设置里,设置减少透明度这个选项。

  • In Windows 10/11: Settings > Personalization > Colors > Transparency effects.
  • In macOS: 系统设置 > 无障碍访问 > 显示 > 减少透明度
  • In iOS: 设置 > 无障碍访问 > 显示 & 文本尺寸 > 减少透明度

好吧,就这些,一个与用户体验密切相关的CSS新特性。

不过,按照以往的尿性开看,没几个前端会在真实项目中使用的,投入产出比太低,吃力不讨好。

所以,大家了解下就好了,万一以后有机会开发个很多人使用的UI组件,这个就有用处了,毕竟用的人多,价值就上来了。

感谢阅读,欢迎

😋😛😝😜

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11505

(本篇完)

HTML select下拉框支持hr元素啦

2024-12-29 22:25:59

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11503
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

人手 铅笔 绘制 html hr 占位他图

一、hr元素与下拉分隔线

在过去,<select>下拉元素的子元素,只能是<option><optgroup>(下拉选项分组)元素。

而现在,<select>又多支持了一个元素,为<hr>元素。

可以在下拉选项中创建分隔线。

例如:

<select is="ui-select">
  <option>选项1.1</option>
  <option>选项1.2</option>
  <hr>
  <option>选项2.1</option>
  <option>选项2.2</option>
</select>

实时渲染效果如下:

下图是我电脑上的截图效果:

分隔线效果

我试试看这个hr样式能不能自定义。

结果,和option元素一样,是无法自定义的,sad 😔。

二、一些细节知识

首先,hr元素可以不闭合。

其次,如果<select>元素需要设置<hr>分隔效果,那么祖先元素不能是<p>元素,因为可能会有渲染问题。

例如下面这样的HTML代码:

<p>
  <select is="ui-select">
    <option>选项1.1</option>
    <option>选项1.2</option>
    <hr>
    <option>选项2.1</option>
    <option>选项2.2</option>
  </select>
</p>

在Chrome 129下,<hr>元素会中断<select>元素,变成下图所示的效果:

渲染异常

不过Chrome在版本131之后修复了这个渲染bug,不过用户不一定实时升级Chrome浏览器,因此,还是避免p > hr的标签组合。

兼容性

最先开始支持的是Chrome浏览器,时间应该是去年年底,caniuse上的截图:

select hr 兼容性

Safari支持最晚,今年3月份才开始支持。

为什么都是棕黄色,而非绿色呢,是因为可访问性这块还没怎么支持。

二、LuLu UI中的支持

LuLu UI组件的设计理念是基于原生HTML构建,既然浏览器原生支持了下拉框中的hr元素,LuLu UI 也定然要跟随支持。

所以,昨天在家,抽空弄了下,已经发版了。

演示页面地址访问:https://l-ui.com/edge/apis.select.html

分隔线 LuLu UI中的支持

Nice!

三、越来越短了

15年前刚写博客那会儿,恨不得每篇文章万把字,现在,年纪上去了,更新也还更新,但是字数缩写得厉害。

精力没有以前那么旺盛了,创作欲也下来了。

瞧瞧本文,之前篇幅的1/10.

不过嘛,现在的年轻人都喜欢短平快,说不定这种短短的内容他们更喜欢。

好了,不唠叨了。

这周三元旦,吼吼,天气也不错,可以出远门钓个鱼。

桀桀桀。

桀桀桀

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11503

(本篇完)

如何使用JS获取系统内存、CPU/GPU、电量等信息

2024-12-23 00:31:51

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11498
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。

封面图 JS系统 圣诞

目前,浏览器是有能力获取系统的一些信息的,包括内存大小,CPU/GPU、电量等。

一、JS获取内存大小

很简单,下面一行代码即可:

navigator.deviceMemory

例如在我的Chrome浏览器控制台的输出结果就是:

设备内存大小获取

deviceMemory的兼容性如下截图所示,目前仅Chrome浏览器支持。

deviceMemory设备内存获取兼容性

二、JavaScript get cpu信息

目前Web没法获取CPU具体的参数信息,但是可以获取CPU的核数。

同样是navigator对象,不过属性值看不到CPU三个字母的影子,名为hardwareConcurrency,表示可以并行运行的硬件数量。

代码示意:

navigator.hardwareConcurrency

运行结果示意:

CPU核数示意

没想到,我的破电脑CPU是12核的,应该与去年换主板有关,不过没看出性能有多少提升。

不过Mac下貌似可以看出芯片的品牌,例如我的Mac办公电脑运行navigator.platform返回的是'MacIntel'

hardwareConcurrency值的兼容性比deviceMemory好多了,参见下图,可以看到所有标准浏览器都是支持的:

硬件并行数量兼容性

三、GPU也是可以获取的

也是一行语法:

navigator.gpu

不过navigator.gpu返回的并不是具体的数值,而是GPU对象,这个对象和WebGPU API关联密切。

支持一个属性和两个方法,属性是wgslLanguageFeatures,方法为requestAdapter()getPreferredCanvasFormat()

navigator.gpu.wgslLanguageFeatures.size返回的是当前Web环境支持的WGSL语言特征数量,例如我的电脑windows电脑返回的是4,Mac笔记本也是4,有些GPU比较老,数量就不会是4.

不过这个API……怎么说呢,跟想象的有些不一样,检测的其实是浏览器是否支持WebGPU,以及是否可以调用适配器,以使用WebGL等功能。

我看来下兼容性,嘿,最新的Safari和Firefox都已经支持了,还挺巧的。

GPU属性兼容性

四、设备的电量识别

电量获取使用getBattery()方法,使用示意:

let batteryIsCharging = false;

navigator.getBattery().then((battery) => {
  // 当前电量水平是...范围0-1
  console.log(battery.level);
  // 是否在充电
  batteryIsCharging = battery.charging;
  
  // 充电状态变化的时候
  battery.addEventListener("chargingchange", () => {
    batteryIsCharging = battery.charging;
  });
});

通过上述代码,我们就可以获悉当前设备的电量状态,以及是否是充电状态。

像是PC电脑,接电源的,没电池的,只要设备运行,电量范围就一定是1,但是移动笔记本就会不一样。

我们可以据此,显示自定义的电池进度,充电动画,或者低电量模式的交互提醒(例如,关闭不必要的动画以帮助用户省电)等。

这个API其实和用户体验还是走得蛮近的,兼容性的话,我看看,是这样的:

getBattery兼容性

有些遗憾,仅仅Chrome浏览器支持,怪不得社区很少见到有对此API的讨论。

而且从Chrome开始支持的时间来看,短时间内,看不到Safari浏览器支持的迹象。

这么好的API,目前也只能当做玩具使用了。

五、其他一些硬件与设备的识别

navigator对象还提供了很多其他的硬件识别,例如蓝牙,虚拟键盘,USB,外置摄像头,是否掉线(navigator.onLine)等。

篇幅原因,我就不一一展示了,有兴趣可以访问对应的文档。

只要遇到类似的场景,知道Web有这样的能力就可以了。

ok,就这样吧,轻轻松松,又水了一篇文章,佛佛佛。

佛佛佛

本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11498

(本篇完)