JavaScript 脚本化CSS
脚本化css非常重要,脚本化就是控制的意思,Dom操作可以控制Css,但不是完全直接的控制,是存在一个间接的行为,Dom是不能操作Css的但是可以间接的操作Css
一、读写元素css属性
dom.style.prop
可读写行间样式,没有兼容性问题,碰到float这样的关键字属性,前面应加css
eg:float — > cssFloat
复合属性必须拆解,组合单词变成小驼峰式写法
写入的值必须是字符串格式
第一个最常用的方法是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. 下面这些虽然我们没设置,也没写值但是确实是存在的,只有我们设置的那三个是有值的(往下找)
往下找肯定还有一个length属性,没有css属性叫length,肯定是类数组的length
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完全都是读取操作没有写入操作,下面是读取操作查询计算样式
二、查询计算样式
window.getComputedStyle(ele,null);
计算样式只读
返回的计算样式的值都是绝对值,没有相对单位
IE8 及 IE8以下不兼容
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 获取的名字一样)
把这个样式表打开也是一个类数组,有很多的索引属性下面还有很多对应的属性
但会发现有一个不同的一点,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
三、查询样式
ele.currentStyle
计算样式只读
返回的计算样式的值不是经过转换的绝对值
IE独有的属性
封装兼容性方法getStyle(obj,prop);
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让伪元素改变颜色,怎么改变伪元素的?
这个下尖角号当点击的时候变上尖角号了,这个尖角号从结构上它充当伪元素的作用,伪元素把它放到后面。伪元素在操作的时候是需要改变一些东西的包括颜色、字体…怎么改变伪元素?
比如,改变点击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>
小方块还是在大方块里面
为什么小方块在大方块里?
说明 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>