gpt4 book ai didi

javascript - 如何获得所需的元素样式?

转载 作者:行者123 更新时间:2023-12-05 00:32:15 24 4
gpt4 key购买 nike

我有以下代码,我想获得元素的所需 CSS 属性(即使样式是由 js 设置的,即对于由 SPA 创建的文件,如 react),而不是计算/应用的。例如 computedStyle.width应该有一个未定义的值。我怎样才能做到这一点?

let ele = document.querySelector(".hello");
let computedStyle = window.getComputedStyle(ele);

console.log(computedStyle.backgroundColor);
console.log(computedStyle.height);
console.log(computedStyle.width); // <- This should be undefined or ""
.hello {
height: 10px;
background-color: red;
}
<div class="hello">
helloInnerText
</div>

最佳答案

您可以通过检查所有样式表中适用于正在调查的元素的规则来做到这一点。当规则适用时,您有一个 css 属性,它是编写样式表的开发人员对该元素所需的值。
由于更具体的规则优先,因此您必须对照其他适用的规则检查每个规则的特殊性。
请注意,我不建议将其用于生产,因为它相当慢。
请参阅下面代码中的注释:

/* Say, we want to know the width, height, and background-color */
let propertiesWeWant = ['width', 'height', 'background-color', 'color', 'margin', 'font-size'];
let ele = document.querySelector(".hello");
/* First we have to prepare the stylesheets, in order to avoid CORS problems,
* since css rules of external stylesheets cannot be accessed.
* We loop through all stylesheets and inject external sheets into the head,
* so we can read them in the next step.
*/
for(let i = 0; i < document.styleSheets.length; i++){
prepareStylesheet(document.styleSheets[i]);
}

setTimeout(function(){
/* We get all the styles for this element, as found in the stylesheets. */
let givenStyles = getStylesFromStylesheets(ele);
/* And filter the results, so we only have the properties we want. */
let propertyList = {};
for(let i = 0; i < propertiesWeWant.length; i++){
let property = propertiesWeWant[i];
if(typeof(givenStyles[property]) !== "undefined"){
propertyList[property] = givenStyles[property].style;
}
else{
propertyList[property] = "";
}
}
/* prints all given properties.
* Object { width: "1px", height: "4px", "background-color": "pink", color: "turquoise", margin: "", "font-size": "17.5px" }
* */
console.log(propertyList);
},2000);

