DOM
DOM:文档对象模型。
文档:整个HTML网页文档;
对象:对象表示将网页中的每一个部分都转化为了一个对象;
模型:使用模型来表示对象之间的关系,这样方便我们获取对象;
DOM作用:JS中通过DOM来对HTML文档进行操作,随心所欲的操作Web页面。
节点
节点:构成网页的最基本的组成部分,网页中每一个部分都可以称为一个节点。构成HTML文档的最基本的单元
节点分类
元素节点:HTML文档中的HTML标签
属性节点:元素的属性
文本节点:HTML标签中的文本内容
节点属性
nodeName
nodeType
nodeValue
浏览器已经为我们提供了文档节点对象document,这个对象是window对象的属性,可以在页面中直接使用,文档节点代表的是整个网页。
DOM查询
获取元素节点
通过document对象调用
- getElementById():通过id属性获取一个元素节点对象;
- getElementsByTagName():通过标签名获取一组元素节点对象;会返回一个类数组对象,所有查询到的元素都会封装到这个对象中;即使查询到的元素只有一个,也会封装到数组中返回。
- getElementsByName():通过name属性获取一组元素节点对象
- getElementsByClassName():根据元素的class属性值查询一组元素节点对象(IE8及以下不支持)
- querySelector():可以根据css选择器来查询元素
document.querySelector('.box1 div')
(虽然在IE8中没有getElementsByClassName(),但是可以使用querySelector()代替,可以根据类名,id,选择器查)。使用该方法总会返回唯一的一个元素,如果满足条件的有多个,但是只会返回第一个。 - querySelectorAll():与querySelector()类似,不同的是它会将符合条件的元素作为数组都返回,即使符合条件的元素只有一个,也会返回一个数组。
节点关系
每一个节点都有一个childNodes属性,parentNode属性。对于childNodes中的同胞节点,可以使用previousSibing和nextSibling属性表示当前节点的第一个兄弟节点及当前节点的最后一个兄弟节点。可以使用firstChild和lastChild分别指向chlidNodes中的第一个节点和最后一个节点。因此someNode.firstChild == someNode.childNodes[0]; someNode.lastChild == someNode.childNodes[someNode.childNodes.length-1];
获取元素节点的子节点
通过具体的元素节点调用
- getElementsByTagName():方法,返回当前节点的指定标签名后代节点;
- childNodes: 属性,表示当前节点的所有子节点;会获取包括文本节点在内的所有节点,DOM标签间的空白也会当成文本节点。在IE8及以下的浏览器中,不会将空白文本当成子节点。
- children 属性可以获取当前元素的所有子元素,不会将空白文本当成子节点。
- firstChild:属性,标签当前节点的第一个子节点(包括空白文本节点);
- firstElementChild:可以获取到当前元素的第一个子元素(不包括空白文本节点),不支持IE8及一下的浏览器。
- lastElementChild:返回元素的最后一个子元素(不包括文本和注释节点)
- lastChild:属性,表示当前节点的最后一个子节点(包括空白文本节点)
获取父节点和兄弟节点
通过具体的节点调用
- parentNode:属性,表示当前节点的父节点(也可能会获取到空白的文本)
- previousSibing:属性,表示当前节点的前一个兄弟元素(IE8及以下不支持)
- nextSibling:属性,表示当前节点的后一个兄弟节点
- previousElementSibing:获取前一个兄弟元素(IE8及以下不支持)
- nextElementSibling:返回相同节点树级别的下一个元素(不包括文本和注释节点)
补充:
innerHTML:通过这个属性可以获取到元素内部的HTML代码;对于自结束标签,这个属性没有意义,比如input标签,如果需要读取元素节点属性,直接使用元素.属性名。input[i].innerHTML
错误,input[i].value
正确;而对于class属性不能采用这种方式,读取class属性时需要使用元素.classNameinput[i].className
innerTEXT:该属性可以获取到元素内部的文本内容,它和innerHTML类似,不同的是它会自动将html去除
DOM查询的其他方法
获取body标签:在document中有一个属性body,它保存的是body的引用var body = document.body
获取html标签:document.documentElement
保存的是html根标签
获取页面中所有元素:
document.all
document.getElementsByTagName('*')
DOM增删改
- 创建元素节点:createElement()创建一个元素节点对象,需要一个标签名作为参数,将会根据该标签名创建元素节点对象,并将创建好的对象作为返回值返回
document.createElement('li')
- 创建文本节点:createTextNode()创建一个文本节点对象,需要一个文本内容作为参数,并将新的节点作为返回值返回
let gzText = document.createTextNode('广州')
,这一步可以采用innerHTMLli.innerHTML = '广州'
- 父节点中添加一个新的子节点:appendChild();用法:
父节点.appendChild(子节点)
;eg:city.appendChild(gzText )
- 在指定的子节点前面插入新的子节点:insertBefore();该方法需要传递两个参数
父节点.insertBefore(newNode,oldNode)
- 使用指定的子节点替换一有的子节点:replaceChild();
父节点.replaceChild(newNode,oldNode)
- 删除一个子节点:removeChild();
父节点.removeChild(子节点)
==子节点.parentNode.removeChild(子节点)
- 使用innerHTML也能完成相关的增删改查的操作,但是innerHTML相当于重新创建所有,如果在以前的节点上绑定了事件,那么使用innerHTML以后,以前绑定的事件就不会存在了。(不建议使用)
- 推荐innerHTML+append的方式
通过JS修改元素的样式
语法:元素.style.样式名 = 样式值;
注意:
- 如果CSS的样式名中含有-,这种名称在JS中是不合法的,比如
box1.style.background-color = 'pink';
应改为驼峰命名法box1.style.backgroundColor = 'pink'
- 通过style设置的样式为内联样式,而内联样式有较高的优先级,所以通过JS修改的样式往往会立即执行,但是如果在样式中写了!important,则此时样式会有最高的优先级,即使通过JS也不能覆盖该样式,此时将会导致JS修改样式失效,所以尽量不要为样式添加!important。
- 通过style属性来修改元素的样式,每修改一个样式,浏览器就需要重新渲染一次页面;这样执行的性能比较差而且如果修改多个样式时会不方便;
- 因此可以采用修改元素的class属性来间接修改元素样式
box.className = 'b2'
,这样一来我们只需要修改一次,即可同时修改多个样式。浏览器只需要重新渲染一次,性能比较好,而且这种方式,可以使表现和行为分开控制。 - 如果只修改部分样式
box.className += ' b2'
;注意引号里面为空格 b2;
读取内联样式:
语法:元素.style.样式名.样式值;
注意:
- 通过style属性设置和读取的都是内联样式,无法读取样式表中的样式(也就是说无法读取style中的样式)
获取元素的当前显示的样式
ie浏览器:
语法:元素.currentStyle.样式名;
(只有IE浏览器支持)
其他浏览器:
可以使用getComputedStyle()这个方法来获取元素当前的样式,这个方法是window的方法,可以直接使用。
- 需要两个参数:1.要获取样式的元素;2.可以传递一个伪元素,一般传null;
- 该方法会返回一个对象,对象中封装了当前元素对应的样式,可以通过对象.样式名来读取样式,如果获取的样式没有设置,则会获取到真实的值,而不是默认值。
alert(getComputedStyle(box1,null).width);
- IE8及以下浏览器不支持
兼容写法(重要)
<script type="text/javascript">
//兼容写法
//obj: 要获取的样式
//name: 要获取的样式名
function getStyle(obj,name){
/*不能写为getComputedStyle(obj,null).name,因为在对象中.name是个字符串,而不是一个变量,这里不能写死*/
//没必要判断浏览器的类型,直接判断浏览器是否有getComputedStyle()方法,验证了一下getComputedStyle是个对象
/*必须加window,不然会在ie8报错,因为如果找一个变量,如果在函数作用域中没找到,就会在全局作用域找,在全局作用域找如果没找到就会报错
因此必须加window,没有加window,他是一个变量,需要去作用域中寻找,加了window,就变成window的一个属性,没有这个属性,就会返回undefined
*/
if(window.getComputedStyle){
return getComputedStyle(obj,null)[name];
}else{
return obj.currentStyle[name];
}
}
window.onload = function () {
let box1 = document.getElementById('box1');
let btn01 = document.getElementById('btn01');
btn01.onclick = function () {
//获取元素的当前显示的样式
//语法:元素.currentStyle.样式名(IE浏览器)
alert(box1.currentStyle.width);
//语法:getComputedStyle()(其他浏览器,iE8及以下不支持)
alert(getComputedStyle(box1,null).width);
//兼容
alert(getStyle(box1,'width'));
}
}
</script>
注意:
通过currentStyle,getComputedStyle()读取到的样式都是只读的,不能修改,如果要修改,必须通过style。
其他样式相关的属性
clientHeight和clientWidth
- 获取元素的可见宽度和高度;
- 不带px,返回都是一个数字,可以直接进行计算
- 会获取元素的高度和宽度,包括内容去和内边距,不包括外边距
- 只读,不能修改
offsetHeight和offsetWidth
- 获取元素的整个宽度和高度;
- 不带px,返回都是一个数字,可以直接进行计算
- 会获取元素的高度和宽度,包括内容去和内边距,外边距
- 只读,不能修改
offsetParent
- 可以获取当前元素的定位父元素
- 会获取到离当前元素最近的开启了定位的祖先元素
- 如果所有的祖先元素都没有开启定位,那么返回body
offsetLeft和ofsetRight
- 可以获取当前元素相对于其定位父元素的水平偏移量和垂直偏移量
scrollHeight和scrollWidth
- 可以获取元素整个滚动区域的宽度和高度
scrollLeft和scrollTop
- 可以获取水平滚动条和垂直滚动条滚动的距离
- scrollHeight - scrollTop == clientHeight表示垂直滚动条到底了
- scrollWidth - scrollLeft== clientWidth表示水平滚动条到底了
事件
事件:文档或浏览器窗口发生的一些特定的交互瞬间。
可参考事件一
可参考事件二
事件冒泡
事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发
取消冒泡:event.cancelBubble = true
判断触发事件的对象是否为想要的对象:event.target.className == 'link'
文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,读取到一行就运行一行;如果将script标签写在页面的上边,在代码执行时,页面还没有被加载。因此一般情况下,将js代码写在页面的下边。
如果不想将script标签写在页面的下面,可以使用onload事件,onload事件会在整个页面加载完成后才触发
window.onload = function(){
alert('hello');
}
一般来说,为了考虑性能,还是建议将JS代码写在页面的下面,因为,即使可以使用onload事件,此时写在上面的JS代码先加载,但是加载又不执行,需要等在整个页面加载完成后在执行,因此影响性能,建议写在页面下面
键盘事件
一般都会绑定给一些可以获得焦点的对象或者document;比如input
onkeydown
- 键盘被按下;
- 如果一直按着某个时间不松手,则事件会一直被触发;
- 当onkeydown连续触发时,第一次和第二次的间隔会长一点其他的会非常快。这种设计是为了防止误操作发生
onkeydown
- 键盘被松开