Go to comments

JavaScript 脚本化CSS

脚本化css非常重要,脚本化就是控制的意思,Dom操作可以控制Css,但不是完全直接的控制,是存在一个间接的行为,Dom是不能操作Css的但是可以间接的操作Css


一、读写元素css属性


第一个最常用的方法是DOM上的一个 style 属性,这个 style属性普遍存在任何dom元素上,是个dom元素就可以用这个属性


 div.style  之后返回什么?

<div style="width:100px; height:100px; background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style); // CSSStyleDeclaration {0: "width", 1: "height", 2: "background-color", alignContent: "", alignItems: "", alignSelf: "", alignmentBaseline: "", all: "", …}
    
</script>

返回的是 CSSStyleDeclaration



Declaration 是宣誓,声明的意思,

CSSStyleDeclaration 是一个css样式表的声明,意思是把这个div能够用的所有的css全给展示出来了,这个div所有能用的css不光有我们写的那些,除了我们写的那些还有好多能用的


然后把CSSStyleDeclaration点开,首先会发现它是一个类数组,因为有索引位的属性还有正常位的属性,只要这两同时存在就是一个类数组

1. 这个类数组,前三位width、height、background-color是我们设置的,

2. 下面这些虽然我们没设置,也没写值但是确实是存在的,只有我们设置的那三个是有值的(往下找)

image.png


往下找肯定还有一个length属性,没有css属性叫length,肯定是类数组的length

image.png


CSSStyleDeclaration返回的样式表非常有意思,是 可读  和  可写 的,也就说是可以被改变的,怎么改变呢?

首先样式表是类数组,类数组本质上是对象,是个对象就可以存取它的属性。


 div.style['width']  现在就存取div对象的 width 属性,然后  div.style.width  这种方式也行,打印结果返回 100px

<div style="width:100px; height:100px; background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.width); // 100px
    
</script>


写入属性的值必须是字符串形式  div.style.width = "200px" 

<div style="width:100px; height:100px; background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.width = "200px"; // "200px"值必须是字符串形式
  div.style.height = "300px";
    
</script>

反馈的页面上div元素就变成 200px * 300px 的尺寸



这就是间接的改变一个元素的css属性,为什么叫间接改变呢?

 div.style  是改变行间的样式,其实本质上还是操作HTML元素,操作改变元素上的属性,而这个属性就能影响Css叫行间样式,所以叫间接的改变Css


怎么设置div的背景颜色?

js变量名不能以数字开头,中间的组成部分包括数字、下划线、英文字母以及$符号,没有"中划线"不能包含特殊字符(CSS里是可以有中划线)

<div style="width:100px; height:100px; background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.background-color = 'red'; // 这就出问题了,在js里访问属性的时候没有杠的形式

    
</script>


js里面"中划线"不行怎么办?

js语法但凡是 background-color 变成小驼峰式命名规则  backgroundColor  就可以访问了还可以向里面赋值

<div style="width:100px; height:100px; background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.backgroundColor = 'red'; // 改变背景颜色
    
</script>



width、height、backgroundColor 这三个属性都是我们写到行间里的,没有写到行间里面能改变吗?

 borderRadius  圆角样式之前没写过  div.style.borderRadius  能实现吗?不管之前写没写,有一条是肯定的 CSSStyleDeclaration 里面包含了所有可被设置的属性,既然包含了里面没有值我们就可以设置值

<div style="width:100px;height:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.borderRadius = '50%';

</script>



div.style 是可以读可以写的,

width属性写到行间  div.style.width  才能取到值,width写到style标签里面,虽然Css样式生效但 div.style 取不到值,div.style 不论是读的还是写的都会被写到行间

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>读写元素css属性</title>
<style type="text/css">
  div{
    width:200px; 
  }
</style>
</head>
<body>

<div style="height:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.height); // height肯定有值返回100px

  console.log(div.style.width); // width没有值

</script>
</body>
</html>


比如通过 div.style 写一个 width:100px 的行间进去

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>读写元素css属性</title>
<style type="text/css">
  div{
    width:200px;
  }
</style>
</head>
<body>

