我最近3个月的前端专业学习记录

21,655 阅读14分钟

以下内容是2023年7月17~10月16日自己每周学习的记录

第29周 7.17-7.23

这周在项目中使用了一种新的布局。

就是下图所示的布局效果。

在过去,这种图片固定比例的,宽度自适应的布局都至少只要2层以上的标签,这一次,使用了容器元素和全新的cqw单位,可以一层标签即实现最终的效果。

相关实现已经整理成文,有兴趣可以访问这里:“CSS高宽不等图片固定比例布局的三重进化”。

第30周 7.24-7.30

本周研究了了一个新的CSS属性text-wrap,目前仅Chrome浏览器支持,兼容性如下图所示:

其中名为balance的属性值很有趣,可以让div元素中的内联元素尽可能宽度一致排列,布局差异如下所示:

这个属性其实很有用,例如类似朋友圈点赞的那种布局效果,目前的实现都是优先第一行显示的。

有了text-wrap:balance属性后,就可以是下图所示的布局效果,体验会更好。

更多内容可以访问这里了解

第31周 7.31-8.6

在做项目的时候,偶然看到有同事的CSS代码中对samp标签样式进行了定义,然后研究了下这个已经没用过的HTML标签,发现还是一个系列,可以用来帮助代码文本的语义化呈现,具体如下:

  • kbd: 键盘输入的文字内容

  • samp: 范例输出

  • code: 计算机代码输出

  • var: 变量与自变量实例

平时只用过 code 标签 ,结果没想到还有其他类似HTML属性,现代浏览器全部都支持。

更详细的内容我已经这里成文章了,有兴趣的可以访问这里了解。

第32周 8.7-8.13

本周学习了两个HTML全局属性,nonce和popover属性。

nonce与安全相关,配合meta元素的CSP设置,可以决定哪个内联JS执行,哪个内联<script›元素不执行。

假设页面有如下所示的代码:

<meta http-equiv="Content-Security-Policy" content="script-src 'nonce-NDhkODkxMzYtNGUxZS00N2NjLTk1YTItNWMyOTM4YzdhZGJj'">
<script nonce="NDhkODkxMzYtNGUxZS00N2NjLTk1YTItNWMyOTM4YzdhZGJj">// …</script>

则此时,只有nonce值有设置,且值匹配的

popover属性是个比较新的属性。

可以让任意的元素点击后直接出现浏览器层面的popover弹出层效果。

例如下面的代码:

<button popovertarget="imgPopover">点击我</button>
<div popover id="imgPopover"><img src="1.jpg" /></div>

此时,点击按钮,就会出现图片显示浮层。

点击空白自动隐藏。

关于这两个HTML属性更多的内容,可以参见我撰写的这篇文章:“我仍未知道的HTML nonce和popover属性”。

第33周 8.14-8.20

本周学习了非常多的东西,因为要专业分享,要讲HTML部分,所以梳理了下HTML相关的内容,发现了很多之前遗漏的知识。

包括:

1. 浏览器的referrerpolicy策略

document.referrer可以返回当前页面的来源页面,而究竟显示哪些信息,是完整地址,还是空,亦或是只有域名,都是可以设置的。

例如:

  • no-referrer不发送任何Referer信息

  • no-referrer-when-downgrade表示协议安全级别下降的时候不发送Referer信息

  • origin是只显示域信息

  • origin-when-cross-origin表示跨域的时候只显示域信息

  • same-origin表示域名相同,否则Referer信息是空

  • strict-origin表示仅当协议安全级别保持不变时发送Referer信息

  • strict-origin-when-cross-origin是默认值(之前默认值不是这个),如果域名和安全协议相同或更高的时候,Referer信息是完整地址,如果跨域,则Referer信息是原始的域信息,如果安全协议降低,Referer信息为空

  • unsafe-url表示就算URL地址不安全,也发送完整的Referer信息

2. 返回顶部

原来<a href="#top">返回顶部</a>也可以返回顶部,以前只知道<a href="#">返回顶部</a>

3. li元素的父元素

<li>元素的父元素除了<ul>``<ol>,还可以是<menu>,这个之前也没注意到。

4. Open Graph协议

也就是开放内容协议,有利于社交分享,以微软官网源码示意:

5. <caption>元素

<caption>元素只能用在<table>表单中,此限制也是最近知道。

6. autocapitalize属性

autocapitalize属性可以控制手机软键盘呼起时候,字母的大小写设置。

7. 其他...

还有很多其他内容,例如exportparts属性,<dfn><abbr>的使用场景,以及上周介绍的几个属性等,篇幅原因,不一一展示了。

第34周 8.21-8.27

这周好好研究了下User Timing API,相比于Date.now()或者performance.now()方法,此API可以在自己希望记录的位置打下标记,然后和浏览器的性能工具配合,可以看到整个的渲染时长、时机等过程,更加方便我们定位调试,以及理解Web渲染的过程。

以及还可以和其他时间线API一起使用,例如PerformanceObserver。

PerformanceObserver可以对各项性能指标进行观察,而浏览器支持的性能指标非常多,尤其是Chrome浏览器。

