Jsdom: offsetWidth, offsetHeight, offsetTop и offsetLeft

Созданный на 1 февр. 2011  ·  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 также должны включать отступы. Я бы предложил некоторые хитрые исправления, чтобы заставить его работать, потому что идеальную реализацию сложно реализовать.

Решение, предложенное @tobyhinloopen, кажется прекрасным, но когда я его использую, я получаю «не могу улучшить свойство offsetLeft»

@zallek Думаю, у вас уже есть поддержка offsetLeft :) Что возвращает window.HTMLElement.prototype.offsetLeft ? Если это что-то, кроме undefined, мое решение не сработает

Просто хотел сказать спасибо @tobyhinloopen , ваше решение мне очень пригодилось. :)

@tobyhinloopen Большое спасибо за размещение решения! Это очень полезно и работает до тех пор, пока я использую переменную для установки значения смещения и исключения this . this выходит неопределенным, что имеет смысл, учитывая, что контекст не является фактическим классом. Вы этого ожидали?

@jordantomax это привязано к элементу при вызове функции, а не при ее определении. 'this' должен быть элементом, когда вы вызываете его из любого элемента html.

Если это не так, мне хотелось бы увидеть пример.

@tobyhinloopen Спасибо за быстрый ответ. Вот чего я ожидал. Когда я пытаюсь воспроизвести свою проблему в codeandbox, используя реальную среду браузера, она работает правильно. Но при использовании шутки я вижу this как неопределенное. Я создал небольшой образец репозитория, чтобы показать вам, что я испытываю, возможно, мои настройки неверны.

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

В связи с этим у меня также возникают проблемы с переопределением таких методов, как scrollIntoView, с использованием jest и jsdom. Есть рекомендуемый способ сделать это?

Обычно на MDN есть какие-то полифилы. В противном случае просто попробуйте реализовать его на основе спецификации таким образом, чтобы это соответствовало вашим потребностям. Если все не удается, просто используйте другую среду тестирования. JSDom имеет свое место, но в какой-то момент вы можете захотеть рассмотреть вместо него настоящий браузер. Многие среды тестирования позволяют проводить тестирование в реальных браузерах (даже в нескольких одновременно), а также отправлять отчеты в реальном времени на вашу машину разработки. IIRC Karma делает это -> https://karma-runner.github.io/latest/index.html

У меня было открыто несколько браузеров (firefox chrome safari internet explorer edge + мобильные в симуляторах) одновременно на моей машине, и все они отчитывались в реальном времени с помощью Karma + Mocha.

@tobyhinloopen Правильно ты на всех аккаунтах! Спасибо!! Я все еще не совсем понимаю, зачем нужен getComputedStyle , и можно ли написать сеттер с учетом этого метода. Для меня это работает:

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 рейтинги

Смежные вопросы

mitar picture mitar  ·  4Комментарии

potapovDim picture potapovDim  ·  4Комментарии

machineghost picture machineghost  ·  4Комментарии

khalyomede picture khalyomede  ·  3Комментарии

tolmasky picture tolmasky  ·  4Комментарии