获取计算样式 仅设置默认值更改的样式



我目前拥有的代码获取整个CSS,甚至是默认的CSS。我想要的是只让 CSS 从默认值更改。

function baba() {
addEventListener("mouseover", function() {
var elem = document.getElementById("ex");
cssObj = window.getComputedStyle(elem, null)
var txt = "";
for (i = 0; i < cssObj.length; i++) {
cssObjProp = cssObj.item(i)
txt += cssObjProp + " = " + cssObj.getPropertyValue(cssObjProp) + "<br>";
document.getElementById("empty").innerHTML = txt;
}
})
}
<p id="ex" onclick="baba()">Hello World</p>
<h1>Hello World</h1>
<p id="empty"></p>

好的,这就是我如何解决它。注意:我刚刚在 5 分钟内在控制台中猛烈抨击;我相信有更有效的方法来处理它,但对于 PoC,这应该让你继续前进。

需求分析

真的(无论如何,除非有更具体的边缘情况应用程序(,你问的是"Element<XXX>当前的计算风格与相同上下文中相同类型的原版对象有何不同?问它与"默认"有何不同是荒谬的,因为"默认",强制,会受到所述上下文的影响(不同意?等待它;我会解释(。

正因为如此,我们真正需要检查的是一个缺乏应用于目标对象的效果的<XXX>(其 DOM 位置、类、id、属性、前置任务等的结果(。好消息是:我们完全可以伪造它!看看吧:

设置的设置

首先,让我们掌握我们的对象。我知道,这最好作为一个函数来执行,但为了说明目的,请在这里与我合作。让我们选择一个可以立即看到结果的对象。我看看。。。这个页面顶部的搜索栏怎么样?按 f12 弹出您的控制台,您会看到它的名字是"q"。那就行了。

// Get the StackOverflow Search field from the top of this page.
var targetDOMElement = document.querySelector('[name="q"]');
// Now, let's get its current style snapshot.
var targetObjsStyles = window.getComputedStyle(targetDOMElement);
// ... and vomit it out to our console, just so we know what we're dealing with.
console.log('ORIGINAL SET (' + Object.keys(targetObjsStyles).length + ' rules):',targetObjsStyles);

资本!现在我们有我们的源对象(我们的"<XXX>",如果你愿意的话(。

控件

接下来,我们需要一些东西来比较它。现在,作为一个听话的小男孩,我被培养成正统的科学家,在我看来,这是一种控制。幸运的是,我们对源对象了解很多,所以让我们制造一个:

// Create a new element of the same type (e.g. tagName) as our target
var tempCopyOfTarget = document.createElement(targetDOMElement.tagName);
// Insert it into the context AT THE BEGINNING of the page. Both bits here are important:
// if we create it within a documentFragment (try it) literally every property will 
// be flagged as unique. I suspect this has to do with the client's default 
// renderer, vs. the purity of a abstracted prototype, but I won't lie: I'm guessing.
// It MUST be at the start of the body to avoid silliness like
// body > .first-element ~ xxx { display:none; }
// CSS still won't let us target predecessors/ancestors, alas.
document.body.insertAdjacentElement('afterBegin', tempCopyOfTarget);
// Now  our new object shares our target's context, get ITS snapshot.
var basicElementsCSS = window.getComputedStyle(tempCopyOfTarget);
console.log('BASELINE (DUMMY OBJECT) SET (' + Object.keys(basicElementsCSS).length + ' rules):',basicElementsCSS);

噜咕噜的工作

虽然我确信大多数人都明白我现在要去哪里,但让我们结束她。给定可测试的数量和控件,检查增量。

// Create an empty object to store any changes in.
var cleanSetOfStyles = {};
// Objectify our target's style snapshot, and iterate.
Object.entries(targetObjsStyles).forEach(p=>{
// If a key-value pair exists that matches our control, ignore it. Otherwise,
// tack it onto our clean object for later perusal.
if(basicElementsCSS[p[0]] !== p[1]){ 
cleanSetOfStyles[p[0]] = p[1];
}
});

棒!干得好!

结论

现在,假设我的假设是正确的,我们应该在我们的干净对象中看到一组属性及其相应的值。此列表的长度应为非零,并且与上述原始集合中包含的计数不同(更细心的您会注意到,这是相同的,因为浏览器在请求getComputedStyles集合时将所有可能的样式值分配给对象。

// Display our deltas
console.log('CLEAN SET (' + Object.keys(cleanSetOfStyles).length + ' rules):',cleanSetOfStyles);
// Oh, and always remember to clean up after you make a mess in the lab.
tempCopyOfTarget.remove()

这是怎麽!?胜利!至少在我的环境中(必须考虑我的浏览器品牌、版本、活动插件、支持的功能、操作系统等;您的里程可能会有所不同(,我数了 116 条剩余的规则,并作用于我们的目标对象。这些规则不同于我们的原版代码对象,我们召唤的第一行代码对象,因为浏览器花了皮秒的时间。

警告

总有一个问题,不是吗? 这不是一个万无一失的系统。我可以想到六种方法,这将在我的头顶上失败(:empty修饰符,具体取决于您所在的范围......[name="q"] ~ [name="q"]规则,插入我们的虚拟对象现在适用于我们的目标......:first-of-type不再适用...各种"嘻嘻"(。但是,我准备断言我能想到的所有情况都是边缘情况,并且只要有适当的预见,它们本身都是可管理的。

TLDR

这是整个代码,如果您愿意,可以直接复制+粘贴到控制台中,并且没有注释:

var targetDOMElement = document.querySelector('[name="q"]');
var targetObjsStyles = window.getComputedStyle(targetDOMElement);
console.log('ORIGINAL SET (' + Object.keys(targetObjsStyles).length + ' rules):',targetObjsStyles)
var tempCopyOfTarget = document.createElement(targetDOMElement.tagName);
document.body.insertAdjacentElement('afterBegin', tempCopyOfTarget);
var basicElementsCSS = window.getComputedStyle(tempCopyOfTarget);
console.log('BASELINE (DUMMY OBJECT) SET (' + Object.keys(basicElementsCSS).length + ' rules):',basicElementsCSS)
var cleanSetOfStyles = {};
Object.entries(targetObjsStyles).forEach(p=>{
if(basicElementsCSS[p[0]] !== p[1]){ 
cleanSetOfStyles[p[0]] = p[1];
}
});
console.log('CLEAN SET (' + Object.keys(cleanSetOfStyles).length + ' rules):',cleanSetOfStyles);
tempCopyOfTarget.remove()

最后说明:我知道这个问题已经有几个月了,但除了"不!你完蛋了! 万一@angels7仍然需要修复,你去吧。否则,"嗨,你们这些遥远的未来人!

最新更新