使用 canvas 实现玩具浏览器的学习思考

在极客时间的《重学前端》的浏览器工作原理,最后 winter 提到了可以试着用 canvas 来实现一个玩具浏览器。所以了解下 canvas。

其实关于 canvas 的教学文章很多,特别是 MDN 中的 canvas 教程非常好。所以我这里写个基础教程意义也不大。简单说下我理解的 canvas。

我理解的 canvas

canvas 说简单也简单,说复杂则非常复杂。
简单是因为 canvas 的基础知识就是基于 标签元素的 context 上下文来绘制图形,具体有哪些绘制方法很多教程和书上都有介绍。
复杂则是因为 canvas 可以实现非常复杂的功能。如复杂图像绘制、图像效果处理、图像特效提价、动画,甚游戏等,具体可以看下《HTML5 Canvas核心技术》一书了解 canvas 的强大之处。

对于我而言只是想实现简单的 2d 页面效果,所以就简单学习了一下 canvas 绘制功能。大概有以下几点:

  • canvas 基本用法
const canvas = document.getElementById('page');
const ctx = canvas.getContext('2d');
  • 绘制图形:矩形、弧形、路径、文本、图片
  • 图形样式设置:颜色、边框、宽高、位置
  • 图形事件:鼠标事件、键盘事件

其实之前用 canvas 实现过折线图表单来呈现数据,使用的是 zrender 库。具体文章可以看下我之前写的使用ZRender实现护理单折线图功能一文。

关于玩具浏览器的实现思路

之前的文章中聊到过浏览器的工作原理,那么如何使用 canvas 实现一个玩具浏览器,我的思路是这样的:

结构:

  1. 浏览器由一个文本框和一个 canvas 构成。


获取资源行为:

  1. 在文本框中输入 URL,点击回车键执行访问 URL 行为。
  2. 通过 ajax 获取到数据,响应内容应该是一段 HTML 代码。
  3. 解析 HTML 代码,如果遇到外部 URL 资源需要另行获取。

解析代码行为:

  1. 将 HTML 代码解析成一个 DOM 树对象。
  2. 解析 CSS 的代码并根据 DOM 树对象创建 CSSOM 树对象,将 DOM 元素和 CSSOM 一一对应。

渲染行为:

  1. 将 CSSOM 对象中的 CSS 规则写到 DOM 树对象中,构成 Render 树对象。
  2. 自上而下遍历 Render 树对象,根据元素的样式计算元素的宽高和位置存储在 Render 。
  3. 知道了元素的内容、宽高、位置后,就可以遍历 Render 树对象用 canvas API 来绘制整个页面了。
  4. 使用 canvas 的事件来替代 DOM 元素的事件。

重排和重绘行为:

  1. 如果元素尺寸的变化,需要重新计算整个页面元素位置排版,清空画布重新绘制整个页面。
  2. 如果是元素背景颜色的变化,直接使用 canvas 重新绘制元素。

难点

  • 解析 HTML 和 CSS 为 DOM 树对象和 CSSOM 树对象。
  • 流式计算元素位置。
  • 遍历 Render 树对象中的元素信息和样式信息计算排版信息。

最后

其实在 Vue.js 的 Visual DOM 中有 parseHTML 相关的代码,原理上也差不多。的确可以试着去实现以下 canvas 版的浏览器。

以上只是我暂时的想法,要真正实现其实还有很多问题。比如:

  • input、textarea 怎么实现
  • 那么多 CSS 属性如何涵盖
  • 浏览器的 HTML 容错机制如何实现
  • 浏览器页面滚动如何实现
  • 如何处理 HTML 中的外部 URL 资源
  • 页面中的复杂组件怎么实现

所以,其实一个浏览器可以做的东西非常多。正如 winter 所说:

一旦你做到了,收益会非常大。

如果对开发 canvas 的浏览器有兴趣,也可以想想怎么来实现。也欢迎留言讨论。

参考资料

  • 重学前端 | 极客时间
  • 《JavaScript 高级程序设计》
  • 《JavaScript 权威指南》
  • 《HTML5 Canvas核心技术》
  • Canvas教程 - Web API 接口参考 | MDN

你可能感兴趣的:(使用 canvas 实现玩具浏览器的学习思考)