Jsdom: offsetWidth、offsetHeight、offsetTop 和 offsetLeft

创建于 2011-02-01  ·  32评论  ·  资料来源: jsdom/jsdom

我正在尝试为 HighCharts 实现服务器端渲染器。 除了生成的 SVG 标记在整个地方缺少 x、y、宽度和高度值之外,一切似乎都运行良好。 通过一些调试,我相信我已经将问题确定为每个元素的 offsetWidth、offsetHeight、offsetTop 和 offsetLeft 都未定义。

这些属性是否计划包含在未来版本中? 另外,有没有我可以暂时实施的解决方法?

css feature layout needs tests

最有用的评论

我使用此代码段作为支持,这对我的情况有效。 请记住,这远非正确的实现。 请注意, window应该是您的document.parentWindow

如果您需要更好的实现,请使用规范扩展代码:
http://dev.w3.org/csswg/cssom-view/#dom -htmlelement-offsetleft

Object.defineProperties(window.HTMLElement.prototype, {
  offsetLeft: {
    get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
  },
  offsetTop: {
    get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
  },
  offsetHeight: {
    get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
  },
  offsetWidth: {
    get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
  }
});

所有32条评论

我认为需要实施http://www.w3.org/TR/cssom-view/

我们已经开始集成 cssom,它应该可以解决一些 SVG 问题。

如果我们可以访问 offset* 属性,那确实很棒,因为与画布相关的项目需要这些属性。

这个问题的进展如何? 我也很欣赏这样的功能,用于使用 Highcharts 进行后端下垂渲染。

我也很想拥有这个:)

各位大侠有空帮忙吗? 就我个人而言,我不需要 svg 1.1,但如果你们也有足够的热情来处理它,我愿意帮助实现它。

@tmpvar :我想提供帮助,但我对那些服务器端 JS 东西
也许你可以暗示我从哪里开始,我可以尽我最大的努力去做一些事情:)

我对 SVG 1.1 也很感兴趣,可以在服务器上启用 highcharts。 我想提供帮助,但首先我需要熟悉 SVG 1.0 及其当前在 jsdom 中的实现,这可能需要一段时间;)

我认为这里的第一步是获取测试套件的副本(http://www.w3.org/Graphics/SVG/WG/wiki/Test_Suite_Overview)并将其转换为无头(这可能是一项艰巨的任务)

然后我们可以添加一个level2/svg.js并开始实施。

我可能最终会解决这个问题,但它现在在我的 jsdom 优先级列表中并不高。

@href svg 1.0 实现非常简单。 它通过了level1/core的测试,但并没有真正实现任何特定于 svg 的内容。

我认为, getBoundingCLientRect 没有正确实现。

我有这个代码来计算特定的 svg 元素:

var html = '<!DOCTYPE html><html><head><title></title></head><body style="margin: 0; padding: 0;"><svg id="svg" xmlns="http://www.w3.org/2000/svg" version="1.1" style="margin: 0; padding: 0;"><rect style="" x="10" y="10" width="100" height="100" rx="0" ry="0"/></svg></body></html>';

        jsdom.env({
            html : html,
            src: [jquery],
            done: function (errors, window) {
                var $ = window.$;
                var clientBox = $("#svg").find(type)[0].getBoundingClientRect();
                console.log(clientBox);
            }
        });

结果是:

{ bottom: 0, height: 0, left: 0, right: 0, top: 0, width: 0 }

但是,如果我在网络浏览器中测试相同的 html,结果是这样的:

{ bottom: 110, height: 100, left: 10, right: 110, top: 10, width: 100 }

@throrin19 :通读#653。

那么是不可能实现的吗? 到目前为止,我设法通过 phantomJS 绕过了这个问题,但它非常慢,如果我有一个很大的 SVG,它就会崩溃。

我的意思是,这并非不可能,但我们必须编写一个完整的布局引擎,而没有人有时间这样做。

我想过,但后来我的大脑痉挛,我不得不走开。

是否有可以遵循的酸以外的测试?

+1 发现这是一个非常理想的功能

我使用此代码段作为支持,这对我的情况有效。 请记住,这远非正确的实现。 请注意, window应该是您的document.parentWindow

如果您需要更好的实现,请使用规范扩展代码:
http://dev.w3.org/csswg/cssom-view/#dom -htmlelement-offsetleft

Object.defineProperties(window.HTMLElement.prototype, {
  offsetLeft: {
    get: function() { return parseFloat(window.getComputedStyle(this).marginLeft) || 0; }
  },
  offsetTop: {
    get: function() { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
  },
  offsetHeight: {
    get: function() { return parseFloat(window.getComputedStyle(this).height) || 0; }
  },
  offsetWidth: {
    get: function() { return parseFloat(window.getComputedStyle(this).width) || 0; }
  }
});

有没有其他人通过 tobyhinloopen 的建议获得成功?

@tobyhinloopen :我的图形背景、轴和标签显示出来(尽管以倾斜的方式显示),但其余部分仍然很混乱。 你能得到一个完整的图表吗?

我有一个不同的用例,其中我建议的实现有效。 如果它不适合您,请扩展它。 可能的 OffsetHeight/width 也必须包括填充。 我会建议一些 hacky hotfixing 来使它工作,因为一个完美的实现很难实现。

@tobyhinloopen提出的解决方案看起来不错,但是当我使用它时,我得到“无法改进属性 offsetLeft”

@zallek我想你已经有 offsetLeft 支持了 :) window.HTMLElement.prototype.offsetLeft返回什么? 如果它不是未定义的,我的解决方案将不起作用

只想说谢谢@tobyhinloopen ,您的解决方案对我非常有用。 :)

