Jsdom: offsetWidth, offsetHeight, offsetTop und offsetLeft

Erstellt am 1. Feb. 2011  ·  32Kommentare  ·  Quelle: jsdom/jsdom

Ich versuche, einen serverseitigen Renderer für HighCharts zu implementieren. Alles scheint gut zu funktionieren, außer dass im resultierenden SVG-Markup überall die Werte für x, y, Breite und Höhe fehlen. Durch einige Debugging glaube ich, dass ich das Problem auf die Tatsache hingewiesen habe, dass offsetWidth, offsetHeight, offsetTop und offsetLeft für jedes Element nicht definiert sind.

Sollen diese Eigenschaften in einer zukünftigen Version enthalten sein? Gibt es auch eine Problemumgehung, die ich vorerst implementieren kann?

css feature layout needs tests

Hilfreichster Kommentar

Ich verwende dieses Snippet zur Unterstützung, was für meinen Fall funktioniert. Denken Sie daran, dass es weit von einer ordnungsgemäßen Implementierung entfernt ist. Beachten Sie, dass window Ihr document.parentWindow .

Wenn Sie eine bessere Implementierung benötigen, erweitern Sie den Code mit der Spezifikation:
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; }
  }
});

Alle 32 Kommentare

Ich denke, http://www.w3.org/TR/cssom-view/ müsste implementiert werden.

Wir haben mit der Integration von CSS begonnen, was einige der SVG-Probleme lösen sollte.

Es wäre in der Tat großartig, wenn wir auf die offset*-Eigenschaften zugreifen könnten, die für ein Canvas-bezogenes Projekt benötigt würden.

Wie ist der Fortschritt in diesem Thema? Ich würde mich auch über eine solche Funktion für das Backend-Sag-Rendering mit Highcharts freuen.

Das hätte ich auch gerne :)

Haben Sie irgendwelche Ersatzzyklen, die Ihnen helfen können? Persönlich brauche ich svg 1.1 nicht, aber ich wäre bereit zu helfen, es zu landen, wenn ihr Jungs genug brennt, um auch daran zu arbeiten.

@tmpvar : Ich würde gerne helfen, aber ich bin ziemlich neu in diesem serverseitigen JS-Zeug.
Vielleicht können Sie mir einen Tipp geben, wo ich anfangen soll und ich könnte mein Bestes geben, um etwas in Gang zu bringen :)

Ich interessiere mich auch sehr für SVG 1.1, um Highcharts auf dem Server zu aktivieren. Ich würde gerne Hilfe anbieten, aber zuerst muss ich mich mit SVG 1.0 und seiner aktuellen Implementierung in jsdom vertraut machen, was eine Weile dauern kann ;)

Ich denke, der erste Schritt hier ist, sich eine Kopie der Testsuite (http://www.w3.org/Graphics/SVG/WG/wiki/Test_Suite_Overview) zu besorgen und sie in Headless umzuwandeln (was ein ziemliches Unterfangen sein kann).

Dann können wir level2/svg.js hinzufügen und mit der Implementierung beginnen.

Ich werde wahrscheinlich irgendwann dazu kommen, aber es steht derzeit nicht ganz oben auf meiner Liste der jsdom-Prioritäten.

@href die svg 1.0-Implementierung ist ziemlich kahl. Es besteht die Tests in level1/core , implementiert jedoch nicht wirklich etwas svg-spezifisches.

Ich denke, das getBoundingCLientRect ist nicht richtig implementiert.

Ich habe diesen Code, um ein bestimmtes SVG-Element zu berechnen:

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);
            }
        });

Und das Ergebnis ist:

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

Aber wenn ich den gleichen HTML-Code im Webbrowser teste, ist das Ergebnis folgendes:

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

@throrin19 : Lies

Es ist also unmöglich zu erreichen? Bisher habe ich es geschafft, dieses Problem durch phantomJS zu umgehen, aber es ist extrem langsam und wenn ich ein großes SVG habe, stürzt es ab.

Ich meine, es ist nicht unmöglich, aber wir müssten eine ganze Layout-Engine schreiben, und niemand hatte die Zeit dafür.

Ich habe darüber nachgedacht, aber dann verkrampft sich mein Gehirn und ich muss weg.

Gibt es Tests über Säure hinaus, die befolgt werden könnten?

+1 dafür, dass dies eine sehr wünschenswerte Funktion ist

Ich verwende dieses Snippet zur Unterstützung, was für meinen Fall funktioniert. Denken Sie daran, dass es weit von einer ordnungsgemäßen Implementierung entfernt ist. Beachten Sie, dass window Ihr document.parentWindow .

Wenn Sie eine bessere Implementierung benötigen, erweitern Sie den Code mit der Spezifikation:
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; }
  }
});

Hat jemand anderes Erfolg mit dem, was Tobyhinloopen vorgeschlagen hat?

@tobyhinloopen : Mein Diagrammhintergrund, meine Achse und Beschriftungen werden

Ich hatte einen anderen Anwendungsfall, bei dem meine vorgeschlagene Implementierung funktionierte. Wenn es für Sie nicht funktioniert, verlängern Sie es. Likely OffsetHeight/width muss auch die Auffüllung enthalten. Ich würde einige hackige Hotfixes vorschlagen, damit es funktioniert, da eine perfekte Implementierung schwierig zu implementieren ist.

Die von @tobyhinloopen vorgeschlagene

