今天学到了系列第1季(HTML/JavScript/CSS 知识点)

1,244 阅读11分钟

从 2019 年 10 月底开始,我坚持每个工作日发布一篇题为“今天我学到了”的沸点。就这样点滴积累,到现在已经攒够足够的量,所以集结拿出来与大家共同分享。

当初之所以做这样一件事情,一方面是督促自己每日坚持学习;另一方面,我发现有时候学到的知识点比较琐粹,一句话就能讲完,但又不够一篇文章的体量,又得找个地方记录下来,否则过后可能又会忘记。我发现沸点是个不错的地方,于是就开始我的分享之旅。

在分享的过程中,会有一些“你说的这个问题不是什么新鲜事了”、“你才知道吗……”、“...毫无意义” 之类的声音,其实我并不太在乎。将这些话列出来也没有也别的意思,只是想说:我发布的这些沸点,对我来说肯定是有用的,是让我学到的,如果你已经知道了,那我祝贺你;如果你还不知道,希望在我学到后,也能让你也学到,大家一起点滴进步。

好了,再多说都是废话了。下面开始正文:

JavaScript

1. str.replace 方法

'2019.12.13'.replace('.', '-') 的结果是 "2019-12.13",默认只替换第一个匹配的 .,如果需要替换所有的 .,就要用到正则表达式的全局标记 g 了。

2. Array.from 方法的映射功能

Array.from() 方法将可迭代对象转为数组的同时,还可以做映射(map)操作。

3. 使用科学计数法显示的数字范围

JavaScript 中以下四个区间范围的数字会使用科学计数法显示:

  1. (-∞, -1e+21]
  2. [-1e-7, 0)
  3. (0, 1e-7]
  4. [1e+21, +∞)

4. Symbol.toStringTag

Object.prototype.toString() 可以用来检查对象类型。

var toString = Object.prototype.toString;
toString.call('foo');     // "[object String]"
toString.call([1, 2]);    // "[object Array]"
toString.call(3);         // "[object Number]"
toString.call(true);      // "[object Boolean]"
toString.call(undefined); // "[object Undefined]"
toString.call(null);      // "[object Null]"

从 ES2015 开始,可以使用内置的 Symbol.toStringTag,自定义对象返回的类型值。

let Obj = {
  get [Symbol.toStringTag]() { return 'Wow' }
}
Object.prototype.toString.call(obj) // "[object Wow]"

你可能不知道的是,有些内置对象已经在使用 Symbol.toStringTag 定义自己的类型了。

Object.prototype.toString.call(new Map());       // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"

参考链接:developer.mozilla.org/en-US/docs/…

5. location 对象的属性说明

6. export default 命令的本质

JavaScript 的 export default 命令本质上是向外输出了一个叫 default 的变量。

// module.js
const apple = '🍏', banana = '🍌'
export default apple
export { banana }
// import.js
import apple, { banana } from 'm.js'

// 等同于

// module.js
const apple = '🍏', banana = '🍌'
export {
    apple as default,
    banana
}
// import.js
import { default as apple, banana } from 'm.js'

就是说:

  • export default xxexport { xx as default } 的另一种写法
  • import xximport { default as xx } 的另一种写法

7. 模板字符串的另一种用法

模板字符串(``)除了提供常用的插值语法(${})外,还有一个用法,这个用法为函数提供了一种特殊调用形式 func`x`。

简单地讲:alert`123` 等同于 alert(123)

而当其中包含变量时,该模板字符串会被拆解成多个参数,再调用函数:

let a = 5;
let b = 10;

tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

即实际调用的参数为:

  1. 第一个参数,是「模板字符串排除变量部分」后,其余各部分字符串组成的数组。
  2. 从第二个参数开始,则由「模板字符串中的变量」组成的列表。

参考链接:es6.ruanyifeng.com/#docs/strin…"

8. 用 Array.from 处理包含 emoji 的字符串

字符串的 .length 属性或 .charAt() 方法对像 😃 这样的 Unicode 码点大于 0xFFFF 的字符检查是错误的。我们可以使用 ES6 引入的 Array.from 方法处理,能得到正确结果。

