How to better use js?

JavaScript can be said that the interaction of the king, as a scripting language with many Web Api further expanded its feature set, richer interactive interface operability. Examples of such API include WebGL API, Canvas API, DOM API, there is a group of lesser known CSS API.

Because JSXand countless JS框架have enabled by JS API DOM interaction with the idea really caught on, but the use of similar techniques in CSS does not seem a lot. Of course, there are like CSS-in-JS type of solution, but the most popular solution is based on translation (transpilation), without additional operation to generate CSS. This is certainly good for performance, since the use of CSS API may result in additional redrawn, which is DOM APIthe same use. But this is not we want. If the company requires our day, it is necessary to manipulate DOM elements and CSS style class, but also the same as using HTML to use JS to create a complete style sheet, how to do?

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 = ' padding: 0px; max-width: 1000%; box-sizing: border-box !important; word-wrap: break-word !important; text-align: left; font-size: 14px; white-space: pre; display: flex; position: relative; font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;">// 或者el.setAttribute('style', ' padding: 0px; max-width: 100%; box-sizing: border-box; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; font-size: 17px; letter-spacing: 0.544px; color: rgb(33, 37, 41); line-height: 1.75em; word-wrap: break-word !important;">直接在.style对象上设置样式属性将需要使用驼峰式命名作为属性键,而不是使用短横线命名。 如果咱们需要设置更多的内联样式属性,则可以通过设置.style.cssText属性,以更加高效的方式进行设置 。请记住,给cssText设置后原先的css样式被清掉了,因此,要求咱们一次死一堆样式 。如果这种设置内联样式过于繁琐,咱们还可以考虑将.styleObject.assign()一起使用,以一次设置多个样式属性。
// ...Object.assign(el.style, {    backgroundColor: "red",    margin: "25px"})
这些“基本知识”比咱们想象的要多得多。.style对象实现CSSStyleDeclaration接口。这说明它带还有一些有趣的属性和方法,这包括刚刚使用的.cssText,还包括.length(设置属性的数量),以及.item().getPropertyValue().setPropertyValue()之类的方法:
// ...const propertiesCount = el.style.lengthfor(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()    }}
这里有个小窍门-在遍历过程中.item()方法具有按索引访问形式的备用语法。
// ...el.style.item(0) === el.style[0]; // true

CSS 类

接着,来看看更高级的结构——CSS类,它在检索和设置时具有字符串形式是.classname
// ...el.className = "class-one class-two";el.setAttribute("class", "class-one class-two");
设置类字符串的另一种方法是设置class属性(与检索相同)。 但是,就像使用.style.cssText属性一样,设置.className将要求咱们在字符串中包括给定元素的所有类,包括已更改和未更改的类。当然,可以使用一些简单的字符串操作来完成这项工作,还有一种就是使用较新的.classList属性,这个属性,IE9 不支持它,而 IE10 和 IE11 仅部分支持它。classlist属性实现了DOMTokenList,有一大堆有用的方法。例如.add().remove()、.toggle()和.replace()允许咱们更改当前的 CSS 类集合,而其他的,例如.item().entries().foreach()则可以简化这个索引集合的遍历过程。
// ...const classNames = ["class-one", "class-two", "class-three"];classNames.forEach(className => {    if(!el.classList.contains(className)) {        el.classList.add(className);    }});

Stylesheets

一直以来,Web Api 还有一个StyleSheetList接口,该接口由document.styleSheets属性实现。 document.styleSheets 只读属性,返回一个由 StyleSheet 对象组成的 StyleSheetList,每个 StyleSheet 对象都是一个文档中链接或嵌入的样式表。
for(styleSheet of document.styleSheets){    console.log(styleSheet);}
通过打印结果咱们可以知道,每次循环打印的是 CSSStyleSheet 对象,每个 CSSStyleSheet 对象由下列属性组成:
Attributes description
media Get the current role of the media style.
disabled Open or disable a style sheet.
href Return style table address CSSStyleSheet connected objects.
title Return value CSSStyleSheet title object.
type Return CSSStyleSheet object type value, usually text / css.
parentStyleSheet Returns the current style sheet that contains the piece of style sheets.
ownerNode Back CSSStyleSheet DOM node object is located, typically <link> or <style>.
cssRules Return all the rules of style sheets.
ownerRule

If it is introduced through @import, Pointer to the attribute rule is introduced, null otherwise

. IE does not support this property.

CSS Style Sheet对象方法:
method description
insertRule() In the current stylesheet cssRules object into a CSS rule.
deleteRule() In the current style sheet object to delete cssRules CSS rules.
有了StyleSheetList的全部内容,咱们来CSS StyleSheet本身。 在这里就有点意思了, CSS StyleSheet扩展了StyleSheet接口,并且只有这种只读属性,如.ownerNode.href.title.type,它们大多直接从声明给定样式表的地方获取。回想一下加载外部CSS文件的标准HTML代码,咱们就会明白这句话是啥意思:
<head><link rel="stylesheet" type="text/css" href="style.css" title="Styles"></head>
现在,咱们知道HTML文档可以包含多个样式表,所有这些样式表都可以包含不同的规则,甚至可以包含更多的样式表(当使用@import时)。CSSStyleSheet有两个方法:、.insertrule().deleterule() 来增加和删除 Css 规则。
// ...const ruleIndex = styleSheet.insertRule("div {styleSheet.deleteRule(ruleIndex);
.insertRule(rule,index):此函数可以在cssRules规则集合中插入一个指定的规则,参数rule是标示规则的字符串,参数index是值规则字符串插入的位置。deleteRule(index):此函数可以删除指定索引的规规则,参数index规定规则的索引。CSSStyleSheet也有自己的两个属性:.ownerRule.cssRule。虽然.ownerRule@import相关,但比较有趣的是.cssRules 。简单地说,它是CSSRuleListCSSRule,可以使用前面提到的.insertrule().deleterule()方法修改它。请记住,有些浏览器可能会阻止咱们从不同的来源(域)访问外部CSSStyleSheet的.cssRules属性。那么什么是 CSSRuleListCSSRuleList是一个数组对象包含着一个有序的CSSRule对象的集合。每一个CSSRule可以通过rules.item(index)的形式访问, 或者rules[index]。 这里的rules是一个实现了CSSRuleList接口的对象, index是一个基于0开始的,顺序与CSS样式表中的顺序是一致的。样式对象的个数是通过rules.length表达。对于CSSStyleRule对象:每一个样式表CSSStyleSheet对象可以包含若干CSSStyleRule对象,也就是css样式规则,如下:
<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 {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/xiewangfei123/p/12047247.html