JS using a centralized method of dynamic operation css

Inline style

Before our in-depth knowledge of the complex, to come back to care about some of the basics. For example, you can modify it .styleto edit a given attribute HTMLElementof the inline style.

const el = document.createElement('div')

el.style.backgroundColor = 'red'
// 或者
el.style.cssText = 'background-color: red'
// 或者
el.setAttribute('style', 'background-color: red')

Directly .styleset style properties on an object will need to use as camel named attribute key instead 短横线命名.  If you need to set more inline style attributes, by setting the .style.cssTextproperty to set a more efficient way.

Remember, after cssText set to the original css style is cleared up, so we requested a bunch of dead styles.

If this is too cumbersome inline style set, you can also consider .styleto Object.assign()be used together to set a plurality of style properties.

// ...
Object.assign(el.style, {
    backgroundColor: "red",
    margin: "25px"
})

These "basics" much more than we imagined. .styleObject implements the CSSStyleDeclarationinterface.

This shows it with some interesting properties and methods, including the use of just .cssText, further comprising .length(set number of attributes), as well as .item(), .getPropertyValue()and .setPropertyValue()methods like:

// ...
const propertiesCount = el.style.length
for(let i = 0; i < propertiesCount; i++) {
    const name = el.style.item(i) // 'background-color'
    const value = el.style.getPropertyValue(name) // 're'
    const priority = el.style.getPropertyPriority(name) // 'important'
    
    if(priority === 'important') {
        el.style.removeProperty()
    }
}

There is a small trick - during traversal .item()method by index alternate form of syntax.

// ...
el.style.item(0) === el.style[0]; // true

CSS class

Next, look at the structure --CSS higher class, having the form of a string and retrieving settings are .classname.

// ...
el.className = "class-one class-two";
el.setAttribute("class", "class-one class-two");

Another method is to set the string class set classattributes (the same as the search).  However, as the use of .style.cssTextproperty, the set .classNamewill include our requirements given element in the string of all classes, including the changed and unchanged classes.

Of course, you can use some simple string manipulation to get the job done, there is a relatively new is the use of .classListproperty that, IE9 does not support it, and IE10 and IE11 are only partially supported it.

classlistProperties achieved DOMTokenList, there is a lot of useful methods. For example .add(), , .remove().toggle () and .replace()allow the current to change our CSS class set, while others, for example .item(), .entries()or .foreach()can be simplified traversal of the index set.

// ...
const classNames = ["class-one", "class-two", "class-three"];
classNames.forEach(className => {
    if(!el.classList.contains(className)) {
        el.classList.add(className);
    }
});

Stylesheets

All along, Web Api Another StyleSheetListinterface, which by the document.styleSheetsrealization of property. document.styleSheets Read-only property, a return of  StyleSheet objects of  StyleSheetListeach of  StyleSheet the objects are in a document linked or embedded style sheet.

for(styleSheet of document.styleSheets){
    console.log(styleSheet);
}

We know by the print result, each cycle is CSSStyleSheet printing objects, each object is CSSStyleSheet consists of the following attributes:

 

 

 CSS Style Sheet object methods:

 

 

 With StyleSheetListall the content, we come CSS StyleSheetitself.  Here it is a bit mean,  CSS StyleSheetextends the StyleSheetinterface, and only this read-only attribute, such as .ownerNode, .href, .titleor .type, most of them given to the local style sheets directly from the statement. Recall that the standard HTML code to load an external CSS file, we will understand the meaning of this sentence is valid:

 

<head>
<link rel="stylesheet" type="text/css" href="style.css" title="Styles">
</head>

 

Now, we know HTML document can contain multiple style sheets, all of these stylesheets can contain different rules, may contain even more style sheets (when using @importthe time). CSSStyleSheetThere are two ways: 、.insertrule()and .deleterule() to add and delete Css rules.

// ...
const ruleIndex = styleSheet.insertRule("div {background-color: red}");
styleSheet.deleteRule(ruleIndex);

.insertRule(rule,index): This function can be cssRulesinserted into a specified rule set in the rule, the parameter ruleis a string denoted rule, the parameter indexis a value of rule string inserted. deleteRule(index): This function can delete the specified index of compliance rules, parameters indexspecified index rules. CSSStyleSheetAlso has its own two properties: .ownerRuleand .cssRule. Although .ownerRulethe @importcorrelation, but more interesting is that .cssRules . Simply put, it is CSSRuleListto CSSRulebe used the aforementioned .insertrule()and .deleterule()to modify its methods. Remember that some browsers may block our access to external CSSSt from different sources (domain) yleSheet the .cssRulesproperty.

 

So what is  CSSRuleList?

CSSRuleListIt is an array object contains an ordered CSSRulecollection of objects. Each CSSRulecan be rules.item(index)in the form of access, or rules[index].  Here rulesis an implementation of the CSSRuleListinterface object,  indexis based on 0the beginning of the sequence and CSSthe sequence stylesheet is consistent. It is the number of style objects by rules.lengthexpression.

For CSSStyleRule objects:

Each stylesheet CSSStyleSheetobject can contain a number of CSSStyleRuleobjects, i.e. css style rules, as follows:

 

<style type="text/css">
  h1{color:red}
  div{color:green}
</style>

 

在上面的代码中style标签是一个CSSStyleSheet样式表对象,这个样式表对象包含两个CSSStyleRule对象,也就是两个css样式规则。CSSStyleRule对象具有下列属性:

