「这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战」。
前言
- 本篇文章将代大家了解dom
- 使用dom可以让我们方便的操作界面, 和获取页面元素, 是原生的js
- dom是文档对象模型
- 本文将会完成一个demo, 在一个框中显示鼠标移动的坐标
内容
DOM简介
- 浏览器已经为我们提供文档节点 对象这个对象是window属性
- 可以在页面中直接使用, 文档节点代表的是整个网页
//获取到button对象
var btn = document.getElementById("btn");
//修改按钮的文字
btn.innerHTML = "nihO";
- 事件
- 事件, 就是文档或浏览器窗口中发生的一些特定的交互瞬间.
- javaScript与HTML之间的交互是通过事件实现的
- 对于Web应用来说, 有下面这鞋代表性事件: 点击某个元素, 将鼠标移动至某个元素上方, 按下键盘上某个键,等等
- 事件, 就是用户和浏览器之间的交互行为
- 我们可以在事件对于的属性中设置一些js代码
- 这样当事件被触发时, 这些代码将会执行
- 这种写法我们称为叫做结构和行为耦合, 不方便维护,
- 不推荐使用
- 可以为按钮的对应事件绑定处理函数的形式来响应事件
- 这样当事件被触发时, 其中对应的哈数将会被调用
//获取对象
var btn = document.getElementById("btn");
btn.onclick = function(){
};
- 这样当事件被触发时, 其中对应的哈数将会被调用
- 文档的加载
- 浏览器在加载一个页面时, 是按照自上向下的顺序加载的
- 读取到一行就运行一行, 如果将script标签写到页面的上边,
- 在代码执行时, 页面还没有加载, 页面没有加载DOM对象也没有加载
- 会导致无法获取到DOM对象
- 将js代码编写到页面的下部就是为了, 可以在页面加载完毕以后再执行js代码
- onload事件会在整个页面加载完成之后才触发
- 该事件对应的响应函数将会在页面加载完成之后执行
- 这样可以确保我们的代码执行时所有的DOM对象已经加载完毕了
为window绑定一个onlaoad事件
window.onload = function(){
}
- dom查询
-
获取元素节点
- 通过document对象调用
- getElementById()
- 通过id属性获取一个元素节点对象
- getElementsByTagName()
- 通过标签名获取一组元素节点对象
- getElementsByName
- 通过name属性获取一组元素节点对象
- getElementById()
- 通过document对象调用
- innerHTML用于获取元素内部的HTML代码
- 对于自结束, 标签这个属性没有意义
- innerText
- 该属性可以获取到元素内部的文本内容
- 它和innerHTML类似, 不同的是它会自动将html去除
- 如果需要读取元素节点属性
- 直接使用元素.属性名
- 例子: 元素.id 元素.name 元素.value
- 注意: class属性不能采用这种方式.
- 读取class属性时需要使用 元素.className
- 直接使用元素.属性名
- 获取元素节点的子节点
- 通过具体的元素节点调用
- getElementsByTagName()
- 方法, 返回当前节点的指定标签后代节点
- childNodes
- 属性, 表示当前节点的所有子节点
- childNodes属性会获取包括文本节点在内的所有节点
- 根据DOM标签空白也会当成文本节点
- 注意: 在IE8及以下的浏览器中, 不会将空白文本当撑字节点
- firstChild
- 属性, 表示当前节点的第一个子节点(包括空白文本)
- lastChild
- 属性, 表示当前节点的最后一个子节点
- children
- 属性可以可以获取当前元素的所有子元素
- firstElementChild
- 获取当前元素的第一个子元素
- 支持IE8及以下的浏览器
- 如果需要兼容他们尽量不要使用
- getElementsByTagName()
-
-
获取父节点和兄弟节点
- 通过节点的调用
- parentNode
- 属性, 表示当前节点的父节点
- previousSibling
- 属性, 表示当前节点的前一个兄弟节点(也可能获取到空白的文本)
- nexrSibling
- 属性, 表示当前节点的后一个兄弟节点
- parentNode
- dom查询的剩余方法
- 获取body标签
var body = document.getElementsByTagName("body")[0];
- 在document中有一个属性body, 它保存的是body的引用
var body = document.body;
- document.documentElement保存的是html根标签
- document.all 表示页面中的所有元素
- 根据class属性值查询一组元素节点对象
- document.getElementByClassName()可以根据class属性值获取一组元素节点对象
- 但是该方法不支持IE8及以下的浏览器
var box1 = document.getElementByClassName("box1");
- document.querySelector()
- 需要一个选择器的字符串作为参数, 可以根据一个CSS选择器来查询一个元素节点对象
- 虽然IE8中没有getElementByClassName()但是可以用document.querySelector()来代替
- 使用该方法总会返回唯一的一个元素, 如果满足条件的元素有多个, 那么它只会返回第一个
document.querySelector(".box, div");
- document.querySelectorAll()
- 该方法和document.querySelector()用法类似, 不同的是它会将符合条件的元素封装到一个数组中返回
- 即使符合条件的元素只有一个, 它也会返回数组
- 获取body标签
dom增删改
- document.createElement()
- 可以用于创建一个元素节点对象
- 它需要一个标签名作为参数, 将会根据改标签名创建元素节点对象.
- 并将创建好的对象作为返回值
var li = document.createElement("li");
- document.createTextNode()
- 可以用来创建一个文本节点对象
- 需要一个文本内容作为参数, 将会根据该内容创建文本节点, 并将新的节点返回
var text = document.createTextNode("广州");
- appendChild()
- 向一个父节点中添加一个新的子节点
- 用法: 父节点.appendChild(子节点);
- insertBefore()
- 可以在指定的子节点前插入新的子节点
- 语法:
- 父节点.insertBefore(新节点, 旧节点);
- replaceChild()
- 可以使用指定的子节点替换已有的子节点
- 语法: 父节点.replaceChild(新节点, 旧节点);
- removeChild()
- 可以删除一个子节点
- 语法: 父节点.removeChild(子节点);
city.removeChild(bj);
- 使用innerHTML也可以完成DOM的增删改的相关操作
- 一般我们会两种方式结合使用
- 使用dom操作css
- 通过JS修改元素的样式
语法: 元素.style样式名 = 样式值
box1.style.width = "100px";
- 注意: 如果CSS的样式名中含有-,
这种名称再JS中是不合法的比如background-color
需要将这种样式名修改为驼峰命名法
去掉-, 然后将-后的字母大写 如: backgroundColor
- 我们通过style属性设置的样式都是内联样式
- 而内联样式有较高的优先级, 所以通过JS修改的样式往往会立即显示
- 但是如果在样式中写了!important, 则此时样式会有最高的优先级
- 即使通过JS也不能覆盖该样式此时将会导致JS样式修改失败, 所以尽量不要为样式添加!important
- 读取box1的样式
- 语法: 元素.style.样式名
- 通过style属性设置和读取的都是内联样式
- 无法读取样式表中的样式
- 获取元素当前显示的样式
-
语法: 元素.currentStyle.样式名
-
它可以用来读取当前元素正在显示的样式
alert(box1.currentStyle.width);
-
如果当前元素没有设置该样式, 则获取它的默认值
currentStyle只有IE浏览器支持, 其他的浏览器都不支持
-
- 在其他的浏览器中可以使用
- getComputedStyle()这个方法来获取当前元素的样式
- 这个方法是window的方法, 可以直接 使用
- 需要两个参数
- 第一个: 要获取的样式
- 第二个: 可以传递一个伪元素, 一般都传null
getComputedStyle(box1, null);
- 该方法会返回一个对象, 对象中封装了当前元素对应的样式
- 可以通过对象.样式名来读取样式
- 如果获取的样式没有设置, 则会获取到真实的值,而不是默认的值
- 比如: 没有设置width, 它不会获取到auto, 而是一个长度
- 但是该方法不支持IE8及以下的浏览器
- 通过currentStyle和getComputedStyle()获取到的样式都是只读的
其他样式的相关属性
- clientWidth
- clientHeight
- 这两个属性可以获取元素的可见宽度和高度
- 这些属性都是不带px的, 返回的都是一个数字 可以直接进行计算
- 会获取元素的高度和宽度, 包括内容区和内边距
- 这些属性都是只读的, 不能修改
- offsetWidth
- offsetHeight
- 获取元素的整个的宽度和高度, 包括内容区, 内边距和边框
- offsetParent
- 可以用来获取当前元素的定位父元素
- 会获取到离当前元素最近的开启了定位的祖先元素
- 如果所有的祖先元素都没有开启定位则返回body
- offsetLeft
- 当前元素相对于其定位元素的水平偏移量
- offsetTop
- 当前元素相对于其定位元素的垂直偏移量
- scrollWidth
- scrollHeight
- 可以获取元素整个滚动区域的高度
- scrollLeft
- 可以获取水平滚动条滚动的距离
- scrollTop
- 可以获取垂直滚动条滚动的距离
- 获取滚动条滚动的距离
- chrome认为浏览器的滚动条是body的, 可以通过body.scrollTop来获取
- 火狐等浏览器认为浏览器的滚动条是html的
//兼容的写法
var st = document.body.scrollTop || document.documentElement.scrollTop;
var sl = document.body.scrollLeft || document.documentElement.scrollLeft;
- 当满足scrollHeight - scrollTop == clientHeight;
- 说明垂直滚动条滚动到底了
- 当满足scrollWidth - scrollLeft == clientWidth;
- 说明水平滚动条滚动到底了
- onscroll
- 该事件会在元素的滚动条滚动时触发
- disabled属性可以设置一个元素是否禁用
- 如果设置为true, 则元素禁用
- 如果设置为false, 则元素可用
事件对象
- 当事件的响应函数被触发时, 浏览器每次都会将一个事件对象作为实参传递进响应函数
- 在事件对象中封装了当前事件相关的一切信息, 比如: 鼠标的坐标, 键盘哪个按键被按下, 鼠标滚轮滚动的方向
- 在IE8中, 响应函数被触发时, 浏览器不会传递事件对象
- 在IE8及以下的浏览器中, 是将事件对象作为window对象的属性保存的
//处理兼容性问题 if(!event){ event = window.event; } //第二种 event = event || window.event;
- 在IE8及以下的浏览器中, 是将事件对象作为window对象的属性保存的
- onmousemove
- 该事件将会在鼠标在元素中移动时被触发
- clientX可以获取鼠标指针的水平坐标
- clientY可以获取鼠标指针的垂直坐标
- clientX和clientY
- 用于获取鼠标在当前的可见窗口的坐标
- div的偏移量, 是相对于整个页面的
- clientX和clientY
- pageX和pageY可以获取鼠标相对于当前页面的坐标
- 但是这两个属性在IE8中不支持, 所以如果需要兼容IE8, 则不要使用
- target
- event中的target表示的触发事件的对象
-
拖拽box1
- 拖拽的流程
6. 当鼠标在被拖拽的元素上按下时, 开始拖拽onmousedown
7. 当鼠标移动时被拖拽元素跟随鼠标移动onmousemove
- 当鼠标松开时, 被拖拽元素固定在当前位置onmouseup
事件的冒泡(bubble)
- 所谓的事件冒泡就是事件的向上传导, 当后代元素上的事件被触发时, 其祖先元素上的相同事件也会被触发
- 在开发中大部分情况冒泡都是有用的, 如果不希望发生事件冒泡可以通过事件对象来取消冒泡
//取消冒泡
//可以将事件对象的cancelBubble设置为true, 即可取消冒泡
event.cancelBubble = true;
- 事件的委派
- 指将事件统一绑定给元素的共同的祖先元素, 这样当后代元素, 上的事件触发时, 会一直冒泡到祖先元素
- 我们希望只绑定一次事件, 即可应用到多个元素上 ,即使元素是后添加的
- 我们可以尝试将其绑定给元素的共同的祖先元素
- 事件的绑定
- 使用 对象.事件 = 函数 的形式绑定响应函数
- 它只能同时为一个元素的一个事件绑定一个响应函数
- 不能绑定多个, 如果绑定了多个, 则后边会覆盖掉前边的
- addEventListener()
- 通过这个方法也可以为元素绑定响应函数
- 参数:
- 事件的字符串, 不要on
- 回调函数, 当事件触发时, 该函数会被调用
- 是否在捕获阶段触发事件, 需要一个布尔值, 一般都传false
btn01.addEventListenner("click", function(){}, false);
- 使用addEventListener()可以同时为一个元素的相同事件同时绑定多个响应函数
- 这样当事件被触发时, 响应函数, 将会按照函数的绑定顺序执行
- 这个方法不支持IE8及以下的浏览器
- attachEvent()
- 在IE8中可以使用attachEvent()来绑定事件
- 这个方法也可以同时为一个事件绑定多个处理函数
- 不同的是他是后绑定先执行, 执行顺序和addEventListener()
- 参数:
- 事件的字符串, 要on
- 回调函数
- 定义一个函数, 用来为指定的元素绑定响应函数
//addEventListener()中的this, 是绑定事件的对象 //attachEvent()中的this, 是window //需要统一两个方法this /* 参数: obj 要绑定事件的对象 eventStr 事件的字符串(不要on) callback 回调函数 */ function bind(obj, eventStr, callback){ if(obj.addEventListener){ //大部分浏览器兼容的方式 obj.addEventListener(eventstr, callback, false); }else{ //this是由谁调用方式决定 //callback.call(obj) //IE8及以下 obj.attachEvent(eventStr, function(){ //在匿名函数中掉用回调函数 callback.call(obj); }); } } - 事件的传播
- 关于事件的传播网景公司和微软公司有不同的理解
- 微软公司认为事件应该是由内向外传播, 也就是当事件触发时, 应该先触发当前元素上的事件, 然后再向当前元素的祖先元素上传播, 也就是说事件应该在冒泡阶段执行
- 网景公司认为事件应该是由外向内传播的, 也就是当事件触发时, 应该先触发当前元素的最外层的祖先元素的事件, 然后再向内传播给后代元素
- W3C综合了两个公司的方案, 将传播分成了三个阶段
- 捕获阶段
- 在捕获阶段时从最外层的祖先元素, 向目标元素进行事件的捕获, 但是默认此时不会触发事件
- 目标阶段
- 事件捕获到目标, 捕获结束开始在目标元素上触发事件
- 冒泡阶段
- 事件从目标元素向它的祖先元素传递,依次触发祖先元素上的事件
- 如果希望在捕获阶段就触发事件, 可以将addEventListener()的第三个参数设置为true
- 一般情况下我们不会希望在捕获阶段触发事件, 所以这个参数一般都是false
- IE8及以下的浏览器中没有捕获阶段
- 捕获阶段
-
拖拽
- 当我们拖拽一个网页中的内容时, 浏览器会默认去搜索引擎中搜索内容,
- 此时会导致拖拽功能的异常, 这个是浏览器提供的默认行为
- 但是这招对IE8不起作用
- IE: 当调用元素的setCapure()方法以后, 这个元素将会把下一次所有的鼠标按下相关的事件捕获到自身上
- releaseCapture()取消捕获
- setCapture()
- 只有IE支持, 但是在火狐中调用不会报错
滚轮的事件
- event.wheelDelta
- event.wheelDelta 可以获取鼠标滚轮滚动的方向
- wheelDelta这个值我们不看大小, 只看正负
- wheelDelta这个属性火狐中不支持
- 火狐中使用event.detail来获取滚动的方向
- 向上滚是-3 向下滚是3
onmousewheel鼠标滚轮滚动的事件,会在滚轮滚动时触发
* 但是火狐不支持该属性
*
* 在火狐中需要使用DOMMouseScroll来绑定滚动事件
- 当滚轮滚动时, 如果浏览器有滚动条, 滚动条会随之滚动
- 这是浏览器的默认行为, 如果不希望发生, 则可以取消默认行为 return false;
- 使用addEventListener()方法绑定响应函数, 取消默认行为时不能使用return false
- 需要使用event.prevetDefault();
- 但是IE8不支持event.preventDefault();这个玩意, 如果直接调用会报错
键盘事件
- onkeydown
- 键盘被按下
- 对于onkeydown来说如果一直按着某个键不松手, 则事件会一直触发
- 当onkeydown连续触发时, 第一次和第二次之间的间隔会稍微长一点其他的会非常快
- 这种设计是为了防止误操作的发生
- 在文本框中输入内容, 属于onkeydown的默认行为
- 如果在onkeydown中取消了默认行为, 则输入的内容不会出现在文本框中
- onkeyup
- 键盘被松开
- 键盘事件一般都会绑定给一些可以获取到焦点的对象, 或者是document
- keyCode
- 可以通过keyCode来获取按键的编码
- 通过它可以判断那个按键被按下
- 除了keyCode, 事件对象中还提供了几个属性
- altKey
- ctrlKey
- shiftKey
- 这三个用来判断alt ctrl 和 shift是否被按下
- 如果按下则返回true, 否则返回false
- 判断y和ctrl是否同时被按下
if(event.keyCode === 89 && event.ctrlKey === 17){ console.log("ctrl和y都被按下了"); }
demo演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2021年6月14日11:57:06</title>
<style>
#areaDiv {
width: 500px;
height: 100px;
border: 1px solid #000;
margin: 50px;
}
#showMsg {
width: 500px;
height: 50px;
border: 1px solid #000;
margin: 50px;
}
</style>
</head>
<body>
<div id="areaDiv"></div>
<div id="showMsg"></div>
<script>
/**
* 当鼠标在 areDiv 中移动时, 在showMsg中来显示鼠标的坐标
*/
//获取两个div
var areaDiv = document.getElementById("areaDiv");
var showMsg = document.getElementById("showMsg");
/**
* onmousemove
* - 该事件会在鼠标在元素中移动时触发
*
* 事件对象
* - 当事件的响应函数被触发时, 浏览器每次都会将一个事件对象作为实参传递进响应函数
* 在事件对象中封装了当前事件相关的一切信息, 比如: 鼠标的坐标 键盘哪个按键被按下 鼠标滚轮滚动的方向等等.....
*/
areaDiv.onmousemove = function(event){
/**
* 在IE8中, 响应函数被触发时, 浏览器不会传递事件对象
* 在IE8及以下的浏览器中, 是将事件作为window对象的属性保存的
*
* clientX可以获取鼠标指针的水平坐标
* clientY可以获取鼠标指针的垂直坐标
*/
// if(!event){
// event = widow.event;
// }
//解决事件对象的兼容性问题
event = event || window.event;
var x = window.event.clientX;
var y = window.event.clientY;
// console.log("x = " + x + "," + "y = " + y);
//在showMsg中显示鼠标的坐标
showMsg.innerHTML = "x = " + x + "," + "y = " + y;
};
</script>
</body>
</html>
后记
- js Dom在实际中用的可能比较少但是我们还是要会是用