web APIs:DOM
文档对象模型(Document Object Model,简称DOM )),是W3C组织推荐的处理可扩展标记语言(HTML或者XML )的标准编程接口。
DOM树,所有都看做对象
文档:一个页面就是一个文档,DOM中使用document表示
元素︰页面中的所有标签都是元素,DOM中使用element表示
节点∶网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
1、获取元素
根据ID获取:getElementById(),返回一个匹配到ID的DOM Element对象。若在当前Document下没有找到,则返回null。
根据标签名获取:getElementByTagName(),返回的是一个伪数组的集合,若为空,返回空伪数组;其元素对象是动态的。可以element.getElementByTagName()获取父元素下子元素内容,不包含父元素,一般给父元素添加id指定
通过HTML5新增的方法获取:querySelector('选择器'),返回第一个元素;getElementByClassName();querySelectorAll('选择器'),返回所有符合条件元素,为数组, .class为类,#nav为id,标签不用加。H5下新增,需要兼容,该方法返回集合
特殊元素获取: document.body、document.documentElement
若要获取某些元素,可以用 getElementById().getElementByTagName()或其他组合
2、事件:触发响应机制,如鼠标点击
事件源 var btn = document.getElementById('btn');
事件类型 btn.onclick 绑定事件
事件处理程序 btn.onclick = function(){ alert('点击') }
3、操作元素
改变内容:.innerText,替换内容,不识别html标签和空格换行;.innerHTML 替换内容,识别html标签,保留空格和换行
修改元素属性:1、获取元素id或者标签等 2、注册事件 id.onclick 3、属性修改 cjj.onclick = fuction(){ img.src = '路径' } 点击改变图片
修改表单属性:type、value、checked、selected、disabled
修改样式属性:element.style()行内样式操作,新建行内样式style, 行内样式权重高、element.className(新类名)类内样式操作,引用新类,新类会覆盖旧类
获取元素属性:element.getAttribute('属性'); 该属性不但可以调用内置属性,还可以使用自定义属性,或者element.dataset.index / element.dataset['index'];
自定义属性:以data- 开头 data-list-name
element.getAttribute('data-list-name'); / element.dataset.listName / element.dataset['listName']; dataset在ie11以上
更改元素属性:element.setAttribute('属性' , '值'); 这个可以用来设置索引号,对事件内外进行传参。比如点击这个按钮,内部要使用这个按钮所对应的索引号,无法直接传参,可以在事件之前使用set设置索引,然后内部用get获得
var lis = document.querySelectorAll('li'); var ps = document.querySelectorAll('p'); for (var i = 0; i < lis.length; i++) { lis[i].setAttribute('index', i); //设置形参 lis[i].onclick = function () { //形参 this.className = 'select'; var index = this.getAttribute('index');//类似传参 ps[index].style.display = 'block'; //实参输入 } }
移出元素属性:element.removeAttribute('属性' , '值');
4、节点操作:利用父子兄节点关系获取元素;逻辑性强,但是兼容性稍差
nodeType、nodeName、nodeValue
获取节点:父节点 parentNode,得到最近的父系节点,若找不到则返回null
<div class = ' box'> <span class = 'erweima'></span> </div> var erweima = document.querySelector( ' .erweima'); // varIbox = document.querySelector( '.box '); erweima.parentNode;
同理,子节点 parentNode.childNodes; 包括文本,空格换行等,所有有时候会获取无用节点,利用判断nodeType获取真正需要的节点;不经常使用,一般使用 parentNode.children获取子元素节点。
获得第一个、最后一个子节点 parentNode.firstChild; / parentNode.lastChild; 获得第一个、最后一个子元素节点 parentNode.firstElementChild; / parentNode.lastElementChild;
兄节点:node.nextSibling / node.previousSibling,包含元素与文本;获取兄弟元素节点 node.nextElementSibling / node.previousElementSibling
创建节点:document.createElement('tagName'); 动态创建元素节点;
创建好后还要添加:node.appendChild('字节点'); node父级,该方法为后置添加;node.insertBefore(child, 指定元素) 指定位置添加,类似添加伪元素,若指定位置没有元素,也可添加,因为没有元素时返回undefined,如ul下无li,打印ul.children[0]返回undefined
删除节点:node.removeChild(child) 父节点删除子节点
如果是使用事件进行节点添加,当添加了新节点后,如果要对新节点进行 操作,需要在创建节点的内部实时更新节点并更新所获取的节点数组
btn[0].onclick = function () { if (text.value != null) { var lis = document.createElement('li'); lis.innerHTML = text.value + "<a href='javascript:;'>删除</a>"; comment.insertBefore(lis, comment.children[0]); //添加节点 } var del = document.querySelectorAll('a'); //添加了新的节点,需要在内部更新节点,在外部的话无法实时更新 for (var i = 0; i < del.length; i++) { del[i].onclick = function () { comment.removeChild(comment.children[0]); //内部删除 } } }
如果不是使用事件进行节点添加,则无所谓
var tbody = document.querySelector('tbody'); for (var i = 0; i < datas.length; i++) { var tr = document.createElement('tr'); tbody.appendChild(tr); for (var j in datas[i]) { var td = document.createElement('td'); //循环创建td td.innerHTML = datas[i][j]; tr.appendChild(td); } var td = document.createElement('td'); //循环创建td td.innerHTML = '<a href="JavaScript:;">删除</a>'; tr.appendChild(td); } var a = document.querySelectorAll('a'); for (var i = 0; i < a.length; i++) { a[i].onclick = function () { tbody.removeChild(this.parentNode.parentNode) } }
复制节点:node.cloneNode(); ,如果括号内为空或者false,则为浅拷贝,只拷贝节点本身,不拷贝子节点 加true则全复制;克隆后也一样需要添加
三种动态创建元素:
document.write();,全部重绘,不常用;
element.innerHTML; 如果循环创建多个元素的时候,如果直接使用innerHTML拼接多个字符串,效率较低,可以使用创建数组的方式,将多个字符串先放进数组,再数组转字符串,再一次绘制innerHTML,效率较高
document.createElement(); 创建多个元素时比innerHTML快很多,但是和数组结构化后的innerHTML比效率稍低,但是结构清晰
事件高级:
注册事件/绑定事件:传统都以on开头,有唯一性,一一对应,一个按钮执行一个事件,后面的新增函数会覆盖旧的;另一种为事件监听
事件监听注册:element.addEventLisener( type, listener[, useCapture]); 同一元素同一事件可以注册多个监听器 type = 'click' 不带on /ie9之前用attachEvent 需要带‘on’
事件解绑:执行n次之后不执行,传统解绑,onclick = ‘null’ ;监听器 element.removeEventLisener( type, listener[, useCapture]);
var divs = document.querySelectorAll('div'); divs[0].onclick = function() { alert(11); // 1. 传统方式删除事件 divs[0].onclick = null; }
// 2. removeEventListener 删除事件 divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号 function fn() { alert(22); divs[1].removeEventListener('click', fn); }
// 3. detachEvent divs[2].attachEvent('onclick', fn1); function fn1() { alert(33); divs[2].detachEvent('onclick', fn1); }
DOM事件流
事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点之间按照特定的顺序传播(先后关系),这个传播过程即DOM事件流。
1.JS代码中只能执行捕获或者冒泡其中的一个阶段。
2. onclick 和 attachEvent (ie)只能得到冒泡阶段。
element.addEventLisener第三个参数为true时,执行捕获阶段,相反false或者省略,则执行冒泡
事件对象 btn.onclick = function(event){ }
event / e: 与事件,如onclick相关的一系列信息,如键盘,鼠标
需要注意,当事件绑定的对象为事件触发(点击)对象时,target和this相同;但是,比如ul绑定事件,但是触发的不一定是ul,可能是li,冒泡,target和this不相同
阻止事件默认行为,如点击链接不跳转:e.preventDefault(); e.returnValue ; return false也可以,但是后面代码不执行,一般放在最后
阻止冒泡:e.stopPropagation(); // .cancelBubble() ie678下
冒泡的应用:事件委托
事件委派:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
比如:给ul注册点击事件,然后利用事件对象的target来找到当前点击的li,因为点击li,事件会冒泡到ul上,ul有注册事件,就会触发事件监听器。如此一来只操作了一次DOM,效率大大提高
禁止鼠标右键:contextmenu 禁止选中文字:selectstart
鼠标事件MouseEvent click、mousemove
键盘事件KeyboardEvent keyup、keydown、keypress该不识别功能键 shift、左右箭头等。keydown和up要注意场合来使用,比如点击某键触发文本框,应该用keyup键盘弹起后触发,否则按键值将输入
调用参数keyCode打印所按按钮的ascii码值,判断是哪一个按钮。keyup/down不区分大小写,press区分
3、pageshow和load事件
三种情况都会刷新页面都会触发load事件:1. a标签的超链接;2.F5或者刷新按钮(强制刷新);3.前进后退按钮
火狐中有个特点,有个“往返缓存”,这个缓存中不仅保存着页面数据,还保存了DOM和JavaScript的状态;实际上是将整个页面都保存在了内存里,所以此时后退按钮不能刷新页面。
此时可以使用pageshow事件来触发。这个事件在页面显示时触发,无论页面是否来自缓存,在重新加载页面中,pageshow会在load事件触发后触发。
根据事件对象中的persisted来判断是否是缓存中的页面触发的pageshow事件,注意这个事件给window添加。
4、change事件
监听元素,若元素发生改变,则执行函数
check.addEventListener('change', function(){ //状态一旦改变 if(this.checked){ //如果是checked状态 } else{ //unchecked状态 } })