javascript - 使用纯js /跨浏览器解决方案检查元素中是否存在伪类(:after,:before,...)
问题描述
首先感谢所有愿意帮助我的人。我的问题很大,所以基本上我想要一个方法,它可以识别给定 HTML 元素上所有当前的伪名称。然后检查通过这些伪类添加或修改了哪些 CSS 样式,并将它们附加到新的 HTML 元素。所有这些都应该尽可能在纯 JS 和跨浏览器上进行。
我自己解决了这个问题的一部分,但我没有足够的 javascript 知识或想象力来完成这个问题,并且至少部分找不到类似解决方案的任何好例子。
constructor() {
this._options = {
pseudoElements: ['active', 'checked', 'disabled', 'empty', 'enabled', 'first-child', 'first-of-type', 'focus', 'hover', 'in-range', 'invalid', 'last-child', 'last-of-type', 'link', 'not(*)', 'nth-child(*)', 'nth-last-child(*)', 'only-of-type', 'only-child', 'optional', 'out-of-range', 'read-only', 'read-write', 'required', 'root', 'target', 'valid', 'visited', 'after', 'before']
}
}
_handleElmCss(domElm, newElm) {
// could not think any better solution then getting all CSS without pseudo then checking with pseudo the same Style object difference. I need as fast as possible way, because i am working with hundred of thousands elements.
var computedStyle = getComputedStyle(domElm);
for (var i = 0, len = this._options.pseudoElements.length; i < len; i++) {
var pseu_name = this._options.pseudoElements[i];
if (this._containsPseudo(domElm, ':' + pseu_name)) {
var differentParameters = this._getComputedDifference(pseu_name, computedStyle, domElm);
console.log(differentParameters);
}
};
}
_getComputedDifference(pseu_name, computed2, domElm) {
var computed1 = getComputedStyle(domElm, ':' + pseu_name);
var array1 = [], array2 = [];
// I belive there is a faster way to convert getComputedStyle to key-value array.
for (var i = 0; i < computed1.length; i++) {
var key = computed1[i];
var value = computed1.getPropertyValue(key);
if (key != "" && key != null) {
array1[i] = value; // i believe this part is incorrect, i mean array-key should be the "key" variable, but i get JS errors.
}
}
for (var i = 0; i < computed2.length; i++) {
var key = computed2[i];
var value = computed2.getPropertyValue(key);
if (key != "" && key != null) {
array2[i] = value; // i believe this part is incorrect, i mean array-key should be the "key" variable, but i get JS errors.
}
}
return array1.filter(val => !array2.includes(val));
}
_containsPseudo(node, selector) {
// this method works only with :empty, :hover and so on. :before and :after does not work.
var nativeMatches = (node.matches || node.msMatchesSelector);
try {
return(nativeMatches.call(node, selector));
} catch (error) {
return false;
}
}
此代码是从我的库中复制的,可能包含一些缺失的部分或类型错误。
最初通过这篇文章标题,我需要帮助检查任何给定元素是否包含任何伪类,但如果有人知道我上面提到的其他问题的解决方案,请自由发表评论。谢谢你。
这个脚本应该按照我的想象完成的部分(我可能错了):
- 检查当前元素是否包含任何伪类。
- 获取当前的伪类顺序(因此不应错误地覆盖 CSS)。
- foreach 当前伪类并获取已修改的当前样式,从任何 CSS 源添加。
- 将新的组合样式(仅在伪元素中更改的样式)添加到新元素。
解决方案
您可以使用带有第二个参数的getComputedStyle() (W3C 参考)pseudoElt
来获取它。检查这个例子:
var el = document.querySelector('#elt'),
pseudo = window.getComputedStyle(el, ':before');
alert(pseudo.getPropertyValue("content"));
#elt:before {
content: "This element has pseudo class"
}
<div id="elt"></div>
编辑
您可能希望看到这一点:(来自另一个的函数所以回答)
<style>
#elt {
color:red;
}
#elt2 {
color:blue;
}
#elt:before {
}
#elt2:first-child {
}
#elt2:after {
}
</style>
<div id="elt">#ELT1</div>
<div id="elt2">#ELT2</div>
<div id="container"></div>
<hr>
<script type="text/javascript">
function ruleSelector(selector) {
function uni(selector) {
return selector.replace(/::/g, ':')
}
return Array.prototype.filter.call(Array.prototype.concat.apply([], Array.prototype.map.call(document.styleSheets, function(x) {
return Array.prototype.slice.call(x.cssRules);
})), function(x) {
return uni(x.selectorText) === uni(selector);
});
}
lists = {pseudos: ['active', 'checked', 'disabled', 'empty', 'enabled', 'first-child', 'first-of-type', 'focus', 'hover', 'in-range', 'invalid', 'last-child', 'last-of-type', 'link', 'not(*)', 'nth-child(*)', 'nth-last-child(*)', 'only-of-type', 'only-child', 'optional', 'out-of-range', 'read-only', 'read-write', 'required', 'root', 'target', 'valid', 'visited', 'after', 'before']};
document.write("<h1>#elt</h1>");
for (var i = 0, len = lists.pseudos.length; i < len; i++) {
var pseudo = lists.pseudos[i];
if(ruleSelector("#elt:"+pseudo).length)
document.write("<strong>#elt has :"+pseudo+"</strong><br>");
else
document.write("<small>#elt hasn't :"+pseudo+"</small><br>");
}
document.write("<h1>#elt2</h1>");
for (var i = 0, len = lists.pseudos.length; i < len; i++) {
var pseudo = lists.pseudos[i];
if(ruleSelector("#elt2:"+pseudo).length)
document.write("<strong>#elt2 has :"+pseudo+"</strong><br>");
else
document.write("<small>#elt2 hasn't :"+pseudo+"</small><br>");
}
</script>
我刚刚修改了代码,你也可以这样做。享受。
推荐阅读
- powerbi - 动态切片器选择项目 DAX
- reactjs - 将道具传递给 createMaterialTopTabNavigator 中的所有选项卡的问题
- python - 使用来自另一个数据框python的公共数据删除数据
- r - 考虑大小写字母相同的单词
- netsuite - 将带有内置搜索的选择字段添加到 Suitelet
- reactjs - CardGroup 表带反应溢出屏幕
- c# - 到达webapi端点,但所有参数为空
- spring - 访问令牌过期后刷新
- javascript - 检查javascript对象的子对象是否包含某个字符串
- azure - 无法连接到在 docker 容器中运行的 Influxdb