Подтвердить что ты не робот

Извлеките текущий DOM и напечатайте его как строку, со стилями нетронутыми

Я бы хотел взять мой DOM, как есть, и преобразовать его в строку. Скажем, я открываю инспектора и вношу изменения в свойство margin-left определенного элемента. Это изменение должно быть отражено в моей строке.

Функция должна должным образом принимать все стили, применяемые в данный момент к элементу (исключая значения по умолчанию) и включать их в встроенный стиль для этого элемента.

Я написал "решение", которое оказалось неадекватным. Функция getMatchedCSSRules в webkit чрезвычайно полезна, и я не мог определить, почему она иногда работает и не работает в другие времена. Поэтому я хотел бы избежать использования этой функции, если она не работает в 100% случаев. Аналогично, функция getComputedStyle имеет свои проблемы. Если вы используете инспектор, чтобы изменить элемент #footer на этой странице 7px solid red, а не 7px solid black, это изменение будет отражено при запуске getComputedStyle(document.getElementById('footer')).cssText в консоли, но это также даст мне множество унаследованных свойства, которые никогда не изменялись ни пользователем, использующим инспектор, ни таблицами стилей на странице.

Я ищу решение, которое работает с webkit - кросс-браузерная совместимость не является проблемой на данный момент.

Спасибо!

4b9b3361

Ответ 1

Я думаю, что это может быть решением (мне потребовался почти целый день!).

Он возвращает строку, представляющую DOM любого элемента, со всеми внешними стилями, включенными в атрибуты стиля, кроме значений по умолчанию, и не постоянно модифицирует этот элемент.

Например: console.log(document.body.serializeWithStyles());

Вы можете загрузить этот код в командной строке Web Inspector или из тега script в элементе body, но НЕ в элементе head, потому что для этого требуется наличие document.body.

Я тестировал его на рабочем столе Safari 5 (у меня нет мобильной версии).

Он работает следующим образом:

Для каждого элемента в DOM:
1) кэширование значения свойства style.cssText, представляющего встроенный стиль, в массиве; 2) вызов getComputedStyle для элемента; 3) проверка наличия таблицы поиска значений по умолчанию css, соответствующей этому имени тега элемента; 4) построение, если нет;
5) повторение результата, определение того, какие значения не используются по умолчанию, используя таблицу поиска; 6) применение этих нестандартных значений стиля к элементу.
Затем сохраните outerHTML в результате.
Для каждого элемента, восстанавливая встроенные стили из кеша,
Возврат ранее сохраненного результата.

Код:

Element.prototype.serializeWithStyles = (function () {  

    // Mapping between tag names and css default values lookup tables. This allows to exclude default values in the result.
    var defaultStylesByTagName = {};

    // Styles inherited from style sheets will not be rendered for elements with these tag names
    var noStyleTags = {"BASE":true,"HEAD":true,"HTML":true,"META":true,"NOFRAME":true,"NOSCRIPT":true,"PARAM":true,"SCRIPT":true,"STYLE":true,"TITLE":true};

    // This list determines which css default values lookup tables are precomputed at load time
    // Lookup tables for other tag names will be automatically built at runtime if needed
    var tagNames = ["A","ABBR","ADDRESS","AREA","ARTICLE","ASIDE","AUDIO","B","BASE","BDI","BDO","BLOCKQUOTE","BODY","BR","BUTTON","CANVAS","CAPTION","CENTER","CITE","CODE","COL","COLGROUP","COMMAND","DATALIST","DD","DEL","DETAILS","DFN","DIV","DL","DT","EM","EMBED","FIELDSET","FIGCAPTION","FIGURE","FONT","FOOTER","FORM","H1","H2","H3","H4","H5","H6","HEAD","HEADER","HGROUP","HR","HTML","I","IFRAME","IMG","INPUT","INS","KBD","KEYGEN","LABEL","LEGEND","LI","LINK","MAP","MARK","MATH","MENU","META","METER","NAV","NOBR","NOSCRIPT","OBJECT","OL","OPTION","OPTGROUP","OUTPUT","P","PARAM","PRE","PROGRESS","Q","RP","RT","RUBY","S","SAMP","SCRIPT","SECTION","SELECT","SMALL","SOURCE","SPAN","STRONG","STYLE","SUB","SUMMARY","SUP","SVG","TABLE","TBODY","TD","TEXTAREA","TFOOT","TH","THEAD","TIME","TITLE","TR","TRACK","U","UL","VAR","VIDEO","WBR"];

    // Precompute the lookup tables.
    for (var i = 0; i < tagNames.length; i++) {
        if(!noStyleTags[tagNames[i]]) {
            defaultStylesByTagName[tagNames[i]] = computeDefaultStyleByTagName(tagNames[i]);
        }
    }

    function computeDefaultStyleByTagName(tagName) {
        var defaultStyle = {};
        var element = document.body.appendChild(document.createElement(tagName));
        var computedStyle = getComputedStyle(element);
        for (var i = 0; i < computedStyle.length; i++) {
            defaultStyle[computedStyle[i]] = computedStyle[computedStyle[i]];
        }
        document.body.removeChild(element); 
        return defaultStyle;
    }

    function getDefaultStyleByTagName(tagName) {
        tagName = tagName.toUpperCase();
        if (!defaultStylesByTagName[tagName]) {
            defaultStylesByTagName[tagName] = computeDefaultStyleByTagName(tagName);
        }
        return defaultStylesByTagName[tagName];
    }

    return function serializeWithStyles() {
        if (this.nodeType !== Node.ELEMENT_NODE) { throw new TypeError(); }
        var cssTexts = [];
        var elements = this.querySelectorAll("*");
        for ( var i = 0; i < elements.length; i++ ) {
            var e = elements[i];
            if (!noStyleTags[e.tagName]) {
                var computedStyle = getComputedStyle(e);
                var defaultStyle = getDefaultStyleByTagName(e.tagName);
                cssTexts[i] = e.style.cssText;
                for (var ii = 0; ii < computedStyle.length; ii++) {
                    var cssPropName = computedStyle[ii];
                    if (computedStyle[cssPropName] !== defaultStyle[cssPropName]) {
                        e.style[cssPropName] = computedStyle[cssPropName];
                    }
                }
            }
        }
        var result = this.outerHTML;
        for ( var i = 0; i < elements.length; i++ ) {
            elements[i].style.cssText = cssTexts[i];
        }
        return result;
    }
})();