/* Taken from her: https://discourse.mozilla.org/t/webextensions-porting-access-to-cross-origin-document-stylesheets-cssrules/18359
* If cssRules cannot be accessed because of CORS issues:
* 1. remove the stylesheet
* 2. fetch it using its url
* 3. insert the rules in the header
*/
function prepareStylesheet(sheet){
try {
sheet.cssRules;
} catch (e) {
if (e.name === 'SecurityError') {
let nextElement = sheet.ownerNode.nextSibling;
let parentNode = sheet.ownerNode.parentNode;
sheet.ownerNode.parentNode.removeChild(sheet.ownerNode);
fetch(sheet.href).then(resp => resp.text()).then(css => {
let style = document.createElement('style');
style.innerText = css;
//document.head.appendChild(style);
if(nextElement === null){
parentNode.appendChild(style);
}
else{
parentNode.insertBefore(style, nextElement);
}

});


}
}
}
/**
* Search through stylesheets for rules that apply to a given element.
* Returns object with css properties name and css property value
*/
function getStylesFromStylesheets(elementToInvestigate){
let givenStyles = {};
//alert(document.styleSheets.length);
for(let i = 0; i < document.styleSheets.length; i++){
let rules = document.styleSheets[i].cssRules;
/* Loop through every rule in the stylesheet and see wether it applies to this element */
for(let j = 0; j < rules.length; j++){
let rule = rules[j];
/* Ignore media rules. Can be added, but needs some logic that you have to write. */
if(typeof(rule.selectorText) === "undefined"){
continue;
}
let split = rule.selectorText.split(",");
for(let l = 0; l < split.length; l++){
let selector = split[l];
let elements = document.querySelectorAll(selector);
let applies = false;
for(let k = 0; k < elements.length; k++){
if(elements[k] === elementToInvestigate){
applies = true;
break;
}
}
if(applies === true){
/* If the rule applies to this element, loop through the css properties of this css rule. */
let styles = rule.style;
for(let k = 0; k < styles.length; k++){
/* For each css property, check if it was already added earlier. */
let styleName = styles[k];
let styleValue = styles[styleName];
let newSpecificity = calculateSingle( selector);
if(typeof(givenStyles[styleName]) !== "undefined"){
/* If the property was already added, compare the specificity of the new one to the one added earlier. */
let earlierSelector = givenStyles[styleName].selector;
let earlierSpecificity = givenStyles[styleName].specificity;
let newHasMoreSpecificity = compareSpecifities( newSpecificity, earlierSpecificity);
if(newHasMoreSpecificity === true){
givenStyles[styleName] = {
style: styleValue,
specificity: newSpecificity
}
}
else{
/* Leave givenStyles as it was, since the former tule had higher specificity. */
}
}
else{
/* If the property was not yet seen, add it to the givenStyles. */
givenStyles[styleName] = {
style: styleValue,
specificity: newSpecificity
}
}
}
}
}
}
/* If the element has inline styles, overwrite the found properties since inline always takes precedence. */
if(elementToInvestigate.style.length > 0){
for(let j = 0; j < elementToInvestigate.style.length; j++){
let styleName = elementToInvestigate.style[j];
let styleValue = elementToInvestigate.style[styleName];
givenStyles[styleName] = {
style: styleValue,
specificity: [1,1,1,1] //not needed here
}
}
}
var inlineStyles;
}
return givenStyles;
}
/* Taken from here and adjusted the output: https://raw.githubusercontent.com/keeganstreet/specificity/master/specificity.js */
/**
* Calculates the specificity of CSS selectors
* http://www.w3.org/TR/css3-selectors/#specificity
*
* Returns specificity: e.g. 0,1,0,0
*/
function calculateSingle(input) {
var selector = input,
findMatch,
typeCount = {
'a': 0,
'b': 0,
'c': 0
},
parts = [],
// The following regular expressions assume that selectors matching the preceding regular expressions have been removed
attributeRegex = /(\[[^\]]+\])/g,
idRegex = /(#[^\#\s\+>~\.\[:\)]+)/g,
classRegex = /(\.[^\s\+>~\.\[:\)]+)/g,
pseudoElementRegex = /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi,
// A regex for pseudo classes with brackets - :nth-child(), :nth-last-child(), :nth-of-type(), :nth-last-type(), :lang()
// The negation psuedo class (:not) is filtered out because specificity is calculated on its argument
// :global and :local are filtered out - they look like psuedo classes but are an identifier for CSS Modules
pseudoClassWithBracketsRegex = /(:(?!not|global|local)[\w-]+\([^\)]*\))/gi,
// A regex for other pseudo classes, which don't have brackets
pseudoClassRegex = /(:(?!not|global|local)[^\s\+>~\.\[:]+)/g,
elementRegex = /([^\s\+>~\.\[:]+)/g;

// Find matches for a regular expression in a string and push their details to parts
// Type is "a" for IDs, "b" for classes, attributes and pseudo-classes and "c" for elements and pseudo-elements
findMatch = function(regex, type) {
var matches, i, len, match, index, length;
if (regex.test(selector)) {
matches = selector.match(regex);
for (i = 0, len = matches.length; i < len; i += 1) {
typeCount[type] += 1;
match = matches[i];
index = selector.indexOf(match);
length = match.length;
parts.push({
selector: input.substr(index, length),
type: type,
index: index,
length: length
});
// Replace this simple selector with whitespace so it won't be counted in further simple selectors
selector = selector.replace(match, Array(length + 1).join(' '));
}
}
};

// Replace escaped characters with plain text, using the "A" character
// https://www.w3.org/TR/CSS21/syndata.html#characters
(function() {
var replaceWithPlainText = function(regex) {
var matches, i, len, match;
if (regex.test(selector)) {
matches = selector.match(regex);
for (i = 0, len = matches.length; i < len; i += 1) {
match = matches[i];
selector = selector.replace(match, Array(match.length + 1).join('A'));
}
}
},
// Matches a backslash followed by six hexadecimal digits followed by an optional single whitespace character
escapeHexadecimalRegex = /\\[0-9A-Fa-f]{6}\s?/g,
// Matches a backslash followed by fewer than six hexadecimal digits followed by a mandatory single whitespace character
escapeHexadecimalRegex2 = /\\[0-9A-Fa-f]{1,5}\s/g,
// Matches a backslash followed by any character
escapeSpecialCharacter = /\\./g;

replaceWithPlainText(escapeHexadecimalRegex);
replaceWithPlainText(escapeHexadecimalRegex2);
replaceWithPlainText(escapeSpecialCharacter);
}());

// Remove anything after a left brace in case a user has pasted in a rule, not just a selector
(function() {
var regex = /{[^]*/gm,
matches, i, len, match;
if (regex.test(selector)) {
matches = selector.match(regex);
for (i = 0, len = matches.length; i < len; i += 1) {
match = matches[i];
selector = selector.replace(match, Array(match.length + 1).join(' '));
}
}
}());

// Add attribute selectors to parts collection (type b)
findMatch(attributeRegex, 'b');

// Add ID selectors to parts collection (type a)
findMatch(idRegex, 'a');

// Add class selectors to parts collection (type b)
findMatch(classRegex, 'b');

// Add pseudo-element selectors to parts collection (type c)
findMatch(pseudoElementRegex, 'c');

// Add pseudo-class selectors to parts collection (type b)
findMatch(pseudoClassWithBracketsRegex, 'b');
findMatch(pseudoClassRegex, 'b');

// Remove universal selector and separator characters
selector = selector.replace(/[\*\s\+>~]/g, ' ');

// Remove any stray dots or hashes which aren't attached to words
// These may be present if the user is live-editing this selector
selector = selector.replace(/[#\.]/g, ' ');

// Remove the negation psuedo-class (:not) but leave its argument because specificity is calculated on its argument
// Remove non-standard :local and :global CSS Module identifiers because they do not effect the specificity
selector = selector.replace(/:not/g, ' ');
selector = selector.replace(/:local/g, ' ');
selector = selector.replace(/:global/g, ' ');
selector = selector.replace(/[\(\)]/g, ' ');

// The only things left should be element selectors (type c)
findMatch(elementRegex, 'c');

// Order the parts in the order they appear in the original selector
// This is neater for external apps to deal with
parts.sort(function(a, b) {
return a.index - b.index;
});

return [0, typeCount.a, typeCount.b, typeCount.c];
};

/**
* Compares two specificities
*
* - it returns false if a has a lower specificity than b
* - it returns true if a has a higher specificity than b
* - it returns true if a has the same specificity than b
*/
function compareSpecifities(aSpecificity, bSpecificity) {

for (var i = 0; i < 4; i += 1) {
if (aSpecificity[i] < bSpecificity[i]) {
return false;
} else if (aSpecificity[i] > bSpecificity[i]) {
return true;
}
}

return true;
};
blockquote{
margin:7px;
border-left: 10000px;
}
#hello-id.hello{
height: 1px;
}
#hello-id{
height: 2px;
}
html #hello-id{
height: 3px;
color: green;
}
#hello-id.hello{
height: 4px;
color: turquoise;
}
.hello-wrapper .hello {
height: 5px;
background-color: blue;
}
.hello {
height: 5px;
background-color: red;
}
#bogus.bogus{
height: 6px;
background-color: orange;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/css/bootstrap.min.css" >
<div class="hello-wrapper">
<blockquote id="hello-id" class="hello" style="width:1px; background-color: pink;">
helloInnerText
</blockquote>
</div>

关于javascript - 如何获得所需的元素样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72718967/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com