const str = '😎'

// .length 属性或 .charAt() 方法对 Unicode 码点大于 0xFFFF 的字符检查是错误的
str.charAt(0) // "�"
str.length // 2

// 使用 ES6 引入的 Array.from 方法处理,能得到正确结果
function charAt(str, index) {
  return Array.from(str)[index] || ''
}
function strLength(str) {
  return Array.from(str).length
}
charAt('😎', 0) // "😎"
strLength('😎') // 1

9. 统计字符串的字节长度

JavaScript 可以使用以下两种方式,统计一个字符串占据的字节长度:

  • new TextEncoder().encode('👀⛰️').byteLength // 10,或者
  • new Blob(['👀⛰️']).size // 10

10. 引入 Lodash ES 模块构建

著名的 JS 工具库 Lodash 提供了使用 ES 模块语法引入的构建——lodash-es。因此我们还能这样使用它:

<script type="module">
import { uniq } from 'https://cdn.jsdelivr.net/npm/lodash-es@4.17.15/lodash.min.js'
uniq([1,1,2]) // [1,2]
</script>

11. Fullscreen API

全屏(Fullscreen) API 的简单使用:

  • 开启全屏:elem.requestFullscreen()
  • 退出全屏:document.exitFullscreen()

demo 地址:codepen.io/zhangbao/pe…

12. 网页顺滑滚动的原生方案

实现网页顺滑滚动(smooth scroll)的原生方式有四种:

  1. html { scroll-behavior: smooth; }
  2. window.scroll({ behavior: 'smooth' })
  3. window.scrollBy({ behavior: 'smooth' })
  4. elem.scrollIntoView({ behavior: 'smooth' })

demo 地址:codepen.io/zhangbao/pe…

13. 原型链继承说明

JavaScript 中的原型链继承:

  • 使用构造函数 Animal 生成的的实例对象(new Animal()),其内部的 [[Prototype]] 链(即 __proto__ 属性)指向 Animal.prototype
  • ES6 类继承语法 class Rabbit extends Animal { ... } 实际做了两件事:Rabbit.prototype 内部的 [[Prototype]] 链指向 Animal.prototype,同时 Rabbit 内部的 [[Prototype]] 链指向 Animal

继承细节见下图。

14. 派发自定义事件

使用 new CustomEvent()target.dispatchEvent(event) API 就能实现 DOM 元素上的自定义事件派发。

function fireEvent(name, target, detail) {
  const event = new CustomEvent(name, {
    bubbles: true,
    detail,
  });
  target.dispatchEvent(event);
};

demo 地址:codepen.io/zhangbao/pe…

15. 整数与不同进制间的转换

我们可以使用 numObj.toString(radix) 方法将整数转为不同进制的字符串;同时,可以使用 parseInt(string, radix) 将不同进制的字符串转为十进制数字。

16. 在整数上调用方法会报错

JavaScript 中直接在整数上调用方法,会报错

1.toString() // Uncaught SyntaxError: Invalid or unexpected token

这是把调用方法时使用的点当成小数点了,避免报错发生的方式有三种:

  1. String 函数显式转为字符串
  2. 数字与点之间空一格
  3. 数字后连续两个点
  4. 用圆括号包围数字

17. 复制文本