<div style="height:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.width = "100px"; // 写width:100px

</script>
</body>
</html>


width:100px 被写到了行间上 

 <div style="height: 100px; background-color: aqua;  width: 100px;  "></div> 


这个 dom.style.prop 以后是最常用到的,没有任何兼容性问题,碰到复合属性必须拆解变成小驼峰式写法


然后碰到关键字比如 float,float在其它语言是浮点型声明变量的意思,

 div.style.float  这样写其实是可以的也能够展示出来,但是W3C标准告诉我们尽量别这样写,因为 float 是保留字未来可能会用

<div style="float:left; height:100px;width:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.float); // left

</script>


W3C标准float怎么些呢?float前面加一个css前缀  div.style.cssFloat 

<div style="float:left; height:100px;width:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.cssFloat); // left

</script>


复合属性必须拆解,比如border属性一个代表三个

<div style="height:100px;width:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.borderColor = "saddlebrown";

  div.style.borderWidth = "10px";

  div.style.borderStyle = "dotted";

</script>



PS:

 borderStyle有很多个属性。


当然就想这样 div.style.border 写行不行呢?原来这样不行,现在这样可以,但是尽量用上面的方式写

<div style="height:100px;width:100px;background-color:aqua;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.style.border = "6px solid saddlebrown";

</script>



js间接的操作css,操作,其实就两点读取和写入,

除了上面的 Ele.style 方法再也没有任何方法可以写入值了,

接下来的间接操作css完全都是读取操作没有写入操作,下面是读取操作查询计算样式


二、查询计算样式


1、window.getComputedStyle( ele, null )

window上有个方法  getComputedStyle(ele, null)  叫获取计算样式


下面代码中 

1. width 属性是在<style>标签里面设置的,

2. float、height、background-color 是在行间设置的,没有重复的属性

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
<style type="text/css">
  div{
    width:200px; /* width属性在style标签里面设置 */
  }
</style>
</head>
<body>

  <div style="float:left;height:100px;background-color:aqua;float:left;"></div>

</body>
</html>



现在通过  window.getComputedStyle(div, null)  方法获取div上的width属性

第一个参数,填要获取的div元素,

第二个参数,不用管先填null

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
<style type="text/css">
  div{
    width:200px; /* width属性在这设置 */
  }
</style>
</head>
<body>

<div style="float:left;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null)); // CSSStyleDeclaration

</script>
</body>
</html>

 window.getComputedStyle(div, null)  获取div元素的样式表也是  CSSStyleDeclaration  (和用 dom.syle 获取的名字一样)

image.png


把这个样式表打开也是一个类数组,有很多的索引属性下面还有很多对应的属性

image.png

但会发现有一个不同的一点,elem.style 获取的样式表没有设置的属性就没有值(值是空的),这个样式表不管设置不设置属性的都有值(默认值)


计算样式 window.getComputedStyle(div, null) 

获取的是当前这个元素所展示出的一切css属性的显示值,获取的是最终显示出来的css属性值包括默认值,


计算样式获取出来的也是一个对象,对象的width属性是多少  window.getComputedStyle(div, null).width  素展示出来的width是"200px"

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
<style type="text/css">
  div{
    width:200px; /* width属性在这设置 */
  }
</style>
</head>
<body>

<div style="float:left;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null).width); // 200px;

</script>
</body>
</html>


在行间加一个  width:100px  再获取完后是多少?获取的是"100px"

<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
</head>
<body>
<style type="text/css">
  div{
    width:200px;
  }
</style>

 <div style="width:100px;height:100px;background-color:aqua;float:left;"></div> <!-- 行间加一个"width:100px" -->

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null).width); // 100px

</script>
</body>
</html>


如果在<style>标签的 width属性后面加一个  !important  呢?这回获取的是"200px"

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
</head>
<body>
<style type="text/css">
  div{
    width:200px!important; /* 这加一个!important呢? */
  }
</style>

<div style="width:100px;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null).width); // 200px

</script>
</body>
</html>


