好的。所以这就是我理解你想用我自己的话做的事情。
循环遍历所有 DOM 元素,将绝对尺寸(即以像素表示的高度/宽度)转换为相对尺寸(即以百分比表示的高度/宽度)。这应该注意维度是使用 CSS 还是 HTML 属性设置的,以便可用于 SVG 元素。
话虽如此,有一个主要限制:如果要将绝对尺寸转换为使用<x>
作为根元素的相对尺寸,则<x>
必须具有绝对尺寸。否则,容器内的相对尺寸将根据其内容而不是 parent 的整体尺寸来改变尺寸<x>
。
有了这个规定,你要问的就很容易了。这是需要使用的算法。
- 开始于
<body>
- 给出
<body>
固定尺寸
- 遍历 DOM 树,
<body>
为每个元素执行以下操作
- 获取元素的尺寸
- 获取父母的尺寸
- 转换为相对尺寸(即宽度/父宽度)。
- 应用相对尺寸
为了测试我的代码,我使用了以下 HTML。它既有您包含的代码,也有一个子元素大于其父元素的实例。这是我确定为要测试的边界条件的一种情况。
<div style="width:100%;height:800px">
<svg width="150" height="200" style="background: red;">
<rect width="30" height="50" x="34" y="24"/>
</svg>
<div style="background: green; width: 50px; height: 50px;">
<p style="background: teal; width: 100px; height: 20px;">Content</p>
</div>
</div>
这是 JavaScript。它得到了很好的评论,并提供了不错的控制台输出。对于生产代码,我建议您删除控制台日志记录。
请记住,代码不会立即执行,而是延迟 2 秒。这样你就可以看到 DOM 在被修改之前的样子。
对于那些不知道以下代码的人,a
如果它存在且不为假,则将返回b
。
foo = a || b;
我们可以像下面两个中的一个一样重写,但这更简洁。
foo = a ? a : b;
if(a)
foo = a
else
foo = b
这是一个jsFiddle。
还有代码!
/** convertToRelative
* Convert absolute width/height to relative. Should work for
* Both HTML and SVG objects. Tries to use CSS attributes, falls
* back on HTML attributes.
*/
function convertToRelative(element) {
// Get Element and Parent
element = $(element);
parent = element.parent();
// If there is no valid with, we need to use attributes
var useAttr = !element.width();
// Get dimensions from css or attributes
var width = element.width() || element.attr('width');
var height = element.height() || element.attr('height');
var pWidth = parent.width() || parent.attr('width');
var pHeight = parent.height() || parent.attr('height');
// Find relative dimensions
var relWidth = (width / pWidth) * 100.0;
var relHeight = (height / pHeight) * 100.0;
// Log info
console.log(element);
console.log("1: "+ parent.height() +", 2: "+ parent.attr('height'));
console.log("Width: "+ width +", Height: "+ height);
console.log("PWidth: "+ pWidth +", pHeight: "+ pHeight);
console.log("relWidth: "+ relWidth +", relHeight: "+ relHeight);
// Clear current stylings
element.removeAttr('width');
element.removeAttr('height');
// Apply relative dimensions
if (useAttr) {
element.attr('width', relWidth +'%');
element.attr('height', relHeight +'%');
} else {
element.width(relWidth +"%");
element.height(relHeight +"%");
}
}
/** walk
* Walk through a DOM element and all its sub elements running
* the convertToRelative function to convert absolute positions
* to relative positions.
* DOES NOT CONVERT THE FIRST ELEMENT, ONLY CHILDREN.
*/
function walk(element) {
$(element).children().each(function() {
convertToRelative(this);
walk(this);
});
}
/** fixBody
* In order to play with relative dimensions for children of the
* body, we need to fix the dimensions of the body. Otherwise it
* will resize as we begin to use relative dimensions.
*/
function fixBody() {
$('body').css('width', $('body').width() +"px");
$('body').css('height', $('body').height() +"px");
}
// Walk the body and all children on a 2 second delay.
setTimeout(function() {
console.log('Running Conversion');
fixBody()
walk('body');
console.log('Conversion Finished');
}, 2000);
如果这不是您想要的,或者您遇到问题,请告诉我!
对于您的问题
可能发生的常见陷阱是什么?
最常见的陷阱将是不正确的转换。转换中会出现问题,生成的 DOM 看起来与输入完全不同。
可能有些标签没有设置宽度或高度,例如 svg:g。然后是非标准尺寸定义,例如 svg:circle 或您一开始没有考虑的属性,例如 svg:texts dy。
有些标签没有width
/height
元素。但是,使用 jQuery 应该会给我们在这个部门更多的健壮性。我没有过多地使用 jQuery 和 SVG,但是如果我们在更晦涩的元素上遇到任何问题,可以使用一个插件来提供支持。
有没有办法对大量回流对性能造成的影响做出有根据的猜测?
我相信这段代码会在O(m * n)
Wherem = delay for a single reflow
和n = number of nodes
. 回流应该有一个相当一致的变化,因为我们在最小元素之前转换了最大的元素。但我可能在最后一个陈述中被证明是错误的。
还有什么?