在極客時(shí)間的《重學(xué)前端》的瀏覽器工作原理唐础,最后 winter 提到了可以試著用 canvas 來(lái)實(shí)現(xiàn)一個(gè)玩具瀏覽器揽思。所以了解下 canvas玩荠。
其實(shí)關(guān)于 canvas 的教學(xué)文章很多辛块,特別是 MDN 中的 canvas 教程非常好存捺。所以我這里寫個(gè)基礎(chǔ)教程意義也不大槐沼。簡(jiǎn)單說下我理解的 canvas。
我理解的 canvas
canvas 說簡(jiǎn)單也簡(jiǎn)單捌治,說復(fù)雜則非常復(fù)雜岗钩。
簡(jiǎn)單是因?yàn)?canvas 的基礎(chǔ)知識(shí)就是基于 <canvas>
標(biāo)簽元素的 context
上下文來(lái)繪制圖形,具體有哪些繪制方法很多教程和書上都有介紹肖油。
復(fù)雜則是因?yàn)?canvas 可以實(shí)現(xiàn)非常復(fù)雜的功能兼吓。如復(fù)雜圖像繪制、圖像效果處理森枪、圖像特效提價(jià)视搏、動(dòng)畫,甚游戲等县袱,具體可以看下《HTML5 Canvas核心技術(shù)》一書了解 canvas 的強(qiáng)大之處浑娜。
對(duì)于我而言只是想實(shí)現(xiàn)簡(jiǎn)單的 2d 頁(yè)面效果,所以就簡(jiǎn)單學(xué)習(xí)了一下 canvas 繪制功能式散。大概有以下幾點(diǎn):
- canvas 基本用法
const canvas = document.getElementById('page');
const ctx = canvas.getContext('2d');
- 繪制圖形:矩形筋遭、弧形、路徑暴拄、文本漓滔、圖片
- 圖形樣式設(shè)置:顏色、邊框乖篷、寬高响驴、位置
- 圖形事件:鼠標(biāo)事件、鍵盤事件
其實(shí)之前用 canvas 實(shí)現(xiàn)過折線圖表單來(lái)呈現(xiàn)數(shù)據(jù)撕蔼,使用的是 zrender 庫(kù)踏施。具體文章可以看下我之前寫的使用ZRender實(shí)現(xiàn)護(hù)理單折線圖功能一文石蔗。
關(guān)于玩具瀏覽器的實(shí)現(xiàn)思路
之前的文章中聊到過瀏覽器的工作原理,那么如何使用 canvas 實(shí)現(xiàn)一個(gè)玩具瀏覽器畅形,我的思路是這樣的:
結(jié)構(gòu):
- 瀏覽器由一個(gè)文本框和一個(gè) canvas 構(gòu)成养距。
<input />
<canvas id="browser" width="600" height="500"></canvas>
獲取資源行為:
- 在文本框中輸入 URL,點(diǎn)擊回車鍵執(zhí)行訪問 URL 行為日熬。
- 通過 ajax 獲取到數(shù)據(jù)棍厌,響應(yīng)內(nèi)容應(yīng)該是一段 HTML 代碼。
- 解析 HTML 代碼竖席,如果遇到外部 URL 資源需要另行獲取耘纱。
解析代碼行為:
- 將 HTML 代碼解析成一個(gè) DOM 樹對(duì)象。
- 解析 CSS 的代碼并根據(jù) DOM 樹對(duì)象創(chuàng)建 CSSOM 樹對(duì)象毕荐,將 DOM 元素和 CSSOM 一一對(duì)應(yīng)束析。
渲染行為:
- 將 CSSOM 對(duì)象中的 CSS 規(guī)則寫到 DOM 樹對(duì)象中,構(gòu)成 Render 樹對(duì)象憎亚。
- 自上而下遍歷 Render 樹對(duì)象员寇,根據(jù)元素的樣式計(jì)算元素的寬高和位置存儲(chǔ)在 Render 。
- 知道了元素的內(nèi)容第美、寬高蝶锋、位置后,就可以遍歷 Render 樹對(duì)象用 canvas API 來(lái)繪制整個(gè)頁(yè)面了什往。
- 使用 canvas 的事件來(lái)替代 DOM 元素的事件扳缕。
重排和重繪行為:
- 如果元素尺寸的變化梯刚,需要重新計(jì)算整個(gè)頁(yè)面元素位置排版逗威,清空畫布重新繪制整個(gè)頁(yè)面挽放。
- 如果是元素背景顏色的變化纤虽,直接使用 canvas 重新繪制元素。
難點(diǎn)
- 解析 HTML 和 CSS 為 DOM 樹對(duì)象和 CSSOM 樹對(duì)象硅瞧。
- 流式計(jì)算元素位置冠跷。
- 遍歷 Render 樹對(duì)象中的元素信息和樣式信息計(jì)算排版信息合是。
最后
其實(shí)在 Vue.js 的 Visual DOM 中有 parseHTML 相關(guān)的代碼衫樊,原理上也差不多。的確可以試著去實(shí)現(xiàn)以下 canvas 版的瀏覽器利花。
以上只是我暫時(shí)的想法科侈,要真正實(shí)現(xiàn)其實(shí)還有很多問題。比如:
- input炒事、textarea 怎么實(shí)現(xiàn)
- 那么多 CSS 屬性如何涵蓋
- 瀏覽器的 HTML 容錯(cuò)機(jī)制如何實(shí)現(xiàn)
- 瀏覽器頁(yè)面滾動(dòng)如何實(shí)現(xiàn)
- 如何處理 HTML 中的外部 URL 資源
- 頁(yè)面中的復(fù)雜組件怎么實(shí)現(xiàn)
所以臀栈,其實(shí)一個(gè)瀏覽器可以做的東西非常多。正如 winter 所說:
一旦你做到了挠乳,收益會(huì)非常大权薯。
如果對(duì)開發(fā) canvas 的瀏覽器有興趣姑躲,也可以想想怎么來(lái)實(shí)現(xiàn)。也歡迎留言討論盟蚣。
參考資料
- 重學(xué)前端 | 極客時(shí)間
- 《JavaScript 高級(jí)程序設(shè)計(jì)》
- 《JavaScript 權(quán)威指南》
- 《HTML5 Canvas核心技術(shù)》
- Canvas教程 - Web API 接口參考 | MDN