DOM简介
文档对象模型(Document Object Model),是W3C组织推荐的处理可扩展标记语言的标准编程接口。通过这些DOM接口可以改变网页的内容、结构和样式。
DOM树
文档:一个页面就是一个文档,DOM中使用document表示
元素:页面中所有的标签都是元素,DOM中使用element表示
节点:网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
DOM把以上内容都看做对象
获取元素
getElementById(id)-根据ID获取
返回匹配到ID的DOM Element对象,若没有找到,返回null。id是大小写敏感的字符串。
<body>
<div id="time">2022-2-2</div>
<!-- 因为文档页面从上往下加载,所以先得有标签,所以script写在标签下面 -->
<script>
var timer=document.getElementById("time");
console.log(timer);
console.log(typeof timer);//object
console.dir(timer);//打印我们返回的元素对象,更好地查看里面的属性和方法
</script>
</body>
getElementsByTagName()-根据标签名获取
返回带有标签名的元素的集合,如果页面中没有这个元素,返回空的伪数组
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
//返回结果以伪数组形式存储
//得到的元素对象是动态的
var lis=document.getElementsByTagName("li");
console.log(lis);
console.log(lis[0]);
//遍历依次打印元素对象
for(let i=0;i<lis.length;i++)
{
console.log(lis[i]);
}
</script>
</body>
还可以获取某个元素(父元素)内部所有指定标签名的子元素。父元素必须是单个对象(必须指名是哪一个元素对象),获取的时候不包括父元素自己。
element.getElementsByTagName(‘标签名’);
<body>
<ol id="olid">
<li>1-1</li>
<li>2-1</li>
<li>3-1</li>
</ol>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var ol=document.getElementsByTagName('ol');
console.log(ol[0].getElementsByTagName('li'));
//改进:通过给指定的ol标签赋予一个ID,来特指这一个元素对象
var ol=document.getElementById('olid');
console.log(ol.getElementsByTagName('li'));
</script>
</body>
getElementsByClassName(‘类名’)-根据类名获取
返回元素对象集合
querySelector(‘选择器’)-根据指定选择器返回第一个元素对象
<body>
<ol id="olid">
<li class="li1">1-1</li>
<li class="li1">2-1</li>
<li class="li1">3-1</li>
</ol>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var firstli=document.querySelector('.li1');
console.log(firstli);
</script>
</body>
qureySelectorAll(‘选择器’)-根据指定选择器返回
返回所有的
获取body标签
document.body
获取html标签
document.documentElement
事件基础
事件三要素
事件是可以被JavaScript侦测到的行为,简单解释:触发-响应机制。
事件由三部分组成:事件源、事件类型、事件处理程序。
事件源
事件源是事件被触发的对象,
事件类型
事件源是如何触发 什么事件
事件处理程序
通过一个函数赋值的方式完成
<body>
<button id="btn">
唐伯虎
</button>
<script>
//获取事件源
var btn=document.getElementById('btn');
//绑定事件
btn.onclick=function(){
alert('点秋香');
}
</script>
</body>
操作元素
改变元素内容
element.innerText
从起始位置到终止位置的内容,但它不识别html标签,同时空格和换行也会去掉。
<body>
<button>显示当前系统时间</button>
<div>某个时间</div>
<script>
//当我们点击了按钮,div里面的文字会发生变化
//1.获取元素
let btn=document.querySelector('button');
let div=document.querySelector('div');
//2.注册事件
btn.onclick=function(){
div.innerText='2019-6-6';
}
//可以不注册事件
let div=document.querySelector('div');
div.innerText='2022-6-2';
</script>
</body>
element.innerHTML
起始位置到终止位置的全部内容,包括html标签,同时保留空格和换行。
这两个属性都是可读写的,可以获取元素里面的内容,比如p.innerHTML
常用元素属性操作
<body>
<button id="ZYL">朱一龙</button>
<button id="ZLY">赵丽颖</button><br>
<img src="material/ZLY.jpeg" alt="">
<script>
let zyl=document.getElementById('ZYL');
let zly=document.getElementById('ZLY');
let img=document.querySelector('img');
zyl.onclick=function(){
img.src="material/ZYL.jpeg"
}
zly.onclick=function(){
img.src="material/ZLY.jpeg"
}
</script>
</body>
其他属性以此类推。
表单元素属性操作
利用DOM可以操作以下表单元素的属性:type、value、checked、selected、disabled
<body>
<button>按钮</button>
<input type="text" value="输入内容">
<script>
let btn=document.querySelector('button');
let input=document.querySelector('input');
btn.onclick=function(){
//表单里面的值 文字内容是通过value来修改的
input.value='被点击';
//表单被禁用,不能再点击 disabled
//btn.disabled=true;
//this指向的是事件函数的调用者
this.disabled=true;
}
</script>
</body>
样式属性操作
1.element.style 行内样式操作
样式少,功能简单的情况下使用。
<body>
<div></div>
<script>
var div=document.querySelector('div');
div.onclick=function(){
//style里面的属性采用驼峰命名法
//JS修改style样式操作,产生的是行内样式,css权重更高,所以会覆盖掉原来的样式
this.style.backgroundColor='blue';
this.style.width=300;
}
</script>
</body>
2.element.className 类名样式操作
className会直接更改元素类名,原来的类名会被直接覆盖掉。
<body>
<div></div>
<script>
var div=document.querySelector('div');
div.onclick=function(){
this.className='change'//类名改为change
}
</script>
</body>
div {
width: 200px;
height: 200px;
background-color: pink;
}
.change{
width: 300px;
background-color: blue;
}
如果想保留原来的类名,可以this.className=‘first change’,在原先的类名后面加空格加上新的类名。
排他思想
当有多个按钮等元素需要绑定事件时。
<body>
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
var btns=document.querySelectorAll('button');
for(var i=0;i<btns.length;i++)
{
btns[i].onclick=function()
{
//我们先把所有的按钮背景颜色去掉
for(var i=0;i<btns.length;i++)
{
btns[i].style.backgroundColor='';
}
//然后才让当前的背景颜色改变
this.style.backgroundColor='pink';
}
}
</script>
</body>
获取属性值
1.element.属性
2.element.getAttribute(‘属性’)
3.H5新增element.dataset.属性名 或者 element.dataset[‘属性名’](属性名不要data,其他的用驼峰命名法)
<body>
<div data-index="2"> </div>
<script>
//dateset是一个集合,里面存放了所有以data开头的自定义属性
console.log(div.dataset.index);
</script>
</body>
区别是:第一种获取的是内置属性值(元素自带的属性);第二种和第三种主要获取自定义的属性。第三种只能获取data-开头的。
设置属性值
1.element.属性
2.element.setAttribute(‘属性’,‘属性值’);
区别同上。
移除属性
element.removeAttribute(‘属性’);
自定义属性
为了解决有些自定义属性容易引起歧义,很难判断时内置属性还是自定义属性,所以H5规定自定义属性data-开头作为属性名并且赋值。
节点操作
获取元素通常使用两种方法:利用DOM提供的方法获取元素、利用节点层次关系获取元素。
页面中所有内容都是节点,在DOM中,节点使用node来表示。
一般的,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
- 元素节点 nodeType 为1
- 属性节点 nodeType为2
- 文本节点nodeType为3 (包含文字、空格、换行)
节点层级
最常见的是父子兄层级关系。
父级节点
node.parentNode
<body>
<div class="box">
<div class="erweima"></div>
</div>
<script>
//原来的获取元素
let erweima=document.querySelector('.erweima');
let box=document.querySelector('.box')
//父节点,得到的是离元素最近的父级节点,找不到返回null
let erweima=document.querySelector('.erweima');
console.log( erweima.parentNode);
</script>
</body>
子节点
1.parentNode.childNode
返回包含指定节点的子节点的集合(包含元素节点、文本节点等),该集合为即时更新的集合。
如果只想获得里面的元素节点,则需要专门处理
2.parentNode.children
是一个只读属性,返回所有的子元素节点,只返回元素节点,其余节点不返回。
3.parentNode.firstChild
返回第一个子节点,找不到返回null,也是包含所有的节点
4.parentNode.lastChild
返回最后一个子节点,同上。
5.parentNode.firstElementChild
返回第一个子元素节点。
6.parentNode.lastElementChild
返回最后一个子元素节点。
兄弟节点
1.node.nextSibling
返回当前元素的下一个兄弟节点,找不到则返回null,同样,也包含所有节点。
2.node.previousSibling
返回当前元素的上一个兄弟节点,找不到则返回null,同样,也包含所有节点。
3.node.nextElementSibling
返回当前元素的下一个兄弟元素节点
4.node.previousElementSibling
返回当前元素的上一个兄弟元素节点
创建节点
1.document.createElement(‘tagName’)
该方法创建由tagName指定的HTML元素,因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建节点
2.innerHTML
添加节点
1.node.appendChild(child)
将一个节点添加到指定父节点的子节点列表末尾。node是父级,child是子级。
2.node.insertBefore(child,指定元素)
将一个节点添加到父节点的指定子节点前面。
想要页面有个新的元素,先创建,再添加。
<body>
<input type="text">
<button>发布</button>
<ul></ul>
<script>
let btn=document.querySelector('button');
let text=document.querySelector('input');
let ul=document.querySelector('ul');
btn.onclick=function()
{
let li=document.createElement('li');
ul.appendChild(li);
li.innerHTML=text.value + "<a href='#'>删除</a>";
}
</script>
</body>
删除节点
node.removeChild(child)
删除一个子节点,
复制节点
node.cloneNode()
返回调用该方法节点的一个副本。
克隆完要添加到想放的地方才行。
如果括号参数为空或者为false,则是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点。括号为true,复制标签和里面的内容。
案例:动态生成表格
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>测试</title>
<link rel="stylesheet" href="css/Ceshi.css">
<script src="js/Ceshi.js"></script>
</head>
<body>
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
//1.先准备好学生的数据
var datas=
[
{
name:'魏璎珞',
subject:'JavaScript',
score:100
},
{
name:'弘历',
subject:'JavaScript',
score:98
},
{
name:'傅恒',
subject:'JavaScript',
score:99
},
{
name:'明玉',
subject:'JavaScript',
score:88
}
];
//2.循环创建多个行(有多少个人就有多少行)
var tbody=document.querySelector('tbody');
for(var i=0;i<datas.length;i++)
{
var tr=document.createElement('tr');
tbody.appendChild(tr);
//行里面创建单元格(跟2数据有关系的),数量取决于取决于对象的属性个数
for(var k in datas[i])
{
var td=document.createElement('td');
//把对象里的属性值给td
td.innerHTML=datas[i][k];
tr.appendChild(td);
}
//3.创建有有删除两个字的单元格
var td=document.createElement('td');
td.innerHTML='<a href="javascript:;">删除</a>';
tr.appendChild(td);
}
// 4.删除操作
var as=document.querySelectorAll('a');
for(var i=0;i<as.length;i++)
{
as[i].onclick=function()
{
//点击a,删除当前a所在行
tbody.removeChild(this.parentNode.parentNode);
}
}
</script>
</body>
</html>
CSS
table{
width: 500px;
margin: 100px auto;
border-collapse: collapse;
text-align: center;
}
td,th{
border: 1px solid #333;
}
table thead tr{
height: 40px;
background-color: #ccc;
}
事件高级
注册事件
给元素添加事件,称为注册事件或绑定事件。注册事件有两种方式:传统方式和方法监听注册方式。
传统注册方式
- 利用on开头的事件
- 特点:注册事件唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
方法监听注册方式
- addEventListener()它是一个方法
- 特点:同一个元素同一个事件可以注册多个监听器
- 按注册顺序依次执行
eventTarget.addEventListener(type,listener[,useCapture])
该方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。
- type:事件类型字符串,比如click、mouseover,注意这里不需要带on。记得带引号
- listener:事件处理函数,事件发生时,会调用该监听函数
- useCapture:可选参数,是一个布尔值,默认false,处于冒泡阶段,true时处于捕获阶段。
<body>
<button>监听</button>
<script>
var btn=document.querySelector('button');
btn.addEventListener('click',function(){
alert(22);
})
btn.addEventListener('click',function(){
alert(33);
})
</script>
</body>
删除事件
传统注册方式
eventTarget.on事件=null;
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs=document.querySelectorAll('div');
divs[0].οnclick=function()
{
alert(11);
divs[0].οnclick=null;
}
</script>
</body>
方法监听注册方式
eventTarget.removeEventListener(type,listener[,useCapture])
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs=document.querySelectorAll('div');
divs[0].addEventListener('click',fn)//里面的fn 不需要加小括号调用
function fn(){
alert(22);
divs[0].removeEventListener('click',fn)
}
</script>
</body>
DOM事件流
事件流描述的是从页面中接收事件的顺序。事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。
DOM事件流分为3个阶段:捕获阶段、当前目标阶段、冒泡阶段。
事件冒泡;事件开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。有些事件是没有冒泡的,比如onblur,onfocus,onmouseenter,onmouseleave
事件捕获:由DOM最顶层节点开始,任何逐级向下传播到最具体的元素接收的过程。
事件对象
写到我们侦听函数的小括号里面,当形参来看。事件对象只有有了事件才会存在。它是系统给我们自动创建的,不需要我们传递参数。事件对象是我们事件的一系列相关数据的集合,和事件相关的,比如鼠标点击里面就包含了鼠标相关信息。
<body>
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs=document.querySelectorAll('div');
//事件对象可以自己命名
divs[0].onclick=function(event){
console.log(event);
}
divs[1].addEventListener('click',function(event)
{
console.log(event);
})
</script>
</body>
e.target
返回触发事件的对象
<body>
<ul>
<li></li>
</ul>
<script>
var ul=document.querySelector('ul');
ul.addEventListener('click',function(e){
//e.target返回的是触发事件的元素
console.log(e.target);//<li></li>
//this返回的是绑定事件的元素
console.log(this);//<ul><li></li></ul>
})
</script>
</body>
e.type
返回事件的类型,比如click,mouseover等,不带on
e.preventDefault()
阻止默认行为(事件),比如让链接不跳转,提交按钮不提交。dpm标准写法。
此外还有(仅限于传统注册方式):
- e.returnValue
- retun false
e.stopPropagation()
阻止冒泡。事件冒泡本身的特性,会带来好处和一定的坏处。应用:在孩子处做了点击后就停止冒泡了,不再往上传播
事件委托
事件冒泡也会带来好处。
场景:点击每个li都会弹出对话框,以前需要给每个li注册事件,非常辛苦,而且访问DOM的次数越多,这就会延长整个页面的交互就绪时间。
事件委托也称事件代理,在JQury里面称为事件委派。
事件委托的原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在父节点上,然后利用冒泡原理影响设置每个子节点。
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<script>
var ul=document.querySelector('ul');
ul.addEventListener('click',function(e){
e.target.style.backgroundColor='blue';
})
</script>
</body>
常用鼠标事件
onclick
鼠标点击左键触发
onmouseover
鼠标经过触发。经过自身盒子会触发,经过子盒子还会触发。
mouseenter
鼠标经过触发,只经过自身盒子会触发。mouseenter不会冒泡。
onmouseout
鼠标离开触发
mouseleave
鼠标离开触发,不会冒泡。
onfocus
获得鼠标焦点触发
onblur
失去鼠标焦点触发
onmousemove
鼠标移动触发
onmouseup
鼠标弹起触发
onmousedown
鼠标按下触发
contextmenu
主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单。
禁止鼠标右键菜单:
<body>
我是一段不愿意分享的文字
<script>
document.addEventListener('contextmenu',function(e){
e.preventDefault();
})
</script>
</body>
selectstart
禁止鼠标选中
<body>
我是一段不愿意分享的文字
<script>
document.addEventListener('selectstart',function(e){
e.preventDefault();
})
</script>
</body>
鼠标事件对象
e.clientX/e.clientY
返回鼠标相对于浏览器窗口可视区的X/Y坐标。
e.pageX/e.pageY
返回鼠标相对于文档页面的X/Y坐标。
当有滚动条时,滑动滚动条相同地方坐标会不同
e.screenX/e.screenY
返回鼠标相对于电脑屏幕的X/Y坐标。
案例:鼠标跟随
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>测试</title>
<link rel="stylesheet" href="css/Ceshi.css">
<script src="js/Ceshi.js"></script>
<style>
img{
position: absolute;
}
</style>
</head>
<body>
<img src="material/zylmouse.jpeg" alt="">
<script>
var pic=document.querySelector('img');
document.addEventListener('mousemove',function(e){
//得到鼠标坐标
var x=e.pageX;
var y=e.pageY;
//把坐标给图片,记得加单位,减去图片尺寸的一半可以让鼠标在图片中间
pic.style.left=x-100+'px';
pic.style.top=y-100+'px';
})
</script>
</body>
</html>
常用键盘事件
onkeyup
某个键盘按键被松开时触发
<script>
document.addEventListener('keyup',function(){
console.log(松手);
})
</script>
onkeydowm
某个按键被按下时触发
onkeypress
某个按键被按下时触发,但是它不识别功能键,比如ctrl,shift,箭头等
三个事件执行顺序:keydowm->keypress->keyup
keyCode
键盘事件中的keyCode属性可以得到相应键的ASCII码值。已经淘汰了,用e.key
<script>
document.addEventListener('keyup',function(e){
console.log(e.keyCode);
})
</script>
注意:
- 我们的keyup和keydown事件不区分字母大小写
- keypress事件区分字母大小写