Better

Ethan的博客,欢迎访问交流

前端杂记:CSS 命名、2020 新特性、模块化历史

一些前端不成体系的小笔记,比如命名、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 对象,多个节点也可以。

页面字体

页面字体使用一般如此

  1. 跟设计师协商好,不用特殊字体
  2. 如有特殊设计需求的字体,要么切成图片,要么用 fontface 加载字体文件
  3. CSS 中的 font-family 加载多个字体,并用 serif/sans-serif,保证浏览器能调用到系统默认的衬线/非衬线字体

postMessage

资料:HTML5 之跨域通讯 - 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 中导入的模块都是值传递与引用传递,类似于函数传参

总结

模块化的出现为前端的开发带来了如下好处:

  • 变量都拥有了自己的作用域,而不是直接挂载到全局,有效解决了命名冲突。
  • 让所有的模块都保持单一职责,显著的提升了开发效率以及代码的可维护性。
  • 重复代码不再通过拷贝,而是通过模块引入的方式实现,提升了代码的复用性。
  • 可以使用包管理工具,直接使用网络上开源的模块。


留言