目录
一、什么是DOM?
文档对象模型 (DOM) 是 HTML 和 XML 文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可以使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将 web 页面和脚本或程序语言连接起来。
一个 web 页面是一个文档。这个文档可以在浏览器窗口或作为 HTML 源码显示出来。但上述两个情况中都是同一份文档。文档对象模型(DOM)提供了对同一份文档的另一种表现,存储和操作的方式。 DOM 是 web 页面的完全的面向对象表述,它能够使用如 JavaScript 等脚本语言进行修改。
DOM 树
二、如何获取页面元素
1.根据ID获取
getElementById()
2.根据标签名获取
getElementsByTagName()
3.H5新增:类名获取 选择器获取
getElementsByClassName()
querySelector()
querySelectorAll()
三、如何给元素注册事件
1.事件介绍
事件是您在编程时系统内发生的动作或者发生的事情,系统响应事件后,如果需要,您可以某种方式对事件做出回应。例如:如果用户在网页上单击一个按钮,您可能想通过显示一个信息框来响应这个动作。
2.事件三要素
事件是由三部分组成的,事件源、事件类型、事件处理程序。即事件三要素
(1)事件源、事件被触发的对象 按钮
(2)事件类型、如何被触发,什么事件,比如鼠标点击(onclick)还是鼠标经过,或是鼠标按下
(3)事件处理程序、 通过几个函数赋值的方式完成
3.执行事件的步骤
(1)获取事件源
(2)注册事件(绑定事件)
(3)添加事件处理程序(采取函数赋值形式)
4.常见的鼠标事件
四、如何操作DOM元素属性
1.操作元素,修改元素内容
(1)element.innerText
不识别html的标签,非标准,去除空格和换行
(2)element.innerHtml
识别html的标签,标准,w3c发起,推荐,保留空格和换行
(3)通点
这两个属性是可读写的,可以获取元素里面的内容
2.常用元素的属性操作
例如
<body>
<button id="bn">波妞妞</button>
<button id="zj">宗介介</button>
<img src="./img/zongjie.webp" alt="" title="宗介喜欢波妞">
<script>
// 1.获取元素
var bn = document.getElementById("bn");
var zj = document.getElementById('zj');
var img = document.querySelector("img");
// 2.注册事件
bn.onclick = function() {
img.src="./img/boniu.webp";
img.title="波妞喜欢宗介";
}
zj.onclick = function() {
img.src="./img/zongjie.webp";
img.title="宗介喜欢波妞";
}
</script>
</body>
3.表单元素的属性操作
type是类型属性
value是值属性
checked是选中属性
disabled是表单是否被使用
btn.disable=true;(使用this也可,指向的是事件函数的调用者)
******小插曲******(表单)
表单中登录密码框的显示和隐藏
<script>
var img = document.getElementById('eye');
var int = document.getElementById('pwd');
var flag = 0;
eye.onclick = function () {
if(flag == 0){
pwd.type = 'text';
img.src = './img/k.png';
flag = 1;
} else {
pwd.type = 'password';
img.src = './img/b.png';
flag = 0;
}
}
</script>
******显示隐藏文本框******(表单)
<script>
var int = document.querySelector('input');
int.onfocus = function () {
if(this.value === '惊雷') {
this.value = '';
}
this.style.color = "#333";
}
int.onblur = function () {
if(this.value === '') {
this.value = '惊雷';
}
this.style.color = "#999";
}
</script>
******密码框验证信息******(表单)
<script>
var ipt = document.querySelector('.ipt');
var message = document.querySelector('.message');
ipt.onblur = function () {
if (this.value.length < 6 || this.value.length > 10) {
message.className = 'message wrong';
message.innerHTML = '格式错误,请重新输入。'
} else {
message.className = 'message right';
message.innerHTML = '密码输入正确。'
}
}
</script>
4.样式属性操作
element.style 修改的样式较少,可进行行内样式操作
element.className 修改的样式较多,可进行类名样式操作
<style>
.purple{
background-color: purple;
color: #999;
width: 50px;
height: 50px;
}
.pink{
background-color: pink;
margin-top: 50px;
color: #999;
width: 50px;
height: 50px;
}
</style>
</head>
<body>
<div class="purple">
紫色
</div>
<script>
// 1.获取元素
var box = document.querySelector('div');
// 2.注册表单
box.onclick = function() {
this.className = "pink purple";
}
</script>
</body>
5.关闭二维码、精灵图、排他思想、百度换肤
******点击关闭二维码******
<script>
var goal = document.querySelector('.goal');
var box = document.querySelector('.box');
goal.onclick = function () {
box.style.display = "none";
}
</script>
******精灵图巧用JS生成******
<script>
var lis = document.querySelectorAll('li');
for(var i = 0 ;i < lis.length ; i++) {
var index = i * 60;
lis[i].style.backgroundPosition = '-' + index + 'px 0';
}
</script>
******排他思想******
<script>
// 1.获取元素
var btns = document.getElementsByTagName('button');
// 2.注册表单
for(var i = 0; i < btns.length; i++){
btns[i].onclick = function (){
// (1)先把所有按钮的颜色去掉
for(var i = 0; i < btns.length; i++){
btns[i].style.backgroundColor = "";
}
// (2)然后在上色
this.style.backgroundColor = "purple";
}
}
</script>
******百度换肤******
<script>
// 1.获取元素
var imgs = document.querySelector('.img').querySelectorAll('img');
// 2.注册表单
for(var i = 0; i < imgs.length; i++){
imgs[i].onclick = function(){
document.body.style.backgroundImage = 'url(' + this.src + ')';
}
}
</script>
*******隔行变色******
<script>
var trs = document.querySelector('tbody').querySelectorAll('tr');
for (var i = 0; i < trs.length; i++) {
trs[i].onmouseover = function () {
this.className = 'normall pink';
}
}
for (var i = 0; i < trs.length; i++) {
trs[i].onmouseout = function () {
this.className = 'normall';
}
}
</script>
******表单全选******
<script>
// 1.通过表头的全选下面选项
var j_cbAll = document.getElementById('j_cbAll');
var j_tbs = document.getElementById('j_tbs').getElementsByTagName('input');
j_cbAll.onclick = function(){
console.log(this.checked);
for(var i = 0; i < j_tbs.length; i++){
j_tbs[i].checked = this.checked;
}
}
// 2.通过下面选项影响上面表头
for(var i = 0; i < j_tbs.length; i ++) {
j_tbs[i].onclick = function() {
var flag = true;
for(var i = 0; i < j_tbs.length; i++) {
if(!j_tbs[i].checked){
flag = false;
break;
}
}
j_cbAll.checked = flag;
}
}
</script>
6.获取、设置 自定义属性值(Tab栏布局切换)
(1)获取属性值
方法:element.属性 element.getAttribute('属性')
区别 :获取内置属性值 获取自定义属性值
(2)设置属性值
element.属性 = '值'
element.setAttribute('属性'.,'值')
(2)移除属性值
element.removeAttribute('属性')
******Tab栏切换布局******
<script>
var header = document.querySelector('header');
var lis = header.querySelectorAll('li');
var items = document.querySelectorAll('.item');
for (var i = 0 ; i < lis.length; i++){
// 给5个小li,,,设置索引
lis[i].setAttribute('index',i);
lis[i].onclick = function() {
for(var i = 0; i < lis.length; i++) {
// 干掉所有人,清除掉其他li的class属性
lis[i].className = "";
}
// 留下我自己的class属性
this.className = "green";
// 2.下面的内容显示模块
var index = this.getAttribute('index');
console.log(index);
// 干掉所有人,让其他的item隐藏
for (var i = 0 ; i < items.length ; i++) {
items[i].style.display = 'none';
}
// 留下我自己,让自己的item显示出来
items[index].style.display = 'block';
}
}
</script>
7.H5自定义属性
(1)设置H5自定义属性
H5中规定自定义属性需要以 data- 开头做属性名并且赋值
例如:element.setAttribute('data-index','111');
(2)获取H5自定义属性
<1>兼容性获取: element.getAttribute('data-index','111');
<2>H5新增element.dataset.index或者element.dataset['index'] ie11才开始支持
五、如何操作DOM节点
1.为什么学节点操作?
(1)利用DOM提供的方法获取元素
document.getElementById()
document.getElementsByTagName()
document.querrySelector()
逻辑性不强,繁琐
(2)利用节点层级关系获取元素
利用父子兄弟节点关系获取元素
逻辑性强,但兼容性差
2.节点概述
(1)网页中所有内容都是节点(标签、属性、文本、注释等),在DOM中,结点使用node来表示
HTML DOM 树中的所有节点均可通过Javascript进行访问,所有HTML元素(结点)均可被修改,也可以创建或删除。
(2)一般的,节点至少拥有node Type(节点类型)、nodeName(节点名称)、nodeValue(节点值)这三个基本属性。
<1>元素节点 nodeType为1
<2>属性节点 nodeType为2
<3>文本节点 nodeType为3 (文本节点包含文字、空格、换行等)
实际开发中,主要操作使用的是元素节点
3.节点层级
(1)父级节点(开发中常用)
node.parentNode(得到离他最近的父节点、该节点无父节点返回null)
(2)子节点···········(开发中常用)
<1>parentNode.childNodes(所有节点包括:元素节点、文本节点等等)
<2>parentNode.children(获取所有子元素节点)
<3>parentNode.firstChild(获取第一个子节点,范围是所有节点)
<4>parentNode.lastChild(获取最后一个子节点,范围是所有节点)
<5>parentNode.firstElementChild(获取第一个元素子节点,有兼容性问题)
<6>parentNode.firstElementChild(获取最后一个元素子节点,有兼容性问题)
<7>parentNode.children【i】(获取子元素节点,实际开常用,无兼容性问题)
******下拉菜单案例******
<script>
var nav = document.querySelector('.nav');
var lis = nav.children;
for (var i = 0; i < lis.length; i++) {
lis[i].onmouseover = function () {
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function () {
this.children[1].style.display = 'none';
}
}
</script>
(3).兄弟结点
1.node.nextSibling
返回当前元素的下一个兄弟结点,找不到返回null,也是返回所有的结点
2.node.previousSibling
返回当前元素的上一个兄弟结点,找不到返回null,也是返回所有的结点
3.node.nextElementSibling
返回当前元素的下一个兄弟元素结点,找不到返回null
4.node.previousElementSibling
返回当前元素的上一个兄弟元素结点,找不到返回null
注意:3&4方法有兼容性问题,IE9以上支持
4.创建节点(添加节点)
document.createElement('tagName');
node.appendChild(child);该方法将一个节点添加到指定父节点的子节点列表末尾,类似css中的after伪元素。
<script>
var li = document.createElement('li');
var ul = document.querySelector('ul');
ul.appendChild(li);
var lili = document.createElement('li');
ul.insertBefore(lili,ul.children[0]);
</script>
node.insertBefore(child,指定元素);
******发布留言案例******
<script>
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
btn.onclick = function () {
if (text.value == '') {
alert('请输入内容');
return false;
} else {
var li = document.createElement('li');
li.innerHTML = text.value;
ul.appendChild(li);
}
}
</script>
5.删除节点
node.removeChild(Child) 该方法从DOM中删除一个子节点,返回删除的节点
******删除留言案例******
<script>
var text = document.querySelector('textarea');
var btn = document.querySelector('button');
var ul = document.querySelector('ul');
btn.onclick = function () {
if (text.value == '') {
alert('请输入内容');
return false;
} else {
// 创建元素
var li = document.createElement('li');
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>";
// 添加元素
ul.insertBefore(li,ul.children[0]);
// 删除元素
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function () {
ul.removeChild(this.parentNode);
}
}
}
}
</script>
6.复制节点
node.cloneNode()
(1)如果括号参数为空或为false,则只是浅拷贝,即只克隆复制节点本身,不克隆里面的子节点
(2)如果括号中参数为true,则是深拷贝,会复制节点本身以及里面所有的子节点
7.动态生成删除表格
<script>
// 1.先准备好学生的数据
var dates = [{
name:"波妞",
age:20,
subject:"JS",
},{
name:"宗介",
age:19,
subject:"JAVA",
},{
name:"唐三",
age:20,
subject:"C++",
}];
// 2.往tbody里面创建行,有几个人(通过数组获取长度),就创建几行
var tbody = document.querySelector('tbody');
for (var i = 0; i < dates.length; i++) {
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 往tr里面创建单元格td,单元格数量取决于每个对象的属性个数
for(var k in dates[i]) {
var td = document.createElement('td');
td.innerHTML = dates[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 () {
tbody.removeChild(this.parentNode.parentNode);
}
}
</script>
8.三种动态创建元素区别
(1)document.write()
该方法是直接将内容写入页的内容流,但是文档执行完毕,则它会导致页面全部重绘。
(2)element.innerHTML
是将内容写入某个DOM节点,不会导致页面重绘
但是呢!创建多个元素效率高(不要拼接字符串,采取数组形式拼接),结构稍复杂。
(3)element.createElement()
创建多个元素效率低一些,但是结构清晰
<script>
window.onload = function () {
document.write('<div456/div>');
}
// 1.document.write
// var btn = document.querySelector('button');
// btn.onclick = function () {
// document.write('<div456/div>');
// }
// 2.innerHTML 创建元素(拼接字符串)
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
inner.innerHTML += '<a href = "#">百度</a>';
}
// 2.innerHTML 创建元素(拼接数组)
var arr = [];
for (var i = 0; i <= 100; i++) {
arr.push('<a href="#">百度</a>');
}
inner.innerHTML = arr.join('');
// 3.document.creatElement)()创建元素
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
var a = document.createElement('a');
create.appendChild(a);
}
</script>
六、DOM重点核心
1.创建
(1)document.write
(2)innerHTML
(3)createElement
2.增
(1)appendChild
(2)innerBefore
3.删
(1)removeChild
4.改
主要修改DOM元素属性,DOM元素的内容、属性、表单的值等
(1)修改元素属性:src、href、title等
(2)修改元素内容:innerHTML、innerText
(3)修改表单元素:value、type、disabled等
(4)修改元素样式:style、className
5.查
主要获取查询DOM的元素
(1)DOM提供的API方法:getElementById、getElementByTagName古老用法不太推荐
(2)H5提供的方法:querySelector、querySelectorAll提倡
(3)利用节点操作获取元素:父(parentNode)、子(chiidren)、兄(previousElementSibiling、nextElementSibiling)提倡
6.属性操作
主要针对于自定义属性
(1)setAttribute:设置dom的属性值
(2)getAttribute:得到dom的属性值
(3)removeAttribute:移除属性
7.事件操作
七、高级事件
1.注册事件(绑定事件)
给元素添加事件,称为注册事件或者绑定事件
注册事件有两种方式:传统方式和方法监听注册方式
(1)传统方式:
btn.onclick = function () {};
特点:注册事件的唯一性
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
(2)监听注册方式:
addEventListener()
特点:同一个元素、同一个事件可以注册多个监听器(即监听处理函数)
addEventListener(type,listener,useCapture)
type:事件类型字符串,比如click、mouseover,注意这里不需要带on
listener:事件处理函数,事件发生时,会调用该监听函数
useCapture:可选参数,是一个布尔值,默认是false,学完DOM事件流后,再进一步学习
(3)attachEvent(IE9以前使用)
eventTarget.attachEvent(eventNameWithOn,callbck)
eventNameWithOn:事件类型字符串,比如onclick,onmouseover,这里要带on
callbck:事件处理函数,当目标触发事件时回调函数被调用
2.删除事件(解绑事件)
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function () {
alert(11);
divs[0].onclick = null;
// 1.传统方式解绑
}
divs[1].addEventListener('click',fu);
function fu () {
alert(22);
divs[1].removeEventListener('click',fu);
2.
}
</script>
3.DOM事件流
事件流描述的是从页面中接受事件的顺序
事件发生时会在元素节点之间按照待定的顺序传播,这个传播过程即DOM事件流。
比如我们给一个div注册了点击事件:
DOM事件流分三个阶段:
(1)捕获阶段
(2)前目标阶段
(3)冒泡阶段
事件冒泡:IE最早提出,时间开始时由最具体的元素接收,然后逐级向上传播到DOM最顶层节点的过程。
事件捕获:网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到最具体元素的元素接收过程。
注意:
(1)JS代码只能执行捕获或者冒泡其中的一个阶段
(2)onclick和attachEvent只能得到冒泡阶段
(3)addEventListener(type,listener,useCapture)第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是false(不写就是默认false),表示在事件冒泡阶段调用事件处理程序。
(4)实际开发中,很少使用事件捕获,我们更关注事件冒泡
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function () {
alert('son')
});
var dad = document.querySelector('.dad');
dad.addEventListener('click',function () {
alert('dad')
});
</script>
(5)有些事件是没有冒泡的,比如onblur,onfocus,onmouseover,onmouseleave
(6)事件冒泡有时候也会带来麻烦,有时候又会巧妙地帮助做某些事情。
4.事件对象
(1)event就是一个事件对象,写到侦听函数的小括号里,当形参来看
(2)事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
(3)事件对象,是我们事件一系列相关数据的集合。跟事件相关的,比如鼠标点击就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含了键盘事件的信息,比如判断用户按下了哪个键。
(4)这个事件对象由我们自己命名,比如event,evt,e
(5)事件对象也有兼容性问题,ie678通过window.event兼容性的写法 e = e || window.event;
方法要加小括号(),
常见事件对象的属性和方法
一、(1)e.target返回的是触发事件对象的(元素) this 返回的是绑定事件对象的(元素)
(2)区别:e.target 点击了哪个元素,就返回那个元素 this 哪个元素绑定了这个点击事件,那么就返回谁
二、(1)返回事件类型
(2)阻止默认事件
5.阻止事件冒泡
5.1 阻止事件冒泡的两种方式
事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到最顶层的DOM节点。
事件冒泡本身的特性,会带来好处,也会带来坏处,需要我们灵活掌握
阻止事件冒泡
标准写法:利用事件对象里面的stopPropagation()方法
案例
<style>
.dad {
width: 400px;
height: 400px;
margin: 180px 500px;
background-color: green;
position: relative;
}
.son {
width: 200px;
height: 200px;
position: absolute;
top: 100px;
left: 100px;
background-color: #008c8c;
}
</style>
</head>
<body>
<div class="dad">
<div class="son">
</div>
</div>
<script>
var son = document.querySelector('.son');
son.addEventListener('click',function(e){
alert('son')
e.stopPropagation();
})
var dad = document.querySelector('.dad');
dad.addEventListener('click',function(){
alert('dad')
})
</script>
6.事件委托(代理、委派)
事件委托
事件委托也称为事件代理,在jQuqery里面称为事件委派
事件委托的原理
不是给每个子节点单独设置事件监听器,而是将事件监听器设置在其父节点上,然后利用冒泡原理影响设置的每个子节点。
事件委托的作用
我们只操作了一次DOM,提高了程序性能。
7.常用的鼠标事件
1.(1)禁止鼠标右键菜单
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
(2)禁止鼠标选中(selectstart 开始选中)
2.鼠标事件对象
event对象代表事件的状态,跟事件的一系列信息的集合。现阶段我们主要是用鼠标事件对象
MouseEvent 和键盘事件对象KeyboardEvent
8.常用的键盘事件
1.三个事件执行的顺序:keydown -> keypress -> keyup
2.键盘事件对象:
键盘事件对象中的KeyCode属性可以得到相应键的ASCII码值
(1)我们的keyup和keydown事件不区分字母大小写a和A得到的都是65
(2)我们的keypress事件区分字母大小写 a 97 和 A 65 。
<style>
img {
position: absolute;
width: 30px;
height: 30px;
}
</style>
</head>
<body>
<div><img src="./img/1.png" alt=""></div>
<script>
var img = document.querySelector('img');
document.addEventListener('mousemove',function(e) {
var x = e.pageX;
var y = e.pageY;
img.style.left = x + 'px';
img.style.top = y + 'px';
})
</script>
通过敲击键盘实现光标定位案例
<input type="text">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup', function(e) {
console.log(e.keyCode);
// 大小写的C c 哦 !!!!!!!!!!
if (e.keyCode === 32) {
search.focus();
}
})
</script>
通过键盘事件实现数字放大镜功能案例
<style>
* {
margin: 0;
padding: 0;
}
.search {
width: 178px;
height: 100px;
position: relative;
margin: 100px 200px;
}
.con {
display: none;
position: absolute;
top: -40px;
width: 171px;
height: 20px;
border: 1px solid rgba(0, 0, 0, .2);
box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
padding: 5px 0;
font-size: 18px;
line-height: 20px;
color: #333;
}
.con::before {
content: '';
width: 0;
height: 0;
position: absolute;
top: 28px;
left: 18px;
border: 8px solid #000;
border-style: solid dashed dashed;
border-color: #fff transparent transparent;
}
</style>
</head>
<body>
<div class="search">
<div class="con">123</div>
<input type="text" class="jd" placeholder="请输入快递单号">
<script>
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup',function () {
if(this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerHTML = this.value ;
}
})
jd_input.addEventListener('blur',function () {
con.style.display = 'none';
})
jd_input.addEventListener('focus', function () {
if (this.value !== '') {
con.style.display = 'block';
}
})
</script>
</div>
</body>