用之前的  div.style.width  获取的还是"100px",因为  div.style  获取的就是行间的,行间没写  div.style.width  就认为没有

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>div.style</title>
</head>
<body>
<style type="text/css">
  div{
    width:200px!important; /* 这加一个!important呢? */
  }
</style>

<div style="width:100px;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.width); // 获取的样式是100px

</script>
</body>
</html>


获取元素的显示样式谁更准一些呢?

肯定  window.getComputedStyle(div, null)  更准一些,因为它获取的是最终展示的样式,它不看是不是行间的,看的是最后权重高的


2、计算样式只读

计算样式表 只读 不能 写入,写入样式会报错

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
</head>
<body>
<style type="text/css">
  div{
    width:200px!important;
  }
</style>

<div style="width:100px;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  window.getComputedStyle(div, null).width = "600px"; // Uncaught DOMException: Failed to set the 'width' property on 'CSSStyleDeclaration': These styles are computed, and therefore the 'width' property is read-only.

</script>
</body>
</html>


报错信息 

 These styles are computed  这些样式是计算过的,

 'width' property is read-only  属性width是只读的


3、返回的计算样式的值,不是经过转换的绝对值

 window.getComputedStyle()  Computed是计算的意思,为什么叫 getCompute 呢?因为返回的都是最后的绝对值


什么叫绝对值?

em是相对值、其实像素也是相对值,但计算机认为像素是绝对的。em以像素为基本值的,em相对像素来说肯定是相对值。


1em默认值是16像素,10em十倍是160px, window.getComputedStyle(div, null).width  获取的不可能是10em,获取的是计算完的 "160px"

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
</head>
<body>
<style type="text/css">
  div{
    width:10em; /* 这块写一个"10em" */
  }
</style>

<div style="height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null).width); // 160px

</script>
</body>
</html>


 window.getComputedStyle(div, null)  获取完的值都是经过计算的,背景颜色获取的是什么样子?系统会转换成rgb形式的  rgb(0, 255, 255) 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>查询计算样式</title>
</head>
<body>
<style type="text/css">
  div{
    width:10em;
  }
</style>

<div style="height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(window.getComputedStyle(div, null).backgroundColor); // rgb(0, 255, 255)

</script>
</body>
</html>


getComputedStyle()会把百分号、em、相对的颜色表示形式都给换化成绝对的形式返回,所以它叫获取计算样式


4、IE8 及 IE8以下不兼容

然后IE8及IE8以下不兼容,既然不兼容看看IE8及其IE8以下用什么?在IE浏览器里面用  currentStyle 


三、查询样式


IE8及IE8以下用的是  div.currentStyle  也会返回一个  CSSStyleDeclaration 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
  div{
    width:200px;
  }
</style>
<title>查询样式</title>
</head>
<body>

<div style="height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.currentStyle); // [object CSSCurrentStyleDeclaration]

  alert(div.currentStyle['width']); // 200px

</script>
</body>
</html>


currentStyle有一些注意点

1. 也是只能获取不能写入

2. 返回的样式不是计算的值,写em就是em、写百分号就是百分号,获取的就是原封不动的那个值,获取的就是最终元素展示的那个值,获取的就是权重最高的那个值

3. IE8独有的属性


封装一个兼容性方法 getStyle(obj, prop) ,获取样式的时候在任何一个浏览器都好用,这是一个很实用的方法以后会经常用到

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>封装兼容方法getStyle(obj, prop)</title>
<style type="text/css">
  div{
    width:200px;
  }
</style>
</head>
<body>

<div style="height:100px;background-color:aqua;float:left;"></div>

<script>

  function getStyle(elem, prop){
    if(window.getComputedStyle){
      return window.getComputedStyle(elem, null)[prop]; // 中括号很好的解决了参数的问题
    }else{
      return elem.currentStyle[prop];
    }
  }

  var div = document.getElementsByTagName('div')[0];

  alert(getStyle(div, 'width')); // 200px

</script>
</body>
</html>


四、window.getComputedStyle(div, null) 第二个参数

回归一下,刚才有个没解决的问题

 window.getComputedStyle(div, null)  第二个参数为什么是null?