@zallek Ich denke, Sie haben dann bereits offsetLeft-Unterstützung :) Was gibt window.HTMLElement.prototype.offsetLeft zurück? Wenn es alles andere als undefiniert ist, funktioniert meine Lösung nicht

Wollte mich nur bedanken

@tobyhinloopen Vielen Dank für das Posten der Lösung! Es ist sehr hilfreich und funktioniert, solange ich eine Variable verwende, um den Wert von offset festzulegen und this auszuschließen. this kommt undefiniert heraus, was sinnvoll ist, wenn man bedenkt, dass der Kontext nicht die eigentliche Klasse ist. Ist das das, was Sie erwarten?

@jordantomax dies wird beim Aufruf der Funktion an das Element gebunden, nicht beim Definieren der Funktion. 'this' sollte das Element sein, wenn Sie es von einem beliebigen HTML-Element aus aufrufen.

Wenn nicht, würde ich gerne ein Beispiel sehen.

@tobyhinloopen Danke für die schnelle Antwort. Das würde ich erwarten. Wenn ich versuche, mein Problem in Codesandbox mit einer echten Browserumgebung zu reproduzieren, funktioniert es ordnungsgemäß. Aber wenn ich Scherze verwende, sehe ich this als undefiniert. Ich habe ein kleines Beispiel-Repository erstellt, um Ihnen zu zeigen, was ich erlebe, vielleicht ist mein Setup falsch.

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

In Verbindung damit habe ich auch Probleme beim Überschreiben von Methoden wie scrollIntoView mit jest und jsdom. Gibt es eine empfohlene Vorgehensweise?

Vielen Dank für deine Hilfe!

Ich denke , es ist , weil Sie verwenden get: () => {} - Die () => {} Funktion Syntax Verwirrungen mit Ihrem this . Wenn Sie stattdessen get() {} (empfohlen) oder get: function() {} (alternativ) verwenden, funktioniert es. @jordantomax

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

Sie verwenden auch => in den it / describe 's Ihrer Testsuite. Ich kenne JEST nicht, aber in MOCHA wird es nicht empfohlen, da this in Ihrem it / test / describe alle Arten von hat Dienstprogramme, auf die Sie nicht zugreifen können, wenn Sie die Pfeilfunktionen verwenden. Zum Beispiel hat Mokka Dinge wie this.slow() , this.timeout(4000) usw.

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

In Verbindung damit habe ich auch Probleme beim Überschreiben von Methoden wie scrollIntoView mit jest und jsdom. Gibt es eine empfohlene Vorgehensweise?

Normalerweise ist auf MDN eine Art Polyfill verfügbar. Versuchen Sie andernfalls einfach, es basierend auf der Spezifikation so zu implementieren, dass es Ihren Anforderungen entspricht. Wenn alles fehlschlägt, verwenden Sie einfach eine andere Testumgebung. JSDom hat seinen Platz, aber irgendwann möchten Sie vielleicht stattdessen einen echten Browser in Betracht ziehen. Viele Testumgebungen ermöglichen das Testen in echten Browsern (auch in mehreren gleichzeitig) und melden gleichzeitig Echtzeit an Ihren Entwicklungscomputer. IIRC Karma macht das -> https://karma-runner.github.io/latest/index.html

Ich habe mehrere Browser gleichzeitig auf meinem Computer geöffnet (Firefox Chrome Safari Internet Explorer Edge + mobile in Simulatoren), und alle haben sich in Echtzeit mit Karma + Mocha gemeldet.

@tobyhinloopen Richtig bist du auf allen Konten! Dankeschön!! Mir ist immer noch ein wenig unklar, warum getComputedStyle notwendig ist und ob es möglich ist, einen Setter mit dieser Methode zu schreiben. Bei mir scheint das zu funktionieren:

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

Danke nochmal

@jordantomax getComputedStyle holt den echten berechneten Stil für alle CSS-Eigenschaften, egal wo er angewendet wurde (Stylesheet, style Attribut oder aus JS). Ich bin mir nicht sicher, ob this.marginTop dasselbe tut, aber ich denke, es tut es (aber natürlich nur für den Rand, nicht für alle CSS-Requisiten)

@tobyhinloopen Ah, verstanden. Dankeschön!

Danke @tobyhinloopen . Ich verwende eine noch kürzere Version. Ich denke, getComputedStyle wird nicht wirklich benötigt, da ich persönlich nie CSS zu meinen Unit-Tests hinzufüge, es sei denn, es ist Inline, weshalb .style gut genug und schneller ist.

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 }
  }
})

Wurde dies behoben, erhalte ich 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

Wurde dies behoben, erhalte ich offsetWidth = 0

@petran Es ist nicht realistisch zu erwarten, dass jsdom die Breite Ihres SPAN berechnet, da dies die Kenntnis der Größe Ihrer Schriftart und aller geerbten CSS-Eigenschaften erfordert. Ich glaube nicht, dass das das Ziel von JSDOM ist. Wenn Sie eine genauere Simulation eines Browsers wünschen, sollten Sie einen tatsächlichen Browser verwenden.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

potapovDim picture potapovDim  ·  4Kommentare

machineghost picture machineghost  ·  4Kommentare

kentmw picture kentmw  ·  3Kommentare

lehni picture lehni  ·  4Kommentare

jhegedus42 picture jhegedus42  ·  4Kommentare