我们可以使用PerformanceObserver.supportedEntryTypes这个语句获取,例如在Mac OS X系统的Chrome浏览器下。

通过设置需要指定观察的类型,我们就可以看到对应的性能指标了,例如'paint'类型,我们可以看到页面内容初次渲染的时间。代码示意:

const observer = new PerformanceObserver(entryList => {
    for (const entry of entryList.getEntries()) {
        console.dir(entry);
    }
});
observer.observe({
  entryTypes: ['paint']
});

浏览器返回:

startTime就可以示意首次渲染时间。

PerformanceObserver的相关知识非常多,这里就不具体展开,有兴趣的可以参考我撰写的“狠狠地研究了下 PerformanceObserver API”一文。

额外的思考

User Timing API非常庞杂,想要全部通透,需要非常多的时间精力,而相关知识的应用价值其实有限,如今的Web页面的性能都非常强悍了,很少遇到需要打开控制台排查性能的机会。

所以,对于大部分而言,花非常多的时间学习相关的内容是不换算的,我觉得了解个大概就足够了,至少那些基本的概念需要知道。

例如时间线是什么,时间线中的mark和measure是什么意思,first-input和largest-contentful-paint的含义是什么等?

对于这类非热门的前端知识,通常业内深入介绍的文章较少,文档呢,也通常会省略很多细节,此时,要想有个全面且大概的了解,一定要亲自实践,而不是自己脑补。

largest-contentful-paint渲染的元素究竟是哪个?如果不是自己预期的元素,会是什么原因造成的呢?

通透了这些原因,你对这些API的理解自然就比别人深刻一些,专业技术也就比别人更加扎实了。

第35周 8.28-9.3

这周研究了下registerProtocolHandler()方法。

第一眼看到registerProtocolHandler()方法的时候,说实话,我还是挺兴奋的。

这可是个有趣的东西啊,居然可以自定义协议地址,并且可以像正常链接一样访问。

然而,亲自体验了之后,发现没有想象的那么美好,限制较多,最大的问题,在Web端并不能简化URL,还需要对协议内容进行分析处理。

通常的自定义协议都是,桌面软件注册,浏览器URL呼起。

而registerProtocolHandler()方法是浏览器注册,浏览器呼起……总之比较鸡肋。

有兴趣可以访问这篇文章“一言难尽的registerProtocolHandler()方法”。

其他学习

之前对外分享的时候,多次提到,要节约时间,要学会坚持,重复做一件事情,后来发现效果一般,听众没什么感触。

这周看到了路长全的分享,讲得比我好——什么是吃苦?吃苦的本质是自律,心不苦,则智不开(有兴趣的可以搜相关视频)。

和日常的辛苦相对比,更有说服力些,可以借鉴下。

第36周 9.4-9.10

1. reset与chang事件

<form>元素在执行reset()方法的时候,虽然里面的输入框元素的值变了,但是并不会触发change事件,这个现象有时候会对我们的开发带来麻烦。

那有没有什么办法打个补丁呢?

有,正好reset事件执行时机是在输入框value值变化之前触发的,因此,我们可以检测此value前后有没有变化,以此来决定是否触发change事件。

具体代码如下,在页面任意位置引入即可:

在线演示页面戳这里

2. 本地环境跨域

本地开发域名经常是localhost,而请求地址往往是域名,此时会有跨域的问题。

之前的做法都是让运维配置运行跨域的请求头,但这个比较麻烦,后来我发现了一个更简单的解决方法。

那就是安装个Chrome插件Access Control Allow Origin,安装后,只要开启就没有跨域的烦恼了。

第37周 9.11-9.17

本周学习了这些。

1. HTML elementtiming属性

抽空研究了下elementtiming属性,在性能监控的需求中,这个属性很实用。

给任意的有图文内容的DOM元素添加此属性,并自定义标志量作为属性值,则使用PerformanceObserver API进行观察的时候,就可以知道此元素的渲染起始时间,如果是图片等元素,还可以知道图片的加载时间。

这对于排查页面中哪个元素的渲染最耗时非常有用。

详见我整理的这篇文章:“HTML elementtiming属性初体验记录”。

2. 复制图片到剪切板

上周做了个在线PNG/JPG优化的小工具,但是有个问题,如果我想直接粘贴到编辑器中,或者在其他地方进行上传,就必须先将优化的图片下载到本地,然后再进行处理。

但这样的操作显然有些啰嗦,最好可以直接复制优化的图片进入剪切板。

浏览器提供了原生的API可以满足此需求,代码示意:

// blob是图片二进制数据 
const data = [newClipboardItem({ ['image/png']: blob })]; 
navigator.clipboard.write(data);

然而,此API只能复制PNG图片,复制其他格式的图片数据会报错。

虽然可以通过canvas将JPG图片转为PNG,但那就是无损图了,而不是压缩图。

后来,曲线救国,直接复制图片的base64信息,然后再在上传页面,或者预览页面进行二次处理。

具体可以参见我整理的文章:“又get到了,JS复制图片到剪切板”。

第38周 9.18-9.24

本周比较忙碌,没有学习,只有思考。