这个知识百分之99.9的人都不会,如何选择伪元素,为什么伪元素叫伪元素?伪元素客观存在但就是找不到它,伪元素像元素但是它又不是元素


第二个参数解决的就是获取伪元素的问题,用它可以获取元素的样式表

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>getComputedStyle()第二个参数选伪元素</title>
<style type="text/css">
  div{
    width:200px;
  }
  div::after{ /* 加上伪元素 */
    content:"";
    width:50px;
    height:50px;
    background-color: #FFA500;
    display: inline-block; /* 伪元素的默认值是inline,这里用inline-block不然加不了宽高 */
  }
</style>
</head>
<body>

<div style="height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  // console.log(window.getComputedStyle(div, 'after')); // CSSStyleDeclaration

  console.log(window.getComputedStyle(div, 'after').width); // 50px

</script>
</body>
</html>


这是获取伪元素的唯一方法,

第一个参数写元素div,第二个参数写伪元素after,这个方法用的非常少,不获取伪元素就写一个 null、0、false 都可以


伪元素是有操作的需求的,点击div让伪元素改变颜色,怎么改变伪元素的?

这个下尖角号当点击的时候变上尖角号了,这个尖角号从结构上它充当伪元素的作用,伪元素把它放到后面。伪元素在操作的时候是需要改变一些东西的包括颜色、字体…怎么改变伪元素?

image.png


比如,改变点击div让伪元素变黄颜色

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>点击伪元素变背景色</title>
<style type="text/css">
  .green::after{
    content:"";
    width:50px;
    height:50px;
    background-color: green;
    display: inline-block;
  }
  .yellow::after{ /* 加一个伪元素样式 */
    content:"";
    width:50px;
    height:50px;
    background-color: yellow; /* 两个伪元素就颜色不一样 */
    display: inline-block;
  }
</style>
</head>
<body>

<div class="green" style="width:100px;height:100px;background-color:aqua;float:left;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.onclick = function(){
    this.className = "yellow"; // 通过js动态改变div行间的class属性(class="green")
  }

</script>
</body>
</html>


其实没有通过js去改变伪元素里面的东西,改变的是换了一个class行间属性,

功能已经定义到class里写好了,这是一个很系统的编程思路,虽然通过 div.style 的方式改变Css,然而真正普遍状态下常态改变Css就这么改


通过点击的方式,点击一次把div的变成 "200px * 200px" 然后背景颜色绿色的方块

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>div点击变尺寸变背景颜色</title>
<style type="text/css">
  div{
    width:100px;
    height:100px;
    background-color: red;
  }
</style>
</head>
<body>

<div></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.onclick = function(){
    div.style.height = "200px";
    div.style.width = "200px";
    div.style.backgroundColor = "green";
  }

</script>
</body>
</html>


还可以设置再点击一次div又变回来,

这样的状态改变最好的方式不这样处理,凡是这种发生状态切换的情况下,我们把状态提前预先编辑好,改变css状态通过权重的覆盖也行


通过改变class的方式和css进行配合,点击div变成绿色的方块

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>className</title>
<style type="text/css">
  div{
    width:100px;
    height: 100px;
    background-color: red;
  }
  .active{
    width:200px;
    height: 200px;
    background-color: green;
  }
</style>
</head>
<body>

<div></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  div.onclick = function(){
    this.className = "active"; // 给一个div或一个DOM元素改class用className就行
  }

</script>
</body>
</html>


强调一下,

给一个div或一个DOM元素改class用 className 就行,class不是属性是保留字所以用 className 对应class,通过这种方式改变div的状态有几个好处


第一个好处是效率问题,

DOM操作是js和html搭建一个桥梁,一个 div.style.width 就会浪费一个效率,再 div.style.height 还会浪费一个效率,而且连续这样会浪费很多效率,

而这样  div.className = "green"  一步操作虽然也损耗了一部分效率,但明显感觉从操作上就小,从内部的效率上更是简便。


第二点好维护,

以后想改状态直接到 style 标签里改,js只负责状态切换状态,

好维护省效率是 className 的优点,所以普遍情况下一些改变状态位的js操作就这么来改,其实改的是class,这样是一个正常的编程想法,

