本篇精读来自笔者代码实践,没有原文出处请谅解。
早些我们介绍过了 磁贴布局 - 功能分析 与实现,现在我们来做一个更进一步的思考,如何让磁贴布局与自由布局混合实现?
让磁贴布局与自由布局混合实现,从效果来看就是让画布同时存在磁贴与自由布局两种布局状态的组件,并且可以随时切换。接下来我们分析实现该方案的技术要点。
磁贴与自由布局的差异
磁贴布局与自由布局在交互上有很多差异,比如:
- 磁贴布局不能重叠,自由布局可以重叠。
- 磁贴布局可以向上方吸引,自由布局不会被吸引。
- 磁贴布局不存在自动吸附概念,但自由布局可以支持对齐,吸附等功能。
这些交互时差异都容易在运行时分开处理弥补,真正需要从顶层设计的是 单位的差异。
自由布局因为位置固定,所以一般以像素描述位置;磁贴布局因为宽高是按照比例来的,往往以不带单位的 {w:1, h:2}
等相对数字描述位置,在渲染时再根据当前视窗大小缩放。
但在磁贴与自由混合的情况下,一个组件的布局选择磁贴还是自由可以由父容器来决定,或者自身来决定,这就引发了一个挑战:
一个组件的状态可能随时被切换到磁贴或自由,同时混用两种单位论上也可以实现,但计算成本比较高,所以最好采用一种单位来存储与计算,那么 同时适配磁贴与自由的单位就是像素。
用像素实现磁贴布局
因为自由布局使用像素计算非常容易,所以我们只讲磁贴布局下如何用像素计算。
像素模式下所有磁贴组件的位置、大小都是像素:
代码语言:javascript复制{
"layoutMode": "grid",
"x": 100,
"y": 100,
"width": 150,
"height": 150
}
如上所示,磁贴模式的组件与自由布局组件的差异仅在 layoutMode
值的区别,位置描述是完全一样的。
为了让磁贴布局组件可以适配屏幕大小缩放,需要存储画布根节点宽度 rootWidth
,比如宽度为 150 的组件是在画布 rootWidth
为 1000 时保存下来的,那么在画布宽度为 2000 的屏幕尺寸打开时,组件宽度就要放大到 300.
自由布局对齐磁贴布局
自由布局在大部分情况下是无法对齐磁贴布局的,因为即便我们将这两种布局的位置统一使用像素描述,但磁贴布局还是免不了会在不同尺寸的屏幕间缩放,也就是磁贴布局组件的位置是不固定的,而自由布局组件的位置是固定的,所以自由布局组件某条边对齐了磁贴布局的组件,也只在当前画布宽度下生效,一旦换一个尺寸屏幕就会产生偏移。
一种维持自由与磁贴组件相对位置的办法是 “整体随访”,即画布中所有组件位置都按照画布大小缩放,实现该方案有两种技术路线:
- scale 画布整体缩放。
- 仅位置、宽高的缩放。
第一种缩放方式会同时缩放组件内字体、图表等元素的大小,而第二种方案不会,我们可以根据实际场景灵活选择来实现,但两种方式都可以达到自由布局与磁贴布局稳定对齐的效果。
总结
自由与磁贴混合布局模式下,还有更多值得我们思考的地方,比如:
- 是否允许磁贴布局与自由布局的组件产生碰撞。
- 怎么设计才能在同时多选了磁贴与自由布局组件时,批量拖动。
- 磁贴布局组件在拖入更小的容器时,宽度按照画布尺寸缩放,还是按照该容器尺寸缩放。
- 自由布局成组模式下,组内组件如何支持磁贴布局。
甚至,能否将浏览器最早支持的流式布局模式一起加入混合?混合布局模式还有很多值得深入思考的地方。
讨论地址是:精读《自由 磁贴混合布局》· Issue #488 · dt-fe/weekly