这篇博客主要是熟悉浏览器的大致工作流程(不涉及代码,代码在最后的链接里)
如上图所示:
- url回车后,先是解析http
- 再解析html生成dom树
- 再解析css
- 再依据dom和css,进行layout获取position
- 最后进行render 绘制bitmap
第一步(解析http)
response:
要想解析http 报文,我们可以利用状态机,使用多个状态来区分报文里的每个部分
比如设置一个 WAITTING_STATUS_LINE 状态,在第一个’\n’之前我们都可以视为在 WAITTING_STATUS_LINE 状态,’\n’之后用 WAITTING_STATUS_LINE_END 表示status line 的部分结束,以此类推使用各个状态来筛选响应报文的内容
这样我们就可以拿到response body 里面的html文本
第二步,解析html生成dom树
要想利用html文本最后返回一颗dom树,还是创建状态机来实现,其实html规范里面已经定义了很多很多个状态了,我们只选取一些 状态来模拟一下大致过程,'<‘表示 tagOpen ,在tagOpen之后就是tagName如果后面有个空格后面又有字符串那就是 attributeName 紧跟着’=’,后面就是 attributeValue,简而言之就是分析每一个token,找到每一个token所表达的语义
最后获得多个平级的对象,这个对象如下图结构
接下来就是如何把同级对象构建成一颗dom树
- 从标签构建DOM树的基本技巧是使用栈
- 遇到开始标签时创建元素并入栈,遇到结束标签时出栈
- 自封闭节点可视为入栈后立刻出栈
- 任何元素的父元素是它入栈前的栈顶
如此操作之后会获得如下图包含children的一个树结构(ast)
第三步 给每个dom树节点匹配对应的css rules
首先利用css库将<style>里的css表达式转换成css rules(其实现方式也是利用状态机生成ast),rule结构如下,declartions里面包含了css属性名和属性值,
然后根据当前的css rule的 selectors以及它的parent 的selectors 和第二步我们获得dom树进行比对,得到当前的css rule 应该添加到哪一个元素上,把这些css rule 添加到元素的computedStyle属性上
第四步 进行layout 计算每个元素在坐标轴上的位置
首先我们需要抽象出一个坐标轴
主轴:mainSize, mainStart, mainEnd, mainSign, mainBase,
交叉轴: crossSize, crossStart, crossEnd, crossSign, crossBase
例如flex布局中的 flexDirection === ‘row’ ,那么上面的变量就是如此:
mainSize = 'width'; mainStart = 'left'; mainEnd = 'right'; mainSign = +1; mainBase = 0; crossSize = 'height'; crossStart = 'top'; crossEnd = 'bottom'
然后把每个元素放入一行(行可以用数组实现)根据主轴的尺寸和css规则判断换不换行,再计算交叉轴的高度(取每一行的元素的最高交叉轴尺寸),获得每个元素在坐标轴上的坐标表示,如element[mainSize],element[crossSize]的具体数值
第五步根据坐标点render进行绘制
这里使用images库( Node.js轻量级跨平台图像编解码库 ),把上面的元素传入images的绘制方法就可以了,循环调用子元素的绘制方法完成dom树的 绘制(这里没有实现文字的绘制和图层的一些处理)
完整的代码地址: https://github.com/dz333333/Frontend-01-Template/tree/master/week07/layout