feat: 添加多个附录交互式组件和文档更新
- 添加浏览器前端组件:无障碍访问、国际化、实时通信 - 添加 Transformer 注意力机制系列组件 - 更新 Canvas、数据追踪等现有组件 - 修复 ESLint 变量名冲突问题 - 完善相关附录文档
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
::: tip 🎯 核心问题
|
||||
|
||||
以前的网页只能展示干巴巴的文字和图片。但如果你想做打砖块游戏、华丽的动态特效、或是可以自由拖拽的数据报表呢?这就是 **Canvas(画布)** 诞生的原因。
|
||||
以前的网页只能展示干巴巴的文字和图片。但如果你想做打砖块游戏、华丽的动态特效、或是可以自由拖拽的数据报表,仅仅靠 `<div>` 是远远不够的。这就是 **Canvas(画布)** 诞生的原因。
|
||||
|
||||
本指南将带你从画下第一条线开始,一路打怪升级,最终亲手写出能在浏览器中流畅运行 60 帧的粒子引擎。
|
||||
|
||||
:::
|
||||
|
||||
@@ -10,52 +12,53 @@
|
||||
|
||||
## 1. 什么是 Canvas?
|
||||
|
||||
如果说早期的那些 HTML 标签(如 `<div>`、`<img>`)是用**乐高积木**拼起一个静态的网页,那么 HTML5 的 `<canvas>` 标签就是扔给你一张**巨大的数字白纸**,然后递给你一支靠代码控制的**画笔**,剩下的全交给你自由发挥。
|
||||
如果说早期的网页是用**乐高积木**(HTML 标签)拼凑起来的静态模型,那么 HTML5 的 `<canvas>` 标签就是扔给你一张**巨大的数字白纸**,然后递给你一支靠代码控制的**画笔**,剩下的全交给你自由发挥。
|
||||
|
||||
这里面的画没有任何标签结构,你用画笔涂上去的心血,一旦落笔就变成了最纯粹的**“像素颜料”**。
|
||||
这里面的画没有任何标签结构。你用画笔涂上去的心血,一旦落笔就变成了最纯粹的**“像素颜料”**。
|
||||
|
||||
### 1.1 Canvas vs SVG:两种不同流派的艺术家
|
||||
|
||||
在前端画图界,Canvas 有个宿敌叫 **SVG**。它们代表了两种截然不同的绘画观念:
|
||||
|
||||
**Canvas(位图画板):**
|
||||
* **原理**:就像真实在纸上涂色,几笔画上去就变成一团颜料。
|
||||
* **优势**:电脑只管往屏幕上“洒颜料”,性能起飞!能同时画出大几千个活蹦乱跳的闪烁粒子。
|
||||
* **缺点**:画完就没法单独反悔(没法被 DOM 直接选择),而且你用浏览器一旦放大,画面就会马赛克发虚。
|
||||
|
||||
**SVG(矢量图拼接):**
|
||||
* **原理**:就像在做幻灯片(PPT)。你画一个圆,它就生成一个圆圈的“实体对象”放在画面上。
|
||||
* **优势**:不管被放大成 100 倍还是 10 万倍,永远极其清晰。而且因为每一个形状都是一个独立标签,你可以在任何时候用鼠标点中某个小正方形,命令它换一种颜色。
|
||||
* **缺点**:如果你试图放几万个对象乱飞,繁重的排版引擎会直接把浏览器卡死。
|
||||
- **Canvas(位图画板):**
|
||||
- **原理**:就像真实在纸上涂色,几笔画上去就变成一团颜料(像素点)。
|
||||
- **优势**:电脑只管往屏幕上“洒颜料”,性能起飞!能同时画出大几千个活蹦乱跳的闪烁粒子。
|
||||
- **缺点**:画完就没法单独反悔(没法通过 DOM 节点选择),且放大会造成马赛克发虚。
|
||||
- **SVG(矢量图拼接):**
|
||||
- **原理**:就像做 PPT。你画一个圆,它就生成一个独立标签的“圆实体”放在画面上。
|
||||
- **优势**:不管放大 100 倍还是 10 万倍,永远极其清晰。每个形状都是独立的 DOM 节点,你可以随时用 CSS 和 JS 改变它的颜色或绑定点击事件。
|
||||
- **缺点**:如果你试图放几万个对象乱飞,繁重的 DOM 树和排版引擎会直接把浏览器卡死。
|
||||
|
||||
**🎮 简单总结:玩动态游戏、做酷炫粒子特效用 Canvas;画精密的 Logo、写交互清晰的小图表用 SVG。**
|
||||
|
||||
---
|
||||
|
||||
## 2. 第一笔:用代码找坐标
|
||||
## 2. 第一笔:理解反直觉的坐标系
|
||||
|
||||
### 2.1 这张纸的上下怎么颠倒了?
|
||||
|
||||
当你准备下笔时,得先明白 Canvas 里的尺子是反着的。对于传统的数学课坐标系,中心点零点在中间,越往上越大。
|
||||
当你准备下笔时,得先明白 Canvas 里的尺子是反着的。对于传统的数学课坐标系,中心点零点在中间,越往上越大。但在计算机屏幕显示领域,几乎所有设备的“原点(0,0)”都定在**屏幕的最左上角**。向右走 X 轴变大没问题,但是**向下走,Y 轴变大。**
|
||||
|
||||
但在屏幕显示领域,几乎所有设备的“原点(0,0)”都定在**屏幕的最左上角**。向右走 X 轴变大没问题,但是**向下走,Y 轴变大。**
|
||||
**Canvas 坐标系统的核心原则:**
|
||||
- **原生单位:** 像素 (px),与屏幕物理像素 1:1 对应。
|
||||
- **X 轴:** 向右为正方向,从 `0` 到 `canvas.width`。
|
||||
- **Y 轴:** 向下为正方向,从 `0` 到 `canvas.height`。
|
||||
|
||||
👇 **动手点点看**:
|
||||
拖拽下面的这些点,直观地感受一下坐标是如何变化的:
|
||||
👇 拖拽下面的小圆点,直观感受计算机图形学中的坐标原点与走向:
|
||||
|
||||
<CoordinateSystemDemo />
|
||||
|
||||
### 2.2 给你的魔法画笔上调料
|
||||
|
||||
有了坐标,我们就能召唤那支画笔了(在代码里这支笔叫 `Context` 或简称 `ctx`)。
|
||||
有了坐标体系,我们就能召唤画笔了(代码中称为 `Context`,或缩写 `ctx`)。就如同拿着真实的调色盘作画,Canvas 的 API 设计完美遵循了物理作画的三个步骤:
|
||||
|
||||
就像拿着调色盘作画,流程总是固定的三步:
|
||||
1. **调色**:告诉它你需要什么填充色(`fillStyle`)和描边色(`strokeStyle`)
|
||||
2. **构形**:构思你是画一个圈、还是一条直线?
|
||||
3. **下笔**:实打实地去填充(`fill( )`)还是去勾勒边缘(`stroke( )`)
|
||||
1. **调色(State)**:通过 `fillStyle` 设置填充色,`strokeStyle` 设置描边色。
|
||||
2. **构形(Path)**:构思你是要画一条线(`lineTo`)、还是一个圆(`arc`)、亦或一个矩形(`rect`)。
|
||||
3. **极简下笔(Render)**:决定是内部填充(`fill()`)还是勾勒边缘(`stroke()`)。
|
||||
|
||||
👇 **动手点点看**:
|
||||
试试把下面代码面板里的形状颜色换换:
|
||||
由于 Canvas 是纯粹的位图画布,“落子无悔”,你一旦画下,它立刻干涸成为像素,无法再被撤销为独立对象。
|
||||
|
||||
👇 尝试在下面的演示中挑选不同形状和颜色,看看背后的代码是如何执行上述“三步走”的:
|
||||
|
||||
<CanvasBasicsDemo />
|
||||
|
||||
@@ -63,38 +66,36 @@
|
||||
|
||||
## 3. 翻页动画书:如何让画面动起来极度丝滑
|
||||
|
||||
我们刚才说过,Canvas 一旦你填上了颜色,这就变成了永久的马赛克。你怎么可能让马赛克奔跑呢?
|
||||
既然 Canvas 一旦填色就变成了永久的像素,那么各种 HTML5 页游里满屏乱跑的角色是怎么做出来的?
|
||||
|
||||
**答案是“骗过你的眼睛”。这和翻页手翻书或者电影胶片的原理一模一样。**
|
||||
答案是**“骗过你的眼睛”**。这和手翻动画书或者电影胶片的原理一模一样。
|
||||
|
||||
如果你想让一个球飞起来:
|
||||
1. **擦黑板**:用 `clearRect` 把这整块画布上的内容毫不留情地清空!
|
||||
2. **挪位置**:让那个球的 X 坐标往前偷偷加 2 毫米。
|
||||
3. **下笔重画**:把球在新的位置重新画一次。
|
||||
4. **疯狂循环**:浏览器内置了一个极其精准的神仙秒表叫 `requestAnimationFrame`。它会以每秒 60 次(即 60 FPS)的变态速度,重复着【擦除 -> 移动 -> 重绘】。由于人眼自带“视觉残留”,你在屏幕上看到的,不仅不是黑板被擦,反而是如同丝绸般顺滑的动画。
|
||||
1. **擦黑板(Clear):** 用 `clearRect()` 把整块画布上的内容毫不留情地清空。
|
||||
2. **计算新位置(Update):** 让角色的 X 坐标往前偷偷加 2 个像素点。
|
||||
3. **下笔重画(Render):** 把角色在新的位置重新画一次。
|
||||
4. **疯狂循环(Loop):** 结合浏览器内置的极其精准的节拍器 `requestAnimationFrame`。它会以显示器的刷新率(通常是每秒 60 次,即 60 FPS)重复这三个动作。
|
||||
|
||||
👇 **动手点点看**:
|
||||
尝试添加或者减少物体的数量,感受每秒 60 帧带来的无缝快感:
|
||||
由于人眼自带“视觉残留”,在每秒 60 次的【擦除 -> 更新 -> 重绘】中,你看到的不仅不是闪烁的黑板,反而是如同丝绸般顺滑的动画。
|
||||
|
||||
👇 在下方的演示中调整播放速度,观察每一帧的位移是如何连缀成流畅运动的:
|
||||
|
||||
<AnimationLoopDemo />
|
||||
|
||||
---
|
||||
|
||||
## 4. 瞎子摸象:我在 Canvas 里面怎么点击?
|
||||
## 4. 瞎子摸象:在 Canvas 里面怎么做点击交互?
|
||||
|
||||
因为 Canvas 画布就只是一张没有任何结构的“颜料布”。假设你在这个布上画了一只哥布林:
|
||||
因为 Canvas 画布在浏览器眼里只是一张没有任何结构的“颜料布”。假设你在画布上用 `arc()` 画了一只怪兽,当你想要实现“点击怪兽扣血”时,你**根本没法**使用传统的 `document.getElementById` 来获取这个怪兽。因为在 HTML 结构中,只有那个宽 600 像素的死板 `<canvas>` 标签。
|
||||
|
||||
如果你想写个代码:“当玩家点中了哥布林,哥布林阵亡”。你根本没法像写普通网页那样通过 `getElementById` 去直接绑定这个外星怪物。因为在浏览器的眼里,**这里永远没有任何怪兽,只有一块宽 600 高 400 的 `<canvas>` 标签死死挡在这里**。
|
||||
这就是图形编程中最经典的问题:**碰撞检测 (Collision Detection) 与事件代理**。
|
||||
|
||||
那我们要怎么做事件交互呢?
|
||||
1. **监听布面被点**:先获取你目前鼠标点在这个死板的 HTML 大布的哪个具体的 XY 位置。
|
||||
2. **拿账本去对**:然后你必须自己翻你的代码记录,“我记得刚刚我在(100,100)的位置画了一个半径 50 的哥布林”。
|
||||
3. **勾股定理**:我们用初中教的勾股定理公式去疯狂计算——当前鼠标点击的位置,是不是落在了那个(100,100)距离 50 半径的圆内?。
|
||||
由于浏览器只知道你的鼠标点击了 Canvas 的屏幕坐标 `(x, y)`,你需要自己去通过初中的几何数学进行反算:
|
||||
- **对于圆形:** 通过勾股定理计算 `鼠标点击处` 到 `圆心位置` 的距离,如果距离小于半径,则说明“被点中了”。
|
||||
- **对于矩形:** 判断点击的 `x` 是否在矩形的左右边界内,同时 `y` 是否在上下边界内。
|
||||
|
||||
恭喜你!这种疯狂算几何数学距离的方法就是你在各大 3A 游戏里听过的 **“碰撞检测 (Collision Detection)”**
|
||||
无论你的画布上有多少元素,鼠标悬停或点击事件永远是绑定在 Canvas 这个唯一容器上的,这就是终极的“事件委托”。
|
||||
|
||||
👇 **动手点点看**:
|
||||
打开最下面的“Hover 悬停模式”,你就能看到它内部拼命去算距离有多累了。
|
||||
👇 试着在下面使用鼠标(点击、拖拽、悬停)或键盘(方向键移动),体会这种“手动算距离”的底层交互逻辑:
|
||||
|
||||
<EventHandlingDemo />
|
||||
|
||||
@@ -102,12 +103,16 @@
|
||||
|
||||
## 5. 解放算力:粒子系统与视觉魔法
|
||||
|
||||
到了这一步,当你把【坐标不断重绘的动画】跟【颜色和大小变换】融合,再放进成百上千个小碎片里。这就是引爆视觉的终极杀器:**粒子系统**。
|
||||
到了这一步,当我们把“坐标系”、“动画循环”以及“颜色与形状”全部融合,并将其数量暴增到成百上千个微小碎片时,你就掌握了引爆视觉的终极杀气:**粒子系统(Particle System)**。
|
||||
|
||||
你只需要建立一个巨大的数组,里面塞满了几百个拥有独立生命值、独立初始随机速度的数字对象。每次“重绘”,让所有的点根据重力或者惯性去减速。你的浏览器里马上就能发生逼真的大爆炸或者漫天飞雪。
|
||||
其核心思路极其粗暴且有效:
|
||||
1. 建立一个巨大的数组,里面塞满了几百个独立的“粒子对象”。
|
||||
2. 每个对象拥有自己的独立生命周期(`life`)、加速度(`vx/vy`)、重力阻尼(`gravity`)。
|
||||
3. 每次 `requestAnimationFrame` 触发时,遍历更新这几百个粒子,然后渲染,最后悄悄清理掉那些“死亡”(生命值耗尽/掉出屏幕)的粒子。
|
||||
|
||||
👇 **动手点点看**:
|
||||
试试“烟花”和“鼠标轨迹”!
|
||||
你的浏览器一瞬间就能变成一台制造烟花、大雪和爆炸的梦工厂。
|
||||
|
||||
👇 点击不同的效果,调整重力与粒子数,观察它们是如何通过最简单的物理数学公式呈现出复杂的群体视觉:
|
||||
|
||||
<ParticleSystemDemo />
|
||||
|
||||
@@ -115,32 +120,35 @@
|
||||
|
||||
## 6. 守护 FPS 荣耀:如何应对高烧的 CPU?
|
||||
|
||||
让成千上万个对象在一秒内计算重画 60 遍,这是极其消耗电脑算力(CPU 和内存)的。
|
||||
很多野生小白刚做出来的游戏玩了两分钟可能风扇就起飞了。下面是真正的引擎大佬使用的降温护体绝技:
|
||||
让成千上万个对象在一秒内计算并重画 60 遍是非常消耗性能的。如果毫无章法,你的电脑风扇很快就会起飞。
|
||||
|
||||
1. **局部擦黑板(脏矩形 Dirty Rect)!** 一个角色在一望无际的草原上奔跑。你千万别每帧把整块大草原都擦了重画!角色经过哪一小块,你就用小板擦把哪里擦掉然后只补哪里的洞,这能省下几千倍的力气。
|
||||
2. **隐藏后台魔法(离屏 Canvas)!** 如果游戏背景是繁星漫天、有各种复杂绚丽的山脉。最好先偷偷在没人的后台建一个内存 Canvas 把它一次性精美地画上去。以后每秒 60 下的刷新,你直接把这幅“定格全图”通过贴图的方式贴到前端(`drawImage`)就行了。
|
||||
3. **批量洗画笔!** 如果画画时你要反复交替使用“红、蓝、红、蓝、红”这几种笔,频繁切换。可以提前把所有红色的兵全归档画完,再清空换蓝颜料画,省去了昂贵的上下文来回切换。
|
||||
以下是真正引擎大佬用来抢救帧率的“护体绝技”:
|
||||
|
||||
👇 **动手点点看**:
|
||||
先把对象数量拉满,看着网页快掉进卡顿的深渊,再依次打开右下方的绝技进行抢救。
|
||||
1. **局部擦黑板(脏矩形 Dirty Rect):**
|
||||
一个角色在宽广的草原上奔跑,你千万不要每帧去 `clearRect` 整片大草原!角色经过哪一小块,你就用“小板擦”擦掉那一块并覆盖重绘,性能立刻飙升指数倍。
|
||||
|
||||
2. **后台替身魔法(离屏 Canvas):**
|
||||
如果背景是繁星漫天、有着各种复杂绚丽的山脉,每次都实时渲染太蠢了。我们通常在内存里偷偷建一个看不见的 `<canvas>`,把它精美地画上去一次。之后的每一帧刷新中,只需要通过 `drawImage()` 将这张合成好的“静态底片”直接贴出,免去了海量的基础计算。
|
||||
|
||||
3. **批量洗画笔(Batching):**
|
||||
调色盘里从红色换到蓝色,在底层是昂贵的。如果画布上有 1000 个红色圆和 1000 个蓝色圆交叉散落。最快的方法是:先把红颜料准备好,遍历画完所有红圈,再换蓝颜料画所有蓝圈。这是著名的批量渲染(Batch Rendering)思想。
|
||||
|
||||
👇 将对象数量拉到 3000 以上,看着网页掉进卡顿的深渊,再依次打开右下方的“优化技术”开关,亲眼见证实打实的帧率抢救:
|
||||
|
||||
<PerformanceDemo />
|
||||
|
||||
---
|
||||
|
||||
## 7. 名词对照表
|
||||
## 7. 专业名词总结
|
||||
|
||||
| 术语 | 解释 |
|
||||
| 术语 | 通俗解释 |
|
||||
| --- | --- |
|
||||
| **Canvas** | Html5 提供的 2D 画布。绘制极快,但画完就变成颜料像素,不支持通过 DOM 操作内容。 |
|
||||
| **SVG** | 矢量图,放大永远不模糊,且每个图形都是独立的标签元素可以单独点击绑定事件。 |
|
||||
| **Context (ctx)** | 获取到的“2D 上下文”,可以理解为用来在这张布上调各种颜色、干各种特殊效果的“画笔”。 |
|
||||
| **requestAnimationFrame** | 浏览器内置的神级节拍器,会以显示器的刷新率(通常 60FPS)不断狂飙执行,专门用来做完美动画。 |
|
||||
| **FPS / Frame Rate** | 帧率。60 FPS 代表一秒钟内浏览器帮我们默默擦除了 60 次黑板并画了 60 副新图,这骗过了视神经,看起来极其丝滑。 |
|
||||
| **Dirty Rect / 脏矩形** | 只在画面中发生变化的微小矩形区域内进行擦除和重绘,强力保留性能。 |
|
||||
| **Offscreen Canvas** | 藏在内存里的“影子画布”,把静态且复杂的树木和山脉先画好,当作死的一张贴图重复利用。 |
|
||||
| **Canvas** | HTML5 提供的 2D 画布。绘制极快,但画完就变成颜料像素,不支持通过 DOM 操作内容。 |
|
||||
| **SVG** | 矢量图。放大永远不模糊,且每个图形都是独立的标签元素,可以轻易绑定各种 CSS 样式和交互。 |
|
||||
| **Context (ctx)** | 你申请到的那支“2D 魔法画笔”,用来调色、设定形状和绘制各种特殊效果。 |
|
||||
| **requestAnimationFrame** | 浏览器内置的神级节拍器,会严格依照显示器的刷新率执行回调,是制作丝滑动画的不二之选。 |
|
||||
| **FPS (Frame Rate)** | 帧率。60 FPS 代表一秒内浏览器帮你无缝擦除了 60 次画布并重画了 60 副新图。 |
|
||||
| **脏矩形 (Dirty Rect)** | 只在发生变化的那一点微小区域内进行精准擦除和重绘,从而强力保留性能。 |
|
||||
| **离屏 Canvas** | 藏在内存里的“影子画布”。把极度复杂但不会动的景物提前画好,以后就当死贴图拿来重复使用。 |
|
||||
|
||||
---
|
||||
|
||||
现在,不管是一把简单的魔法画笔、还是由万千雪花组成的宏大粒子系统,整个能够不断刷新重绘的数字世界引擎,都在你的掌控之中了!
|
||||
> 从一条简单的直线段,到宏大绚丽的粒子系统引擎;一切看似魔法的特效,不过是每秒 60 次的坐标计算与重绘轮回罢了。
|
||||
|
||||
Reference in New Issue
Block a user