节点操作
获取元素有两种方式:
- 利用DOM提供的方法获取:逻辑性不强,繁琐
- 利用节点层级关系获取:逻辑性强但兼容性较差
节点概述
节点拥有:nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)三个基本属性。
- 元素节点,nodeType为1
- 属性节点,nodeType为2
- 文本节点,nodeType为3
节点层级
子节点
- parentNode.childNodes():返回指定节点的子节点的集合,包括元素节点,文本节点等;
- parentNode.children():是一个只读属性,返回所有的子元素节点;
- parentNode.firstChild():返回第一个子节点
- parentNode.lastChild():返回最后一个子节点
- parentNode.firstElementChild():返回第一个子元素节点
- parentNode.lastElementChild():返回最后一个子元素节点
(最后两个方法ie9以上才支持)因此在实际开发中为了获得第一个或最后一个子元素节点的写法是:
<ul>
<li>li</li>
<li>li</li>
<li>li</li>
<li>li</li>
</ul>
<script>
var ul = document.querySelector('ul');
//获得第一个子元素节点
console.log(ul.children[0]);
//获得最后一个子元素节点
console.log(ul.children[ul.children.length -1]);
</script>
兄弟节点
- nextSibling:下一个兄弟节点,包括元素节点文本节点等
- nextElementSibling:下一个兄弟元素节点
- previousSibling:上一个兄弟节点,包括元素节点文本节点等
- previousElementSibling:上一个兄弟元素节点
创建节点(元素)
- document.createElement(TagName)
- 先创建节点,再将元素添加进去
- document.write()
- 直接将内容写入页面的内容流,当文档流执行完毕,会导致页面全部重绘
- element.innerHTML
- 将内容写入某个节点,不会导致页面重绘
innerHTML创建多个元素效率更高(不要凭借字符串,用字符串效率很低,采用数组形式拼接),结构比较复杂。
createElement()创建多个元素效率低于使用数组的innerHTML高于使用字符串的innerHTML,但结构更清晰。
//使用字符串的innerHTML
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href="#">百度</a>'
}
//使用数组的innerHTML
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
//使用createElement()
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
添加节点
- 在后面追加元素:document.appendChild(往里添加的节点)
- 往前面添加:documnet.insertBefore(往里添加的节点,添加到哪个节点前)
删除节点
node.removeChild(child)
- node是要删除节点的父节点
- child是要删除的节点
克隆节点
node.cloneNode()括号里可选值true、flase或者空。
- 克隆节点跟添加节点一样,要先创建克隆节点再将节点插入
- 括号为空或者false为浅拷贝,只复制标签但不复制里面的内容
- 括号为true为深拷贝,赋值标签里的内容
<ul>
<li>12</li>
<li>123</li>
</ul>
<script>
var ul = document.querySelector('ul');
//首先克隆节点
var cloneLi = ul.children[0].cloneNode(true);
//再将克隆节点添加进去
ul.appendChild(cloneLi);
</script>
事件
注册事件
- 传统注册事件方式
- 以on开头的事件名,如onclick
- 特点:注册事件的唯一性(同一个元素同一个事件只能设置一个处理函数,若设置多个后面的函数会覆盖前面的)
- 方法监听注册方式
- 利用eventTarget.addEventListener(type,listener[,useCapture])
- type:事件类型,如click、mouseover
- listener:事件处理函数
- useCapture:可选参数,boolean
- 特点:同元素同事件可以注册多个监听器,按照注册的顺序依次执行
attachEvent也是方法监听注册方式,用于较老的浏览器,不常用
<body>
<button>传统方式注册事件</button>
<button>方法监听注册事件</button>
<script>
var btns = document.querySelectorAll('button');
//1.传统方式注册事件(结果:点击之后只能弹出‘点击了传统2’)
btns[0].onclick = function(){
alert('点击了传统哦1');
}
btns[0].onclick = function(){
alert('点击了传统哦2');
}
//2.方法监听注册事件(结果:点击之后依次弹出两个alert)
btns[1].addEventListener('click',function(){
alert('点击了方法监听哦1');
})
btns[1].addEventListener('click',function(){
alert('点击了方法监听哦2');
})
</script>
</body>
删除事件
- 传统注册方式
- eventTarget.onclick = null
- 方法监听注册方式
- eventTarget.removeEventListener = (type,listener[,useCapture]);
eventTarget.detachEvent()也是删除方法监听注册方式,用于较老的浏览器,不常用
<body>
<div>a</div>
<div>b</div>
<div>c</div>
<script>
var divs = document.querySelectorAll('div');
//传统方式
divs[0].onclick = function(){
alert('点击了一次1');
this.onclick = null;
}
//利用removeEventListener方法
divs[1].addEventListener('click',fn);
function fn(){
alert('点击了一次2');
divs[1].removeEventListener('click',fn);
};
</script>
</body>
事件流三个阶段
事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
事件流分为三个阶段:
- 捕获阶段,事件捕获:由DOM最顶层节点开始,然后逐级向下传播到最具体的元素接受的过程
- 当前目标阶段
- 冒泡阶段,事件冒泡:由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程
事件流的一些注意点:
- JS代码中只能执行捕获或者冒泡其中的一个阶段
- onclick和attachEvent只能得到冒泡阶段
- addEventListener(type,listener【,useCapture】)
- 第三个参数如果为true,表示在事件捕获阶段调用事件处理程序
- 若为空或false,表示在事件冒泡阶段调用事件处理程序
4.一些事件没有冒泡,如:onblur、onfocus、onmouseover、onmouseleave
<body>
<div class="father">
<div class="son"></div>
</div>
<script>
var father = document.querySelector('.father');
var son = document.querySelector('.son');
//结果:点击son:先document、再son,最后father,因为document为捕获阶段,向下到father,发现father
//是冒泡阶段则继续向下到最具体的son,son执行冒泡阶段,弹出son,再弹出father
father.addEventListener('click',function(){
alert('father');
},);
son.addEventListener('click',function(){
alert('son');
},);
document.addEventListener('click',function(){
alert('document');
},true);
</script>
</body>
事件对象
eventTarget.onclick = function(event){}
eventTarget.addEventListener('click',function(event){})
这里的event就是事件对象,事件发生后跟事件相关的一系列信息都存储在这个对象里。
- event是个形参,系统会帮助设定为事件对象,并不需要传递实参
- 当注册事件时,event对象会被系统自动创建,并以此传递给些事件监听器
常见事件对象的属性和方法
- e.target返回触发事件的元素
- 注意:e.target是触发了哪个元素(点击等)就返回哪个元素,this返回的是绑定时间的元素
<body>
<ul>
<li>12</li>
<li>123</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
//点击12(li)后返回li
console.log(e.target);
//返回ul
console.log(this);
})
</script>
</body>
- e.type返回事件类型,返回mouseover、click等
- e.preventDefault()阻止默认行为:让链接不跳转或让提交按钮不提交
<body>
<a href="https://juejin.cn/">掘金</a>
<script>
//阻止之后页面无法跳转
var a = document.querySelector('a');
a.addEventListener('click',function(e){
e.preventDefault();
})
//如果是传统的注册方式
a.onclick = function(e) {
// 可以用e.preventDefault()
// 也可以用return false 阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
return false;
alert(11);
}
</script>
</body>
- 阻止事件冒泡
- 标准写法:
e.stopPropagation()
- 非标准写法:ie6~8,利用事件对象昂的cancelBubble属性
- 常见鼠标事件
- 禁止鼠标右键菜单
- 禁止选中文字
<body>
<div>1234</div>
<script>
//禁止鼠标右键
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})
//禁止选中文字
document.addEventListener('selectstart',function(e){
e.preventDefault();
})
</script>
</body>
- 鼠标事件对象:client(鼠标在可视区的x,y坐标),page(鼠标在页面文档的x,y坐标),screen(鼠标在电脑屏幕的x,y坐标)
- 常见键盘事件
- keyup(按键弹起时触发,不区分字母大小写,默认为大写)
- keydown(按键按下时触发,可以识别功能键,不区分字母大小写,默认为大写)
- keypress(按键按下时触发,不能识别功能键,区分字母大小写)
注意keyup是键盘操作完松开之后再执行事件,keydown相反
- 三个事件的执行顺序:keydown-keypress-keyup
- 键盘事件对象:keyCode可以得到相应键的ASCII码值
事件委托
事件委托的核心:给父节点添加监听器,利用冒泡影响每一个子节点。
<body>
<ul>
<li>你好我好大家好</li>
<li>你好我好大家好</li>
</ul>
<script>
var ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
//点击li后,利用冒泡使得绑定在父元素(ul)上的监听器响应
//这样就不用每个li都注册
e.target.style.color = 'red';
})
</script>
</body>