使用 JavaScript 复制文本分三步:

  1. 选择文本(input.select()
  2. 复制文本(document.execCommand('copy')
  3. 移除文本选择(window.getSelection().removeAllRanges()

demo 地址:codepen.io/zhangbao/pe…

18. 检查空对象

JavaScript 中检查空对象的两种方式:

19. 输入框文本全选

实现输入框文本全选功能,有两个API可供选择:

  1. HTMLInputElement.select()
  2. HTMLInputElement.setSelectionRange()
<input onClick="this.select();" value="via select()" />
<input onClick="this.setSelectionRange(0, this.value.length)" value="via setSelectionRange()" />

demo 地址:codepen.io/zhangbao/pe…

20. 一个解构赋值知识点

你可能不知道的解构赋值知识点:

  • 扩展运算符的解构赋值,只能复制目标对象的自身属性
  • 单纯的解构赋值,可以复制目标对象继承的属性

21. URLSearchParams API

URLSearchParams API 可以用来操作浏览器地址栏里的 url 参数。

以 "example.com/?q=URLUtils…" 为例。先来初始化下:

var searchParams = new URLSearchParams(location.search)

再来操作:

  • 获取参数:searchParams.get('topic') // 'api'
  • 添加/更新参数:searchParams.set('topic', 'More webdev')
  • 当前参数:searchParams.toString() // "q=URLUtils.searchParams&topic=More+webdev"
  • 删除参数:searchParams.delete('topic')
  • 是否包含参数:searchParams.has('topic') // false
  • searchParams.toString() // "q=URLUtils.searchParams"

参考链接:developer.mozilla.org/en-US/docs/…

CSS

22. 响应式字体设置

可以使用 vw@media 查询实现网站字体尺寸的响应式设置。

html {
    font-size: 1.6666666666666667vw;
}

@media (max-width: 600px) {
    html {
        font-size: 14px;
    }
}

@media (max-width: 400px) {
    html {
        font-size: 17px;
    }
}

23. attr() 功能函数

我们可以在伪元素(比如 ::after)的 content 属性里使用 attr() 函数获取元素属性值,而且还支持使用空格做字符串连接。

demo 链接:codepen.io/zhangbao/pe…

24. background-clip 干什么的?

CSS background-clip 用于限定只让在哪个区域的背景可见。可取值包括:border-boxpadding-boxcontent-box 和有趣的 text。

取值 padding-box,表示只让在 padding box 区域内的背景可见,border-box(默认值)和 content-box 作用类似;当取值 text 时(就比较有趣了),表示只在文本区域内的背景是可见,或者说“文本被背景填充了”,不过需要把文本颜色设置成透明的(transparent)才能看到效果。

demo 地址:codepen.io/zhangbao/fu…

25. auto-fitauto-fill 的区别

Grid 布局中 auto-fitauto-fill 关键字的区别。

  • 1fr 情况:auto-fill 会尽可能多的,在可用空间内分配更多 grid item 坑位;auto-fit 则尽可能拉伸当前的 grid item ,以便填充可用空间。
  • 固宽情况:auto-fill 在空间充裕的情况下会分配额外的 grid item 坑位;auto-fit 则不会。

demo 地址:codepen.io/zhangbao/pe…

26. 百分比 padding 的计算依据

CSS 百分比 padding 是依据父元素的 width 计算的。如下图所示,Child 的 padding-top: 25%,最终解析为 400 * 0.25,也就是 100px

demo 地址:codepen.io/zhangbao/pe…

27. text-decoration-skip-ink

CSS text-decoration-skip-ink 属性用于设置,下划线经过字符突出的上/下边缘时,是自动跳过还是直接穿过。

28. text-decoration-style

text-decoration-style 有 5 个可能的取值:soliddoubledotteddashedwavy。渲染结果如下:

demo 地址:codepen.io/zhangbao/pe…

29. 使用 scaleX(-1)/scaleY(-1) 实现翻转功能

使用 scaleX(-1)/scaleY(-1) 实现元素在 X轴/Y轴 方向上的翻转。

demo 地址:codepen.io/zhangbao/pe…

30. :placeholder-shown

:placeholder-shown<input><textarea>placeholder 属性有关。当输入框中的占位文本显示时,就匹配这个输入框。有几个边缘情况,需要注意:

demo 地址:codepen.io/zhangbao/pe…

31. 逻辑属性:inline-size、block-size

inline-sizeblock-size 属性的含义与网页的书写模式(writing-mode)有关。以文字排版为例:

  • 文字书写的方向称为 x/inline 轴,元素在这个轴上占据的尺寸称为 inline size。
  • 文字折行的方向称为 y/block 轴,元素在这个轴上占据的尺寸称为 block size。

因此这两个属性跟 widthheight 存在某种对应关系:

  • 在默认书写模式(writing-mode: horizontal-tb;)下,width = inline-size,height = block-size
  • 而在垂直书写模式下(比如 writing-mode: vertical-rl;)下,width = block-size,height = inline-size

demo 地址:codepen.io/zhangbao/pe…

32. clip-path

使用 clip-path 属性裁剪元素的两种方式:

demo 地址:codepen.io/zhangbao/fu…

33. :nth-child 与 :nth-of-type 的区别

:nth-child(1):nth-of-type(1) 的区别:

span:nth-child(1) 匹配的是:1. <span>;2. 是父元素的第一个孩子。判断条件使用 JS 表达是下面这样的:

if (parent.children[0] && parent.children[0].tagName === 'SPAN') {
    /* 为元素应用样式... */
}

a:nth-of-type(1) 匹配的是:在父元素范围内第一个出现的 <a>,查找逻辑使用 JS 表达是下面这样的:

if (document.querySelectorAll('.nav > a')[0]) {
    /* 为元素应用样式... */
}

demo 地址:codepen.io/zhangbao/pe…

34. Flex 项目的内容尺寸 & 基础尺寸

Flex 项目的最终渲染尺寸是基于内容尺寸/基础尺寸进行的:

  • 当 Flex 项目设置了 flex-basiswidth(同时设置时,flex-basis 优先级高于 width)时,它是基于此基础尺寸缩减/增长的。
  • 当 Flex 项目未设置 flex-basiswidth 时,则是基于内容尺寸(max-content)缩减/增长的。

demo 地址(Firefox 中打开观察):codepen.io/zhangbao/fu…

35. 区分鼠标聚焦和 Tab 键索引聚焦

:focus-visible 伪类可以区分一个元素是通过鼠标点击聚焦的,还是通过 Tab 键索引聚焦的。

这样就能实现以下的交互效果——点击 <button> 时不会出现 outline,而用 Tab 键索引时出现 outline。

demo 地址:codepen.io/zhangbao/pe…

36. writing-mode

在不同的 writing-mode 取值下,文字排版(文档流)方向的表现:

demo 地址:codepen.io/zhangbao/fu…

37. Grid 项目最终渲染尺寸

使用了 grid-template-columns: 1fr 1fr 之后,就能保证两个 Grid 项目一样宽吗?不一定。

如果一个 Grid 项目的 min-content 大于最终计算出来的 1fr 的值,那么这个 Grid 项目最终渲染尺寸是 min-content

demo 地址:codepen.io/zhangbao/fu…

38. visibility 属性

CSS 的 visibility 属性有一个有趣的地方——父元素 visibility: hidden,子元素 visibility: visible,最终的呈现效果是:父元素不可见,这个子元素却是可见的。

demo 地址:codepen.io/zhangbao/fu…

39. text-decoration 是个复合属性

CSS 中的 text-decoration 是个复合属性,语法如下:

text-decoration: <'text-decoration-line'> || <'text-decoration-style'> || <'text-decoration-color'>

其中每个单独属性的初始值如下:

  • text-decoration-line: none
  • text-decoration-style: solid
  • text-decoration-color: currentcolor

就是说,当我们使用 text-decoration: underline 的时候,实际作用的是 text-decoration: underline solid currentcolor

链接:developer.mozilla.org/en-US/docs/…

HTML

40. rel="nofollow"

某些个人网站上会出现一些垃圾评论外链,有些外链的目的是为了提高自己网站的搜索引擎排名。

为了告知搜索引擎此外链不被网站信任,无需计入搜索排名。可以这样做:

<a rel="nofollow" target="_blank">

更进一步,添加避免本页面被外链网页操作的代码:

<a rel="nofollow noopener noreferrer" target="_blank">

参考链接:ahrefs.com/blog/zh/nof…

41. rel="noopener noreferrer"

在当前页面使用 <a target="_blank">window.open() 打开新页面时,如果不做特殊处理,在新页面中可以使用 window.opener 访问当前页面的 window 对象。

后果是在新页面中能够重置当前页面的 url 地址:window.opener.location = 'evil.com'

为了避免这类事情发生,我们可以使用下图的做法。

参考链接:mathiasbynens.github.io/rel-noopene…

(完)