基于JSON数据和JS在Web端模拟视频播放功能上周已经弄好了。

不过周末想了下,需要重新改变下算法实现。

原因:

之前算法是,先提前对每个tts音频和背景音乐进行合并,然后再控制播放,这样实现的好处是解析器编写简单。

但是有一个问题,由于浏览器的限制,这种合成需要用户至少点击一次页面,无法默默地完成。

而根据实际运行的结果,此合成会造成几百毫秒的卡顿,如果在用户点击后执行,会有体验问题。

所以,需要换一种实现,就是时间轴运行到哪个tts,就播放哪个tts音频,之前的xx工具就是这么处理的,虽然麻烦了点,不过因为即点即播,用户体验不受影响。

另外还有个好处,tts和背景音乐分离后,背景音乐的音量设置也可以比较容易地反馈出来。

至于音频的合成,就留在视频导出的时候完成,因为此时会专门做一个loading效果,即使有延时和卡顿,用户也不会觉得有什么问题。

不过,这里还有个技术小缺失,基于canvas图片序列+音频=>MP4视频的技术我这边是没问题的,demo已经跑通,但是合并的时候,需要控制某一个音频的音量我还不知道具体的细节,这个需要花时间研究下,可能需要额外的半天时间。

第39周 9.25-10.1

因为某某工作的原因,重新拾起了对<html><body>元素的关注,然后以前一些模模糊糊的理解现在终于理清楚了。

默认情况下,body元素的高度是0,但是此时设置background背景,会发现满屏显示。

例如:

body { background-color: black; }

但,如果此时html元素也设置个背景色,例如:

html { background-color: skyblue; }

此时,body设置的背景色消失了,明明 body 是子元素。

还有奇怪的,如果body设置的是线性渐变,例如:

body { background: linear-gradient(black, white); }

发现背景是个8px像素平铺的水平条纹。

8px哪里来的,为何是水平条纹?

很多人并不理解这种现象。

这其实是body、html元素的某种特异性。

即:

  1. 如果body设置了背景,但html没设置,则body的背景等同于设置在 html 元素上,否则,body按照普通的标签元素渲染。

  2. html背景的渲染高度至少一屏。

这就可以理解上述所有的现象了。

尤其是最后的水平条纹。

由于body元素默认有8px的margin大小,考虑到margin合并,因此,html元素的默认高度是8px,于是渐变背景高度也是8px。

但是html元素的背景至少要一屏高,于是8px水平平铺了起来。

overflow属性也有类似的现象。

单纯如下body overflow是无法隐藏div元素的,哪怕div元素的高度比body明显高,例如:

body { height: 30px; overflow: hidden; } 
body > div { height: 300px; background-color: #cd0000; }

此现象出现原因和背景色类似。

  1. 如果html元素没有设置overflow属性,那么body元素的设置等同于设置在html元素上,否则,body元素的overflow属性按照普通元素渲染。

  2. html元素的overflow剪裁高度至少一个屏幕高度。

所以,上面CSS代码,只需要html元素设置任意不是 visible 值的overflow属性,都能触发body元素剪裁div,哪怕html元素的高度很高。

例如:

html { height: 400px; overflow: scroll; }

此时body overflow生效。

于是,下面的现象也就理解了,即如果div高度很高,例如3000px,可以看到div元素在一屏高度的地方隐藏了:

body > div { height: 3000px; background-color: #cd0000; }

这是因为html元素的overflow生效高度至少1屏。

第40周 10.2-10.9

学什么学,国庆假期,浪起来!

钓鱼钓了个昏天暗地……

第41周 10.9-10.15

本周学习围绕音频处理展开,两个需求点。

1. 改变原始音频的音量

如果仅仅是调整播放的音量,那很简单。

如果你使用的是<audio>元素,直接改变volume属性就好了。

audio.volume = 0.5;

如果没有audio元素,而是使用的Web Audio API,希望在 AudioBuffer 层面设置播放的音量,则可以使用GainNodes实现。

您可以狠狠地点击这里体验效果:使用gainNode改变音频播放音量demo

如果希望从原始文件层面改变音频的音量大小,怎么办呢?

可以解析音频文件,然后遍历采样点数据,然后根据音量设置进行调整。

由于代码较长,这里就不放出来了,有兴趣可以访问这篇文章:“JS改变AudioBuffer音量并下载为新audio音频”。

2. 音频的拼接与合并

拼接:

合并:

操作过程和改变音量大小的实现大同小异。ArrayBuffer转AudioBuffer,然后读取音频信息,对采样信息进行处理。

同样,篇幅原因,这里不展示源码,有兴趣的可以访问:“纯JS实现多个音频的拼接或者合并

如果你对原生实现不怎么感兴趣,也可以使用开源项目。

比方说这个叫做crunker的项目:github.com/jaggad/crun…

如果你已经有了 AudioBuffer 资源,上面的 fetchAudio() 方法也是可以省略的。

另外,此JS还支持使用静音填充视频。

----------------

OK,以上就是最近三个月的学习记录。

然后我专门建了个学习记录的专栏,每个季度更新一下。

欢迎关注哈。