个人自学前端21-JS14-DOM和事件对象事件流
DOM和事件对象事件流
一 DOM操作
js 提供了操作页面元素的API。不过这些API不是ES的内容。DOM由w3c组织提供标准。
1.1 什么是DOM
DOM:document object model。文档对象模型。
DOM是页面元素的一种组织方式。它有点类似一个“多维数组”。
从结构上,它有点类似于一棵倒过来的树,因此DOM也称为DOM树。
DOM树的顶层对象是document对象。
DOM中的内容就是html文档的内容,DOM中的内容称之为DOM节点。
1.2 什么是节点
html文档中的所有内容存储在DOM树种,每一项内容,都是DOM的一个节点。
html文档中出现最多的内容是标签,但是标签只是节点的其中一种。
节点都是对象,属于Node类,每个节点都是Node类的一个实例。
例如:
网页上的一个注释也是一个节点,但是注释不是标签。
文档声明,也是一个节点,但是它不是标签。
节点的类型有12种。但是常见和常用的有以下几种:
document,属性节点,文本节点,注释节点,元素(标签)节点。
节点是一个 js 对象,注意,不是纯对象。节点对象有3个常用属性。
1:nodeName
2:nodeValue
3:nodeType
-
关于nodeType,需要记忆的:
元素节点的nodeType是1
属性节点的nodeType是2
文本节点的nodeType是3
注释节点的nodeType是8
document节点的nodeType是9
doctype节点的nodeType是10
-
关于nodeName,需要记忆的是:
元素节点的nodeName是全大写的标签名
属性节点的nodeName就是属性名。
document节点的nodeName是#document
-
关于nodeValue,需要记忆的是:
文本节点,注释节点,属性节点的值可以通过nodeValue获取
1.3 创建节点
可以通过document.createElement(标签名)来创建元素节点。
可以通过document.createTextNode(文本内容)来创建文本节点。
可以通过document.createComment(注释内容)来创建注释节点。
1.4 插入节点
在父元素中插入任何节点到最后面:父元素.appendChild(子节点);
在父元素中插入任何节点到指定位置:父元素.insertBefore(新节点,老节点)
1.5 删除节点
在父元素中删除任何节点:父元素.removeChild(子节点);
1.6 查找节点
查找子节点:父元素.childNodes
查找子元素:父元素.children
查找属性节点列表:元素.attributes
查找父节点:子元素.parentNode
查找父元素:子元素.parentElement
查找兄弟节点:元素.previousSibling,元素.nextSibling
查找兄弟元素:元素.previousElementSibling,元素.nextElementSibling
二 事件对象
事件句柄是事件触发的函数。事件句柄是系统自动调用的。
系统在调用事件句柄的同时,会给事件句柄自动传入一个事件对象,这个事件对象可以获取当前事件的很多信息。
// 获取事件对象。
oBtn.onclick = function(ev){
console.log(ev)
}
注意:只能通过事件句柄的形参获取事件对象,你必须非常清楚哪个是事件句柄!
事件对象常用属性:
ev.clientX => 鼠标事件的鼠标相对于视口的横坐标。
ev.clientY => 鼠标事件的鼠标相对于视口的纵坐标。
ev.keyCode => 键盘事件的键盘码。
ev.target => 事件源。(触发事件的标签对象)
三 事件流
什么是事件流? 事件流是一种事件的传递机制。
为什么需要事件传递?因为需要实现事件委托。
为什么要实现事件委托?事件委托性能更好。
事件流因事件传递的方向不同而分为两种:冒泡和捕获。
冒泡事件流由微软公司提出,事件会沿着DOM树,从事件源传递到document。
捕获事件流由网景公司提出,事件会沿着DOM树,从document传递到事件源。
任何浏览器都支持冒泡,但是IE不支持捕获。因此我们习惯使用冒泡事件流。
事件冒泡 + 事件捕获 => 事件流
3.1 事件委托
事件流的最大意义就是用于实现事件委托。
事件委托可以让程序性能更好。
事件委托为什么能够提升性能?
例如,我们有100个li,每个都需要添加事件,正常情况我们需要循环100次,给每个li添加事件。
如果后续新增了li,还需要给新增的li添加事件。这样性能不太好。
如果使用事件委托,则无需给所有的 li 添加事件,转而给 li 的父元素添加事件。
由于事件流的存在,点击 li,事件也会传递给父元素,从而触发父元素的事件句柄。
// 事件委托里,通过ev.target获取被点击的li之元素。
oUl.onclick = function(ev){
ev.target.style.backgroundColor = 'red'
}
// ev.target => 事件源.(事件的源头)
// ev.target和this有时候是重合的.(绑定事件的标签和事件源是同一个标签时,重合)
事件委托注意事项:
1:给祖先元素添加事件,而不是给子元素添加事件。
2:通过ev.target获取子元素。
3:事件内this指向父元素,ev.target指向子元素。
4:应避免父元素触发事件句柄,因此需要判断事件源的标签类型。
3.2 阻止冒泡
有些时候事件冒泡会给我们带来麻烦。如果需要阻止冒泡:
1:ev.stopPropagation()
2:ev.cancelBubble = true (IE)
3.3 阻止默认事件
浏览器有很多的默认事件,例如右键事件。如果要禁止默认事件:
1:ev.preventDefault()
2:return false
四 其他
4.1 动态获取和静态获取
-
querySelectorAll => HTML5新增的DOM方法 => 静态获取 => 不会随着页面上的元素增减而变化
-
其他方法: => 动态获取 => 会随着页面上的元素增减而变化.
getElementsByTagName
getElementsByClassName
children
4.2 鼠标移动
const [oDiv] = document.querySelectorAll('div');
// 事件对象常见的名字
// e,ev,event
document.onmousemove = function(ev) {
// top变成鼠标纵坐标.
oDiv.style.top = ev.clientY + 'px';
// left鼠标横坐标.
oDiv.style.left = ev.clientX + 'px';
}
4.3 键盘事件
oText.onkeydown = function(ev) {
// 键盘码
// 键盘上的每个按键都对应一个阿拉伯数字.
// 可以通过keyCode获取这个数字.
// console.log(ev.keyCode);
}
// 组合键
oText.onkeydown = function(ev) {
// 如何按的是回车
// if (ev.keyCode === 13) {
// oDiv.innerHTML += '<p>' + this.value + '</p>';
// }
// ev.ctrlKey => 按下ctrl键会变成true
// ev.altKey => 按下alt键会变成true
// ev.shiftKey => 按下shift键会变成true
if (ev.keyCode === 13 && ev.ctrlKey) {
oDiv.innerHTML += '<p>' + this.value + '</p>';
// 清空文本框
oText.value = '';
}
}
4.4 事件绑定
添加事件
1: 通过标签的事件属性onclick添加
2: 通过js对象的onclick属性添加
3: 绑定事件.addEventListener添加
// 绑定事件。可以添加多个事件句柄。(工作中应该用这个方法添加事件)
// 语法 => 标签.addEventListener(事件名, 事件句柄, 是否使用捕获事件流)
oBtn.addEventListener('click', show);
function show() {
alert(100)
}
const [oBtn] = document.querySelectorAll('button');
// addEventListener => 默认是冒泡事件流.
// 第三个参数填true,就可以实现捕获事件流.
// 捕获事件流的顺序 => 从顶层对象把事件传递给事件源.(根冒泡是相反的)
oBtn.addEventListener('click', () => {
console.log('按钮')
}, true);
document.body.addEventListener('click', () => {
console.log('body')
}, true);
document.addEventListener('click', () => {
console.log('document')
}, true);
let [bindBtn, unbindBtn] = document.querySelectorAll('button');
// 绑定事件.
bindBtn.addEventListener('click', show);
function show() {
alert(10000);
}
unbindBtn.addEventListener('click', () => {
// 当bindBtn被点击时,不触发指定的回调函数.
// 解绑的函数,必须和绑定时的函数是同一个函数.(必须同函数名来引用)
bindBtn.removeEventListener('click', show);
});
// bindBtn.onclick = function() {
// alert(1000);
// }
// unbindBtn.onclick = function() {
// 只要不赋值函数,都可以解绑on+事件
// bindBtn.onclick = null;
// }
4.5 元素尺寸
元素尺寸 => 元素.clientWidth (width + padding); 元素.offsetWidth (width + padding + border), 元素.scrollHeight
元素偏移 => 元素.offsetLeft(Top);
滚动偏移 => 元素.scrollTop(Left);
窗口变化事件 => window.onresize
滚动条滚动事件 => 元素.onscroll
// 这个div占页面的宽是多少?
const [oDiv] = document.querySelectorAll('div');
// width + padding => 内容尺寸
console.log(oDiv.clientWidth);
console.log(oDiv.clientHeight);
// width + padding + border => 总体尺寸
console.log(oDiv.offsetWidth);
console.log(oDiv.offsetHeight);
// 内容实际的高(有滚动条后)
console.log(oDiv.scrollHeight);
// 视口的宽
console.log(document.documentElement.clientWidth);
// BOM的属性.视口宽
console.log(window.innerWidth);
console.log(window.innerHeight);
// 浏览器窗口的宽
console.log(window.outerWidth);
// 窗口尺寸变化事件
window.onresize = function() {
// 窗口尺寸变化事件,获取最新的视口
console.log(document.documentElement.clientWidth);
}
- 例子:拖拽登录窗
<style>
div{
width: 200px;
height: 200px;
background-color: red;
position: absolute;
}
*{
width: 0;
margin: 0;
}
</style>
<body>
<div></div>
<script>
const [oDiv] = document.querySelectorAll('div');
// oDiv的样式应该怎么设置
// 为什么是给document添加mousemove
// 为什么document的mousemove事件要写在oDiv的mousedown事件里面.
oDiv.addEventListener('mousedown', function(ev) {
// 鼠标按下时,鼠标距离div左边的距离
let disX = ev.clientX - oDiv.offsetLeft;
// 鼠标按下时,鼠标距离div上边的距离
let disY = ev.clientY - oDiv.offsetTop;
// 鼠标移动事件
document.onmousemove = function(ev) {
// 移动时,oDiv的left变成移动的横坐标 - disX
// 移动时,oDiv的top变成移动的纵坐标 - disY
oDiv.style.left = ev.clientX - disX + 'px';
oDiv.style.top = ev.clientY - disY + 'px';
};
// 鼠标松开时,把鼠标移动事件清除.
document.addEventListener('mouseup', function() {
document.onmousemove = null;
});
});
</script>
</body>
- 例子:回到顶部,回到底部
// 设为0就是回到顶部.
// document.documentElement.scrollTop = 0;
const html = document.documentElement;
// 回到底部.
html.scrollTop = html.scrollHeight - html.clientHeight;
// 判断是否触底
if (this.scrollTop >= this.scrollHeight - this.clientHeight) {}
// 一直触底
oUl.scrollTop = oUl.scrollHeight - oUl.clientHeight;
五 BOM
ES => 语法标准 ECMA国际提供的标准
DOM => W3C提供的标准。
BOM => 没标准.(不同浏览器的方法没有统一,兼容性问题)
document对象的是DOM的api
window对象的是BOM的api
location => 网址对象
navigator => 客户端对象
history => 历史记录对象
// 网址对象
console.log(window.location);
// 网页的完整地址
console.log(window.location.href);
// 哈希值.(锚点带#的部分)
console.log(window.location.hash);
// 端口
console.log(window.location.port);
// 主机
console.log(window.location.host);
// 源
console.log(window.location.origin);
const [oBtn] = document.querySelectorAll('button');
oBtn.onclick = function() {
// 刷新网页。(F5)
location.reload();
}
// http://127.0.0.1:5500/12.BOM.html
// 网页url
// 1:orgin(源) => a:协议,b:ip(域名hostname),c:端口 => http://127.0.0.1:5500
// 2:文件路径 => /12.BOM.html
// 客户端对象。
// console.log(navigator);
if (navigator.userAgent.search('Chrome') != -1) {
alert('这是一个谷歌内核的浏览器');
} else {
alert('这不是一个谷歌内核的浏览器');
}
// 历史记录 => 访问过的网页,会存储到一个"页面栈"中.
// 前进后退功能,就是在浏览器页面栈中的网页.
// ['考试云平台', '菜鸟教程' ,'ES6']
// 历史记录对象
console.log(history);
// 页面栈中的页面个数.
console.log(history.length);
// 前进
// history.forward();
// 后退
// history.back();
// 指定跳转.前进2页
// history.go(2);
// 后退两页
// history.go(-2);
// 后退1页(和back作用一致);
// history.go(-1);
// 前进1页(forward作用一样.);
// history.go(1);
// 刷新(location.reload作用一样);
// history.go(0);
<body>
<button>跳转到01页面</button>
<button>关闭01页面</button>
<script>
const [oBtn, oClose] = document.querySelectorAll('button');
// oBtn.addEventListener('click', function() {
// 有些浏览器禁止修改href.
// location.href = 'http://127.0.0.1:5500/01.%E6%80%BB%E7%BB%93.html';
// });
let newWin = null;
oBtn.addEventListener('click', function() {
// 新建一个窗口打开指定的地址
// window.open('01.总结.html');
// 第二个窗口默认可以设置是新建标签页打开还是当前页面打开
// _blank => 空白标签页打开 (默认值)
// _self => 当前页面打开
// window.open('01.总结.html','_self');
// 返回新打开的窗口对象.
newWin = window.open('01.总结.html');
// 给新窗口创建一个全局变量.
newWin.x = 200;
});
oClose.addEventListener('click', function() {
console.log(newWin);
// 关闭当前窗口
window.close();
// 关闭新窗口
// newWin.close();
})
</script>
</body>
本文来自博客园,作者:暗鸦08,转载请注明原文链接:https://www.cnblogs.com/DarkCrow/p/15062026.html

浙公网安备 33010602011771号