1.0 DOM核心总结
关于dom操作,我们主要针对于元素的操作。主要有创建、增、删、改、查、属性操作、事件操作。
1.1创建
- document.write()
- element.innerHTML
- document.createElement()
document.write //是直接将内容写入页面的内容流,界面加载完成之后,再写入,这样它会导致页面全部重绘
innerHTML //是将内容写入某个 DOM 节点,不会导致页面全部重绘
innerHTML //创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
createElement() //创建多个元素效率稍低一点点,但是结构更清晰
总结:不同浏览器下,innerHTML 效率要比 creatElement 高
案例:
<script>
// 三种创建元素方式区别
// 1. document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function() {
document.write('<div>123</div>');
}
// 2. innerHTML 创建元素
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href="#">百度</a>'
}
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3. document.createElement() 创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
</script>
- innerHTML字符串拼接方式(效率低)
<script>
function fn() {
var d1 = +new Date();
var str = '';
for (var i = 0; i < 1000; i++) {
document.body.innerHTML += '<div style="width:100px; height:2px; border:1px solid blue;"></div>';
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
总结:因为要多次开辟变量空间,所以效率低
- createElement方式(效率一般,但结构清晰)
<script>
function fn() {
var d1 = +new Date();
for (var i = 0; i < 1000; i++) {
var div = document.createElement('div');
div.style.width = '100px';
div.style.height = '2px';
div.style.border = '1px solid red';
document.body.appendChild(div);
}
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
- innerHTML数组方式(效率高)
<script>
function fn() {
var d1 = +new Date();
var array = [];
for (var i = 0; i < 1000; i++) {
array.push('<div style="width:100px; height:2px; border:1px solid blue;"></div>');
}
document.body.innerHTML = array.join('');
var d2 = +new Date();
console.log(d2 - d1);
}
fn();
</script>
1.2增加
- appendChild
- insertBefore
1. 末尾添加:element.appendChild(childNode)
将 childNode 添加到element的子节点列表的末尾
2. 指定位置添加:element.insertBefore(childNode, 指定元素)
将childNode 添加到element的指定元素的前面
如:
ul.appendChild(li);
ul.insertBefore(li2, ul.children[0]);
1.3删
1、removeChild
node.removeChild(child)
如:
ul.removeChild(ul.children[0]);
1.4改
- 修改元素属性: src、href、title等
- 修改普通元素内容: innerHTML 、innerText
- 修改表单元素: value、type、disabled等
- 修改元素样式: style、className
1.5查
- DOM提供的API 方法: getElementById、getElementsByTagName
- H5提供的新方法: querySelector、querySelectorAll
- 利用节点操作获取元素: 父(parentNode)、子(children)、兄(previousElementSibling、nextElementSibling)
1.6属性操作
主要针对于自定义属性:
- setAttribute:设置dom的属性值element.setAttribute(‘data-index’, 2)
- getAttribute:得到dom的属性值element.getAttribute(‘data-index’);
- removeAttribute移除属性node.removeChild(child)
2.0事件高级
2.1注册事件(2种方式)
给元素添加事件,称为注册事件或者绑定事件。
传统方式
注意:同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数利用 on 开头的事件 onclick
<button onclick=“alert('~~~~hi~~~~~')”></button>
btn.onclick = function() {}
方法监听
- addEventListener() : 添加事件监听//有兼容
- 特点:同一个元素同一个事件可以注册多个监听器(事件处理程序)
- 按注册顺序依次执行
// 参数1:事件类型,它是字符串 必定加引号 而且不带on
// 参数2:事件处理程序
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
// 3. attachEvent ie9以前的版本支持 ,这里的事件需要带on
btns[2].attachEvent('onclick', function() {
alert(11);
})
2.2 事件监听
addEventListener事件监听 //有兼容
eventTarget.addEventListener(type, listener[, useCapture])
该方法接收三个参数:
1. type:事件类型**字符串**,比如 click 、mouseover ,注意这里不要带 on
2. listener:事件处理函数,事件发生时,会调用该监听函数
3. useCapture:可选参数,是一个布尔值,默认是 false。
2.3attacheEvent()事件监听
eventTarget.attachEvent(eventNameWithOn, callback) //有兼容
2.4事件监听兼容性解决方案
function addEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 addEventListener 方法
if (element.addEventListener) { // 浏览器支持此种方式,可以根据方法名找到方法声明,方法声明会转换为true
element.addEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.attachEvent) {
element.attachEvent('on' + eventName, fn);
} else {
// 相当于 element.onclick = fn;
element['on' + eventName] = fn;
}
2.5删除事件(解绑事件)
传统方式
eventTarget.onclick = null;
方法监听注册方式
1. eventTarget.removeEventListener(type, listener[, useCapture]);
2. eventTarget.detachEvent(eventNameWithOn, callback);
<div>1</div>
<div>2</div>
<div>3</div>
<script>
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);
// 点击div1的时候弹出22,然后直接移除点击事件。
// 移除事件需要参数1,哪种事件,参数2,这种事件中的fn处理程序
// 为啥需要指定处理程序fn?因为这个点击事件可以有多个处理程序,你要指定删除哪个
divs[1].removeEventListener('click', fn);
// divs[1].addEventListener('click', fn()) // 里面的fn 不需要调用加小括号
// 如果添加了小括号,就相当于将fn()调用完成的返回值作为第二个参数传递了
// 事件处理程序,不是我们调用的,而是js引擎调用的。
// 我们通过第二个参数,告诉js引擎,事件发生时要调用的方法是谁,所以只告诉他方面即可
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
</script>
2.6删除事件兼容性解决方案
function removeEventListener(element, eventName, fn) {
// 判断当前浏览器是否支持 removeEventListener 方法
if (element.removeEventListener) {
element.removeEventListener(eventName, fn); // 第三个参数 默认是false
} else if (element.detachEvent) {
element.detachEvent('on' + eventName, fn);
} else {
element['on' + eventName] = null;
}
3.0 DOM事件流
3.1 DOM 事件流会经历3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
我们向水里面扔一块石头,首先它会有一个下降的过程,这个过程就可以理解为从最顶层向事件发生的最具体元素(目标点)的捕获过程;之后会产生泡泡,会在最低点( 最具体元素)之后漂浮到水面上,这个过程相当于事件冒泡。
案例
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// 如果addEventListener 第三个参数是 true 那么则处于捕获阶段
// 顺序为:document -> html -> body -> father -> son
// 如果addEventListener 第三个参数是 false 或者 省略 那么处理冒泡阶段
// 顺序为:son -> father ->body -> html -> document
var son = document.querySelector('.son');
// 给son注册单击事件
son.addEventListener('click', function() {
alert('son');
}, false);
// 给father注册单击事件
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
// 给document注册单击事件,省略第3个参数
document.addEventListener('click', function() {
alert('document');
})
</script>
- 有些事件是没有冒泡的,比如 onblur、onfocus、onmouseenter、onmouseleave
- addEventListener(type, listener[, useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false),表示在事件冒泡阶段调用事件处理程序。
- onclick 和 attachEvent 只能得到冒泡阶段。
3.2 事件对象
- 谁绑定了这个事件。
- 鼠标触发事件的话,会得到鼠标的相关信息,如鼠标位置。
- 键盘触发事件的话,会得到键盘的相关信息,如按了哪个键。
通常情况下target 和 this是一致的
但有一种情况不同,那就是在事件冒泡时(父子元素有相同事件,单击子元素,父元素的事件处理函数也会被触发执行),
这时候this指向的是父元素,因为它是绑定事件的元素对象,
而target指向的是子元素,因为他是触发事件的那个具体元素对象。
总结 :
e.target 点击了哪个元素,就返回哪个元素
this 哪个元素绑定了这个点击事件,那么就返回谁
3.3 事件冒泡:
事件传播的过程叫做DOM事件流
捕获阶段 当前目标阶段 冒泡阶段
事件捕获是从外到里 事件冒泡是从里到外
3.4事件委托
- 原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
- 例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。
3.5阻止默认行为
e.preventDefault(); 方法 但是有兼容性问题 ie9以上才支持
e.returnValue;属性 专门针对ie低版本的
return false //特点 return后面的代码就不执行了 只限于传统的注册方式
3.6阻止冒泡效果:
e.stopPropagation
window.event.setPropagation
window.e.cancelBubble=true//没有兼容性问题
3.7禁止鼠标右键
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
})
document.addEventListener('selectstart', function(e) {
e.preventDefault();
})
3.8常用鼠标事件
- 禁止选中文字
- selectstart 事件:鼠标选中事件,用于界面文字防止选中
- 禁止右键菜单
- contextmenu事件:鼠标右键菜单事件。主要控制应该何时显示上下文菜单(右键菜单),主要用于程序员取消默认的上下文菜单
- 鼠标事件对象
clientX 和 clientY 鼠标在可视区域的X、Y坐标
pageX 和 pageY 相当于文档页面的X、Y坐标
screenX 和 screenY 相当于电脑屏幕的X、Y坐标
// 1. client 鼠标在可视区的x和y坐标
console.log(e.clientX);
console.log(e.clientY);
console.log('---------------------');
// 2. page 鼠标在页面文档的x和y坐标
console.log(e.pageX);
console.log(e.pageY);
console.log('---------------------');
// 3. screen 鼠标在电脑屏幕的x和y坐标
console.log(e.screenX);
console.log(e.screenY);
4.0常用的键盘事件
4.1 键盘事件
- 事件:
- onkeyup:某个键盘按键被松开时触发
- onkeydown:某个键盘按键被按下时触发
- onkeypress:某个键盘按键被按下时触发(但它不识别功能键,比如 Ctrl shift 箭头等)
- 三个事件的执行顺序:keydown —- keypress —- keyup (按下 —- 按住 —- 抬起)
4.2 键盘事件对象
- 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
- onkeydown 和 onkeyup 不区分字母大小写,通过keyCode属性获取到的a 和 A 得到的都是65
- onkeypress 区分字母大小写 ,通过keyCode属性获取到的 a 是 97 和 A 得到的是65
- keydown和keyup, 它能识别所有的键(包括功能键)
- Keypress 不识别功能键,但是keyCode属性能区分大小写,返回不同的ASCII值