一些前端不成体系的小笔记,比如命名、postMessage、JS 新特性、过渡动效、前端模块化以及一些小知识点。
CSS 相关
CSS 编写
写 CSS 的时候,每写一个像素值的时候都有意识思考一下,不写具体值能否实现,能否用自适应的方式实现。因为越多的像素值意味着越不灵活。
关于命名
函数命名的时候,一定要使用动宾结构,光用动词可能会给别人造成困惑。
语义化命名,对于 CSS 来讲,有两种命名体系
- 描述用途或特征
- 容器类:wrapper、container、panel、row、col
- 特征:bluebg、redtext、default-icon
- 描述具体内容
- username、avator、article-list、news-detail
事实上,搞 CSS 架构的都推崇第一种方式,原因就是为了适应变化
变量命名规范
- 向标准靠拢
- 向知名框架靠拢
手动重绘
常见的触发重绘的方法有
- 设置元素的 visibility 为 visible
- el.className = el.className
后退按钮
监听点击后退按钮
- beforeunload 不靠谱,ios 上不行
- pagehide 事件也各种不灵
- 解决办法:做成单页应用,通过监听路由变化来控制
检测 video 是否播放
监听 timeupdate 事件,看 currentTime 是否大于 0。之所以要做这个检测,是因为移动端不允许预加载资源,video 点击播放的时候才开始加载,此时黑屏时间较长,需要给用户一个提示,比如『视频加载中……』
不知道的 API
Range 对象的 createContextualFragment 可以接受 html 字符串生成对应的 DOM 对象,多个节点也可以。
页面字体
页面字体使用一般如此
- 跟设计师协商好,不用特殊字体
- 如有特殊设计需求的字体,要么切成图片,要么用 fontface 加载字体文件
- CSS 中的 font-family 加载多个字体,并用 serif/sans-serif,保证浏览器能调用到系统默认的衬线/非衬线字体
postMessage
破碎图片添加样式
资料:破碎图片添加样式
2020 新特性
Promise.allSettled
都知道 Promise.all 具有并发执行异步任务的能力。但它的最大问题就是如果其中某个任务出现异常(reject),所有任务都会挂掉,Promise直接进入 reject 状态。
我们需要一种机制,如果并发任务中,无论一个任务正常或者异常,都会返回对应的的状态(fulfilled 或者 rejected)与结果(业务value 或者 拒因 reason),在 then 里面通过 filter 来过滤出想要的业务逻辑结果,这就能最大限度的保障业务当前状态的可访问性,而 Promise.allSettled 就是解决这问题的。
可选链
可选链可让我们在查询具有多层级的对象时,不再需要进行冗余的各种前置校验。
var name = user?.info?.name;
var age = user?.info?. getAge?.();
空值合并运算符
当我们查询某个属性时,经常会遇到,如果没有该属性就会设置一个默认的值。
用空值合并运算在逻辑正确的前提下,代码更加简洁。
空值合并运算符 与 可选链 相结合,可以很轻松处理多级查询并赋予默认值问题。
var level = user.data?.level ?? '暂无等级'
dynamic-import
按需 import 提案几年前就已提出,如今终于能进入ES正式规范。
为了首屏渲染速度更快,很多时候都是按需加载,比如懒加载图片等。而这些按需执行逻辑资源都体现在某一个事件回调中去加载。
globalThis
过去获取全局对象,可通过一个全局函数,例如 getGlobal,内部进行各种条件判断
而 globalThis 目的就是提供一种标准化方式访问全局对象,有了 globalThis 后,你可以在任意上下文,任意时刻都能获取到全局对象。
BigInt
JS 中 Number类型只能安全的表示-(2^53-1)至 2^53-1 范的值,即Number.MINSAFEINTEGER 至Number.MAXSAFEINTEGER,超出这个范围的整数计算或者表示会丢失精度。
为解决此问题,ES2020提供一种新的数据类型:BigInt。使用 BigInt 有两种方式:
- 在整数字面量后面加n。
- 使用 BigInt 函数。
String.prototype.matchAll
获取到全局所有匹配项,包括子项呢
String.prototype.matchAll, 该方法会返回一个迭代器。
过渡动效
模块化
CommonJS
CommonJS 在服务端表现良好,很多人就想将 CommonJS 移植到客户端进行实现。由于CommonJS 的模块加载是同步的,而服务端直接从磁盘或内存中读取,耗时基本可忽略,但是在浏览器端如果还是同步加载,对用户体验极其不友好,模块加载过程中势必会向服务器请求其他模块代码,网络请求过程中会造成长时间白屏。所以从 CommonJS 中逐渐分裂出来了一些派别,在这些派别的发展过程中,出现了一些业界较为熟悉方案 AMD、CMD、打包工具(Component/Browserify/Webpack)。
AMD规范:RequireJS
RequireJS 是 AMD 规范的代表之作,它之所以能代表 AMD 规范,是因为 RequireJS 的作者 (James Burke) 就是 AMD 规范的提出者。
James Burke 指出了 CommonJS 规范在浏览器上的一些不足:
- 缺少模块封装的能力:CommonJS 规范中的每个模块都是一个文件。这意味着每个文件只有一个模块。这在服务器上是可行的,但是在浏览器中就不是很友好,浏览器中需要做到尽可能少的发起请求。
- 使用同步的方式加载依赖:虽然同步的方法进行加载可以让代码更容易理解,但是在浏览器中使用同步加载会导致长时间白屏,影响用户体验。
- CommonJS 规范使用一个名为 export 的对象来暴露模块,将需要导出变量附加到 export 上,但是不能直接给该对象进行赋值。如果需要导出一个构造函数,则需要使用 module.export,这会让人感到很疑惑。
CMD规范:sea.js
CMD 规范由国内的开发者玉伯提出,尽管在国际上的知名度远不如 AMD ,但是在国内也算和 AMD 齐头并进。相比于 AMD 的异步加载,CMD 更加倾向于懒加载,而且 CMD 的规范与 CommonJS 更贴近,只需要在 CommonJS 外增加一个函数调用的包装即可。
ES Module
相比于 CommonJS 和 AMD 方案,ESM采用了完全静态化的方式进行模块的加载,静态化也为后来的打包工具提供了便利,并且能友好的支持 tree shaking。
ESM 与 CommonJS 的差异
- 一个使用 import/export 语法,一个使用 require/module 语法。
- ESM 导入模块的变量都是强绑定,导出模块的变量一旦发生变化,对应导入模块的变量也会跟随变化,而 CommonJS 中导入的模块都是值传递与引用传递,类似于函数传参
总结
模块化的出现为前端的开发带来了如下好处:
- 变量都拥有了自己的作用域,而不是直接挂载到全局,有效解决了命名冲突。
- 让所有的模块都保持单一职责,显著的提升了开发效率以及代码的可维护性。
- 重复代码不再通过拷贝,而是通过模块引入的方式实现,提升了代码的复用性。
- 可以使用包管理工具,直接使用网络上开源的模块。