Извлеките текущий DOM и распечатайте его в виде строки без изменений стилей - PullRequest
50 голосов
/ 02 июня 2011

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

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

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

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

Спасибо!

Ответы [ 8 ]

74 голосов
/ 10 июня 2011

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

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

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

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

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

Работает так:

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

Код:

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;
    }
})();
9 голосов
/ 02 июня 2011

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

РЕДАКТИРОВАТЬ: я только что попытался поместить этот скрипт в функцию и присоединить его к событию onclick.Сделал некоторые обновления в инспекторе, нажал кнопку, и все заработало:

HTML

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

Javascript

function printDOM() {
    console.log(document.getElementsByTagName('body')[0].innerHTML) ;
}
3 голосов
/ 16 сентября 2015

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

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

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

  1. document.documentElement.outerHTML;

  2. получить все таблицы стилейиз 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;
}
Добавьте захваченный cssrules в качестве первого элемента заголовка в тексте outerHtml html

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

Этоочевидно, менее применимо к частичному содержанию.

2 голосов
/ 17 ноября 2012

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

Extension Screenshot

1 голос
/ 26 июня 2015

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

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

1 голос
/ 10 июня 2011

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

1 голос
/ 06 июня 2011

Может быть, 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>
0 голосов
/ 17 октября 2017

Функция Chrome - Печать DOM:
Флаг --dump-dom выводит document.body.innerHTML на стандартный вывод:

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

Читать больше

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...