我正在尝试实现我自己的基于流的小布局引擎。它应该模仿 HTML 布局的行为,但只模仿渲染树,而不是 DOM 部分。渲染树中元素的基类是 Node
类。它有:
- 指向 DOM 中元素的链接(对于那些使用该库构建渲染树的元素)
- 对它的父级的引用(这是一个
ContainerNode
实例或无,见后文) - 对布局选项的引用
- X、Y、宽度和高度(在 中计算
layout()
大小之后,在 中计算compute_size()
位置。虽然位置由layout()
父级的方法定义,但大小由选项引用定义)。
它的方法是:
reflow()
调用compute_size()
和layout()
compute_size()
用于计算节点的宽度和高度。layout()
它旨在定位节点的子节点,而不是节点本身。paint()
这是由图书馆的用户覆盖的。
该类ContainerNode
正在实现子节点的处理。它提供了一个名为 的新方法add_node()
,它将传递的节点添加到容器子容器中。该函数还接受默认为 False 的参数force,因为允许容器拒绝传递的节点,但force设置为 True。
这两个类不实现任何布局算法。我的目标是为不同类型的布局创建不同的类(在 CSS 中,主要由display
属性定义)。昨晚我对文本布局进行了一些测试,您可以从pastebin.com找到我的代码(需要 pygame)。您可以将其保存到 python 脚本文件并像这样调用它:
python text_test block -c -f "Georgia" -s 15
注意:代码真的很糟糕。我很欣赏对深层误解的评论。
上面提到的代码中的类InlineNodeRow
实际上代表了我的想法,即如何实现布局类似于display:inline
属性的节点(结合NodeBox
)。
问题 1 - 内联文本的边距和填充
回到我在库中的当前方法:文本中的单个单词也将表示为单个节点(就像上面的代码一样)。<span>
但我注意到标签中的边距和填充有两件事。
- 设置边距时,只考虑水平边距,忽略垂直边距。
- 填充溢出父容器并且不会“移动”跨度节点。
请参阅http://jsfiddle.net/CeRkT/1/。
我在这里看到了问题:当我想计算 的大小时InlineNodeBox
,我向文本节点询问它的大小并将其添加到节点的大小中。但是文本节点的大小包括它的边距和填充,这不包括在 HTML 渲染器的定位中。因此下面的代码是不正确的:
def compute_size(self):
# Propagates the computation to the child-nodes.
super(InlineNodeBox, self).compute_size()
self.w = 0
self.h = 0
for node in self.nodes:
self.w += node.w
if self.h < node.h:
self.h = node.h
node.w
将包括边距和填充。我看到的下一个问题是,为了正确布置文本节点,我想将它们拆分TextNode
为每个单词的单个 s,但是边距和填充随后将应用于所有这些节点,而 HTML 中的边距和填充<span>
仅对标签。
我认为我目前将每个单词放入单独节点的想法并不理想。浏览器如何构建他们的渲染树,或者你有更好的主意吗?
问题 2 - 单词太长,放到下一行。
该类InlineNodeBox
目前只组织一个单行。在上面的代码示例中,我InlineNodeBox
从NodeBox
前者拒绝接受节点(这意味着它不适合)中创建了一个新的。我不能用我目前的方法做到这一点,因为我不想重新重建渲染树。当一个节点被接受一次,但超过InlineNodeBox
下一次回流时,我如何正确地将单词放入下一行(假设我保持InlineNodeBox
类只组织单行节点的想法)?
我真的希望这一切都有意义。如果您不理解我的概念,请随时询问。我也非常愿意接受对其他概念、资源链接、文档、出版物等的批评和想法。