@tobyhinloopen非常感谢您发布解决方案! 只要我使用一个变量来设置 offset 的值并排除this它就非常有用并且确实有效。 this未定义,考虑到上下文不是实际的类,这是有道理的。 这是你所期望的吗?

@jordantomax this 在调用函数时绑定到元素,而不是在定义函数时。 当您从任何 html 元素调用它时,'this' 应该是该元素。

如果没有,我喜欢看一个例子。

@tobyhinloopen感谢您的快速回复。 这就是我所期望的。 当我尝试使用真实的浏览器环境在 codeandbox 中重现我的问题时,它可以正常工作。 但是在使用 jest 时,我看到this未定义。 我创建了一个小示例 repo 来向您展示我正在经历的事情,也许我的设置是错误的。

https://github.com/jordantomax/jest-htmlelement-prototype-sandbox

相关的,我也遇到scrollIntoView使用 jest 和 jsdom 覆盖像

非常感谢你的帮助!

我认为这是因为您使用get: () => {} - () => {}函数语法与您的this混淆。 如果您改用get() {} (推荐)或get: function() {} (替代),它将起作用。 @jordantomax

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#No_separate_this

您还可以在测试套件的it / describe使用=> 。 我不知道 JEST,但在 MOCHA 中不建议这样做,因为this it / test / describe有各种如果使用箭头函数,则无法访问实用程序。 例如,摩卡咖啡有this.slow()this.timeout(4000)等。

https://mochajs.org/#arrow -functions

相关的,我也遇到了使用 jest 和 jsdom 覆盖 scrollIntoView 等方法的问题。 有推荐的方法吗?

通常在 MDN 上有某种 polyfill 可用。 否则,只需尝试以适合您需求的方式基于规范来实现它。 如果一切都失败了,只需使用不同的测试环境。 JSdom 有其一席之地,但在某些时候,您可能需要考虑使用真正的浏览器。 许多测试环境允许在真实浏览器中进行测试(甚至同时进行多个),同时还可以向您的开发机器实时报告。 IIRC Karma 这样做 -> https://karma-runner.github.io/latest/index.html

我在我的机器上同时打开了多个浏览器(firefox chrome safari Internet Explorer edge + 模拟器中的移动浏览器),它们都使用 Karma + Mocha 实时报告。

@tobyhinloopen没错,您在所有帐户上! 谢谢!! 我仍然有点不清楚为什么getComputedStyle是必要的,是否有可能在给定该方法的情况下编写一个 setter。 对我来说,这似乎有效:

Object.defineProperties(window.HTMLElement.prototype, {
  offsetTop: {
    get () {
      return this.marginTop
    },
    set (offset) {
      this.marginTop = offset
    }
  }
})

再次感谢🙏

@jordantomax getComputedStyle获取所有 CSS 属性的实际计算样式,无论它在哪里应用(样式表、 style属性或来自 JS)。 我不确定this.marginTop是否也这样做,但我猜是这样(但显然仅适用于边距,不适用于所有 CSS 道具)

@tobyhinloopen啊,明白了。 谢谢!

谢谢@tobyhinloopen 。 我使用更短的版本。 我认为getComputedStyle并不是真正需要的,因为我个人从不向我的单元测试添加任何 css,除非它是内联的,这就是为什么.style足够好且更快的原因。

Object.defineProperties(window.HTMLElement.prototype, {
  offsetLeft: {
    get () { return parseFloat(this.style.marginLeft) || 0 }
  },
  offsetTop: {
    get () { return parseFloat(this.style.marginTop) || 0 }
  },
  offsetHeight: {
    get () { return parseFloat(this.style.height) || 0 }
  },
  offsetWidth: {
    get () { return parseFloat(this.style.width) || 0 }
  }
})

这是否已修复,我得到 offsetWidth = 0

   const dom = new JSDOM(`<!DOCTYPE html><body></body>`);
    let document = dom.window.document
    let span = document.createElement("span");
    span.innerHtml = 'test
    span.style.fontSize = 150 + 'px';
    span.style.fontFamily = 'Arial'
    document.body.appendChild(span)
    console.log(span.offsetWidth) // 0

这是否已修复,我得到 offsetWidth = 0

@petran期望 jsdom 计算 SPAN 的宽度是不现实的,因为它需要了解字体的大小和所有继承的 CSS 属性。 我认为这不是 JSDOM 的目标。 如果您想要更准确地模拟浏览器,请考虑使用实际浏览器。

此页面是否有帮助?
0 / 5 - 0 等级