但是也不是所有操作都能这样去完成,比如动画效果让一个方块去移动,那就要动态的改变style,因为每个状态都不一样。


五、小练习,让方块运动

怎么让一个方块去运动?

当第一次执行运动函数的时候,我们想要当前方块的当前横坐标加上我们所想加的值,然后函数执行完了之后方块变了一个位置,然后再次执行这个函数的时候,我们还想知道方块当前的位置,求方块当前位置再加上我们所理想的值。


getStyle(div, 'left') 方法就是求当前方块位置的方法,然后后面加上我们所理想的值,

然而这样还不行,要把 position:absolute 设置上,left的值要写0,因为默认值是auto


top和left默认值是什么?外面的大方块套着一个小方块,小方块只设置一个 position: absolute 没设置left和top,小方块在大方块里面还是在页面的最顶端?

<div style="width:100px;height:100px;background-color:yellow;position:absolute;left:30px;">
  <div style="width:30px;height:30px;background-color:red;position:absolute;"></div>
</div>

<div style="width:100px;height:100px;background-color:yellow;position:absolute;top:120px;left:90px;">
  <div style="width:30px;height:30px;background-color:red;position:absolute;"></div>
</div>

<div style="width:100px;height:100px;background-color:yellow;position:absolute;top:240px;left:150px;">
  <div style="width:30px;height:30px;background-color:red;position:absolute;"></div>
</div>

小方块还是在大方块里面

image.png


为什么小方块在大方块里?

说明 left 和 top 的默认值不是0,如果默认值是0那大方块根本带不动小方块,left 和 top的默认值是auto,大方块带着去那小方块就去那,是出生点的位置

<div style="width:100px;height:100px;background-color:#FFA500;position:absolute;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(div.style.left); // 返回空,因为行间没写left

  console.log(getStyle(div, 'left')); // 返回8px,因为是计算后的样式

  function getStyle(elem, prop){
    if(window.getComputedStyle){
      return window.getComputedStyle(elem, null)[prop];
    }else{
      return elem.currentStyle[prop];
    }
  }

  // left在IE里可以测出来默认值是auto
</script>


行间加一个  left: 0  获取出来的是"0px",然而我们只想要数字0,用  parseInt()  返回数字 0

<div style="width:100px;height:100px;background-color:#FFA500;position:absolute;left:0;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  console.log(getStyle(div, 'left')); // 获取出来的是"0px",然而我们只想要数字0

  console.log(parseInt(getStyle(div, 'left'))); // 用parseInt返回数字 0

  function getStyle(elem, prop){
    if(window.getComputedStyle){
      return window.getComputedStyle(elem, null)[prop];
    }else{
      return elem.currentStyle[prop];
    }
  }

</script>


10毫秒运动一次每次加1px,运动的非常平缓

<div style="width:100px;height:100px;background-color:#FFA500;position:absolute;left:0;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  var timer = setInterval(function(){

    div.style.left = parseInt(getStyle(div, 'left')) + 1 + 'px'; // 改变着变的更细腻

  }, 10); // 改变这控制速度


  function getStyle(elem, prop){
    if(window.getComputedStyle){
      return window.getComputedStyle(elem, null)[prop];
    }else{
      return elem.currentStyle[prop];
    }
  }

</script>


还可以加速运动越来越快

<div style="width:100px;height:100px;background-color:#FFA500;position:absolute;left:0;"></div>

<script>

  var div = document.getElementsByTagName('div')[0];

  var speed = 1; // 设置一个speed

  var timer = setInterval(function(){

    speed += speed/7; // 然后...
    
    div.style.left = parseInt(getStyle(div, 'left')) + speed + 'px'; // speed在这用

    if(parseInt((div.style.left)) > 600){
      clearInterval(timer);
    }

  }, 10);

  function getStyle(elem, prop){
    if(window.getComputedStyle){
      return window.getComputedStyle(elem, null)[prop];
    }else{
      return elem.currentStyle[prop];
    }
  }

</script>



Leave a comment 0 Comments.

Leave a Reply

换一张