Ответ 2

Не можете ли вы просто сделать document.getElementsByTagName('body') [0].innerHTML? Когда я вношу изменения в инспектор и затем вхожу в указанный выше javascript в консоли, он возвращает обновленный HTML.

EDIT: я просто попытался поместить эту функцию script в функцию и привязать ее к событию onclick. Сделал некоторые обновления в инспекторе, нажал кнопку, и он работал:

HTML

<button onclick="printDOM()">Print DOM</button>

Javascript

function printDOM() {
    console.log(document.getElementsByTagName('body')[0].innerHTML) ;
}

Ответ 3

Если вы хотите захватить всю страницу, проще просто получить все нестандартные таблицы стилей и встроить их.

Подход в принятом ответе великолепный, но довольно медленный и затрагивает весь документ.

Я взял следующий подход для захвата страницы, включая стиль:

  • document.documentElement.outerHTML;

  • получить все таблицы стилей из document.styleSheets API

По строкам:

function captureCss(){
    var cssrules = "";
    var sheets = document.styleSheets;
    for(var i = 0; i<sheets.length; i++){
        if(!sheets[i].disabled && sheets[i].href != null) { // or sheets[i].href.nodeName == 'LINK'
            if(sheets[i].rules == null){ // can be null because of cross origin policy
                try{
                    var fetched = XHR GET(sheets[i].href); // works nicely because it hits the cache
                    if(fetched){
                        cssrules += "<style>\n"+fetched+"\n</style>\n"
                    }
                }catch(e){
                    console.log(e);
                }
                continue;
            }
            for(var j=0;j<sheets[i].rules.length;j++){
                cssrules += "<style>\n"+sheets[i].rules[j].cssText+"\n</style>\n"
            }
        }
    }
    return cssrules;
}
  1. Добавить захваченный cssrules как первый элемент заголовка в тексте outerHtml html

Таким образом вы получаете страницу со скрытым стилем.

Это явно менее применимо для частичного контента.

Ответ 4

Хорошо, может быть, я здесь что-то пропустил, но это не строка, которую вы хотите просто document.documentElement.innerHTML? Быстрый тест w/Chrome проверяет, чтобы он вносил изменения, внесенные в Инструменты разработчика, чтобы стилировать атрибуты по мере их описания. Назначенные имена классов не расширены (например, вы не знаете, что делает class="superfuntime"), но если я правильно читаю ваш вопрос, вы не указали на это необходимость.

Ответ 5

Возможно, Google Closure Library имеет решение для вас.

Вот код, который, кажется, делает то, что вам нужно, т.е. вычислять правила CSS для воспроизведения того же внешнего вида элемента вне его текущей позиции в dom (в этом случае им нужно, чтобы передать стили в iframe, чтобы используйте его как бесшовный встроенный редактор).

Цитата из исходного файла style.js:

Provides utility routines for copying modified
CSSRule objects from the parent document into iframes so that any
content in the iframe will be styled as if it was inline in the parent
document.

<p>
For example, you might have this CSS rule:

#content .highlighted { background-color: yellow; }

And this DOM structure:

<div id="content">
  <iframe />
</div>

Then inside the iframe you have:

<body>
<div class="highlighted">
</body>

If you copied the CSS rule directly into the iframe, it wouldn't match the
.highlighted div. So we rewrite the original stylesheets based on the
context where the iframe is going to be inserted. In this case the CSS
selector would be rewritten to:

body .highlighted { background-color: yellow; }
</p>

Ответ 6

На основе ответа Luc125 я создал расширение для разработчиков для Chrome, которое включает этот код для захвата стилей и разметки для фрагмента страницы. Расширение находится в Интернет-магазин Chrome и находится на Github. Опция вывода "Вычисляемые стили" использует этот метод.

Extension Screenshot

Ответ 7

Internet Explorer → Инструменты разработчика → DOM Explorer

Выберите элемент и щелкните правой кнопкой мыши → "Копировать элемент со стилями".

Ответ 8

Функция Chrome - печать DOM:
Флаг --dump-dom печатает document.body.innerHTML в stdout:

chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/

Прочитайте подробнее