1.type:返回0-6的数字,表示规则的类型,类型列表如下:

0:CSSRule.UNKNOWN_RULE。

1:CSSRule.STYLE_RULE (定义一个CSSStyleRule对象)。

2:CSSRule.CHARSET_RULE (定义一个CSSCharsetRule对象,用于设定当前样式表的字符集,默认与当前网页相同)。

3:CSSRule.IMPORT_RULE (定义一个CSSImportRule对象,就是用@import引入其他的样式表)

4:CSSRule.MEDIA_RULE (定义一个CSSMediaRule对象,用于设定此样式是用于显示器,打印机还是投影机等等)。

5:CSSRule.FONT_FACE_RULE (定义一个CSSFontFaceRule对象,CSS3的@font-face)。

6:CSSRule.PAGE_RULE (定义一个CSSPageRule对象)。

2.cssText:返回一个字符串,表示的是当前规则的内容,例如:

div{color:green}

3.parentStyleSheet:返回所在的CSSStyleRule对象。

4.parentRule:如果规则位于另一规则中,该属性引用另一个CSSRule对象。

5.selectorText:返回此规则的选择器,如上面的div就是选择器。

6.style:返回一个CSSStyleDeclaration对象。

// ...
const ruleIndex = styleSheet.insertRule("div {background-color: red}");
const rule = styleSheet.cssRules.item(ruleIndex);

rule.selectorText; // "div"
rule.style.backgroundColor; // "red"

实现

现在,咱们对 CSS 相关的 JS Api有了足够的了解,可以创建咱们自己的、小型的、基于运行时的CSS-in-JS实现。咱们的想法是创建一个函数,它传递一个简单的样式配置对象,生成一个新创建的CSS类的哈希名称供以后使用。

实现流程很简单,咱们需要一个能够访问某种样式表的函数,并且只需使用.insertrule()方法和样式配置就可以运行了。先从样式表部分开始:

function createClassName(style) {
  // ...
  let styleSheet;
  for (let i = 0; i < document.styleSheets.length; i++) {
    if (document.styleSheets[i].CSSInJS) {
      styleSheet = document.styleSheets[i];
      break;
    }
  }
  if (!styleSheet) {
    const style = document.createElement("style");
    document.head.appendChild(style);
    styleSheet = style.sheet;
    styleSheet.CSSInJS = true;
  }
  // ...
}

如果你使用的是ESM或任何其他类型的JS模块系统,则可以在函数外部安全地创建样式表实例,而不必担心其他人对其进行访问。 但是,为了演示例,咱们将stylesheet上的.CSSInJS属性设置为标志的形式,通过标志来判断是否要使用它。

现在,如果如果还需要创建一个新的样式表怎么办? 最好的选择是创建一个新的<style/>标记,并将其附加到HTML文档的<head/>上。 这会自动将新样式表添加到document.styleSheets列表,并允许咱们通过<style/>标记的.sheet属性对其进行访问,是不是很机智?

function createRandomName() {
  const code = Math.random().toString(36).substring(7);
  return `css-${code}`;
}

function phraseStyle(style) {
  const keys = Object.keys(style);
  const keyValue = keys.map(key => {
    const kebabCaseKey =
        key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
    const value =
        `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;
    
    return `${kebabCaseKey}:${value};`;
  });
  
  return `{${keyValue.join("")}}`;
}

除了上面的小窍门之外。 自然,咱们首先需要一种为CSS类生成新的随机名称的方法。

然后,将样式对象正确地表达为可行的CSS字符串的形式。 这包括驼峰命名和短横线全名之间的转换,以及可选的像素单位(px)转换的处理。

function createClassName(style) {
  const className = createRandomName();
  let styleSheet;
  // ...
  styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
  return className;
}

完整代码如下:

HTML

<div id="el"></div>

JS

function createRandomName() {
  const code = Math.random().toString(36).substring(7);
  return `css-${code}`;
}

function phraseStyle(style) {
  const keys = Object.keys(style);
  const keyValue = keys.map(key => {
    const kebabCaseKey = key.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
    const value = `${style[key]}${typeof style[key] === "number" ? "px" : ""}`;
    return `${kebabCaseKey}:${value};`;
  });
  return `{${keyValue.join("")}}`;
}

function createClassName(style) {
  const className = createRandomName();
  let styleSheet;
  for (let i = 0; i < document.styleSheets.length; i++) {
    if (document.styleSheets[i].CSSInJS) {
      styleSheet = document.styleSheets[i];
      break;
    }
  }
  if (!styleSheet) {
    const style = document.createElement("style");
    document.head.appendChild(style);
    styleSheet = style.sheet;
    styleSheet.CSSInJS = true;
  }
  styleSheet.insertRule(`.${className}${phraseStyle(style)}`);
  return className;
}

const el = document.getElementById("el");

const redRect = createClassName({
  width: 100,
  height: 100,
  backgroundColor: "red"
});

el.classList.add(redRect);

运行效果:

 

 

总结

正如本文咱们所看到的,使用 JS 操作CSS 是一件非常有趣的事,咱们可以挖掘很多好用的 API,上面的例子只是冰山一角,在CSS API(或者更确切地说是API)中还有更多方法,它们正等着被揭开神秘面纱。

Guess you like

Origin www.cnblogs.com/art-poet/p/12070507.html