提取当前的DOM并将其打印为string,样式不变

我希望能够拿走我的DOM,并将其转换为string。 比方说,我打开检查员,并更改特定元素的margin-left属性。 这个改变应该反映在我的string中。

该函数应该适当地采用当前应用于元素的所有样式(不包括默认值),并将其包含在该元素的内联样式中。

我写了一个已经被certificate是不够的“解决scheme”。 webkit中的getMatchedCSSRules函数是非常挑剔的,我一直无法确定它为什么有时会起作用,并且在其他时候不起作用。 因此,我想避免使用这个function,除非它工作100%的时间。 同样, getComputedStyle函数也有自己的问题。 如果使用检查器将此页上的#footer元素更改为7px solid red而不是7px solid black ,则在控制台中运行getComputedStyle(document.getElementById('footer')).cssText时,但它也会给我一些从未被用户使用检查员或页面上的样式表所修改的inheritance属性。

我正在寻找一个适用于webkit的解决scheme – 跨浏览器兼容性目前不是问题。

谢谢!

我想这可能是一个解决scheme(花了我近一整天!)。

它返回一个表示任何元素的DOM的string,所有外部样式都包含在除“默认值”之外的“样式”属性中,并且不会永久修改该元素。

例如: console.log(document.body.serializeWithStyles());

您可以在Web Inspector命令行或body元素中的脚本标记中加载此代码,但不要在head元素中加载此代码,因为它需要document.body的存在。

我已经testing了桌面上的Safari 5(我没有移动版本)。

它是这样工作的:

对于DOM中的每个元素:
1)在数组中caching表示内联样式的style.cssText属性的值;
2)在元素上调用getComputedStyle;
3)检查是否有与这个元素的标签名相对应的CSS默认值查找表;
4)如果不是,
5)遍历结果,使用查找表查找哪些值是非默认的;
6)将这些非默认样式值应用于元素。
然后存储outerHTML作为结果;
对于每个元素,从caching中恢复内联样式;
返回之前存储的结果。

代码:

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

你不能只是做document.getElementsByTagName('body')[0] .innerHTML? 当我在检查器中进行更改,然后在控制台中input上面的JavaScript时,它将返回更新后的HTML。

编辑:我只是试图将该脚本放入一个函数,并将其附加到一个onclick事件。 在检查员做了一些更新,点击button,它的工作:

HTML

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

使用Javascript

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

如果你想捕捉整个页面,只需要获取所有非内联样式表并将它们内联即可。

被接受的答案的方法是macros伟的,但相当缓慢,触及整个文件。

我采取了以下方法来捕获包括样式的页面:

  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; } 
  1. 添加捕获的cssrules作为outerHtml html文本中头的第一件事

这样你就可以得到一个独立的样式页面。

这显然不适用于部分内容。

好的,也许我错过了这里的东西,但不是你想要的只是document.documentElement.innerHTML的string? 通过Chrome进行快速testing,可以validation是否按照您所描述的方式,在开发人员工具中对所做的更改进行了样式属性设置。 指定的类名不扩展(例如,你不知道什么class="superfuntime"在做什么),但是如果我正确地阅读你的问题,你没有说明的需要。

也许Google Closure图书馆为您提供了一个解决scheme。

有代码似乎做你所需要的,即计算的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> 

基于Luc125的回答,我为Chrome创build了一个开发者工具扩展,它包含了捕获页面片段样式和标记的代码。 该扩展程序位于Chrome网上应用店 ,位于Github上 。 “计算样式”输出选项使用该方法。

扩展程序截图

Internet Explorer – >开发工具 – > DOM资源pipe理器

select元素并右键单击 – >“使用样式复制元素”。

Chromefunction – 打印DOM:
--dump-dom标志将document.body.innerHTML打印到标准输出:

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

阅读更多