Better

Ethan的博客,欢迎访问交流

前端杂记@20200206

一些前端不成体系的小笔记,比如命名、postMessage、JS 新特性、过渡动效、前端模块化以及一些小知识点。

关于命名

函数命名的时候,一定要使用动宾结构,光用动词可能会给别人造成困惑。

语义化命名,对于 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 点击播放的时候才开始加载,此时黑屏时间较长,需要给用户一个提示,比如『视频加载中……』

CSS 编写

写 CSS 的时候,每写一个像素值的时候都有意识思考一下,不写具体值能否实现,能否用自适应的方式实现。因为越多的像素值意味着越不灵活。

不知道的 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 中导入的模块都是值传递与引用传递,类似于函数传参

总结

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

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


留言