Document Object Model(文档对象模型)
由于HTML文档被浏览器解析后就是一棵DOM树,要改变HTML的结构,就需要通过JavaScript来操作DOM。
DOM树:浏览器加载页面到内存时,会在内存中形成一个树状结构 我们html当中的所有的内容都是这个树上的一个节点 这个树就叫做dom树
- 整个文档就是一个文档节点
- 每个标签都是元素节点
- 包含再标签中文本时文本节点
- 属性就是属性节点
- 注释是注释节点
查找页面标签
-
getElementById(标签的id)
返回的只是一个dom对象,因为ID不能重复 -
getElementsByClassName('c1')
根据类名进行查找,返回的是个伪数组 -
getElementsByTagName('div')
根据标签名查找元素,返回的也是个伪数组
====================================
常用: -
querySelector('选择器')
通过选择器查找元素,返回查找到的第一个元素, 选择器写法与CSS一致 -
querySelectorAll('选择器')
通过选择器查找元素,返回所有;返回的是一个真数组;
伪数组和真数组的区别:
伪数组可以使用for循环遍历数组元素 但是不能使用数组的方法;
<div id="d1"></div>
<div id="d2" class="c1"></div>
<div id="d3" class="c1"></div>
<script>
let elementById = document.getElementById('d1');
console.log(elementById);
let elementsByClassName = document.getElementsByClassName('c1');
console.log(elementsByClassName);
for (let i =0;i<elementsByClassName.length;i++){
console.log(elementsByClassName[i]);
}
let elementsByTagName = document.getElementsByTagName('div');
console.log(elementsByTagName);
// 根据class名进行查找
let querySelector1 = document.querySelector('.c1');
console.log(querySelector1);
// 根据id名进行查找
let querySelector = document.querySelector('#d1');
console.log(querySelector);
let elementNodeListOf = document.querySelectorAll('.c1');
elementNodeListOf.forEach(a=>{
console.log(a);
})
console.log(elementNodeListOf);
</script>
JS操作标签属性
JS操作标签的属性分为两种:一种是自带的属性,另一种是自定义的属性。有三种方式:
1、操作自带的属性,不能作用在自定义的属性上,和对象操作属性的方式一致
- querySelector[‘src’] = ‘img/mg.jpg’;
- querySelector.title = ‘mg’;
<body>
<img src="../img/kkx.jpg" alt="" title="kkx" data-tom="toma" data-jack="jacka">
<script>
var querySelector = document.querySelector('img');
console.log(querySelector.title);
console.log(querySelector['title']);
// querySelector.src = '../img/you.jpg';
querySelector['src'] = '../img/you.jpg';
querySelector.title = 'you';
console.log(querySelector.title);
</script>
</body>
2、操作自带的属性和自定义的属性
- getAttribute(‘属性名’)
- setAttribute(‘属性名’,‘属性值’) 如果属性名不存在就是新增属性,存在就是替换原有的属性
<body>
<img src="../img/kkx.jpg" alt="" title="kkx" data-tom="toma" data-jack="jacka">
<script>
var querySelector = document.querySelector('img');
console.log(querySelector.getAttribute('title'));
querySelector.setAttribute('src','../img/you.jpg');
querySelector.setAttribute('title','you');
console.log(querySelector.getAttribute('title'));
console.log(querySelector.getAttribute('data-tom'));
querySelector.setAttribute('data-tom','tomb');
console.log(querySelector.getAttributeNode('data-tom'));
console.log(querySelector)
</script>
</body>
3、只用来操作自定义的属性
- data-*
会把这些自定义的data-*的属性封装到dataset对象中,属性名中不再包含data
<body>
<img src="../img/kkx.jpg" alt="" title="kkx" data-tom="toma" data-jack="jacka">
<script>
var querySelector = document.querySelector('img');
let dataset = querySelector.dataset;
console.log(dataset);
console.log(dataset.tom);
</script>
</body>
JS操作表单样式
1,操作style属性
- querySelector.style.backgroundColor = ‘red’;
- querySelector.style.color=‘yellow’;
2,操作class属性
- querySelector.className=‘c1’;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
/*.c1{
width: 100px;
height: 100px;
}*/
.c2{
width: 100px;
height: 100px;
}
</style>
</head>
<body>
<!--<div>容器1</div>-->
<div class="c2">容器2</div>
<script>
let div = document.querySelector('.c2');
div.style.color='red';
div.style.backgroundColor='yellow';
/*let div = document.querySelector('div');
div.style.color='red';
div.style.backgroundColor='yellow';
div.className = 'c1';*/
</script>
</body>
</html>
JS操作标签文本
-
innerText,不识别标签
-
innerHTML,识别标签
有= 就是赋值 否则就是取值
<body>
<ul>
<li></li>
</ul>
<script>
var li = document.querySelector('ul>li');
// li.innerText = '<h1>列表</h1>';
li.innerHTML = '<h1>列表</h1>';
console.log(li.innerText);
</script>
</body>
JS中事件
用户的任何操作都是事件,与用户交互过程中非常重要
事件的语法
on+事件名
事件的三种定义
1,行内式 <button onclick="alert('aaaa')">点击</button> 基本不用
2, js访问属性的方式
let querySelector = document.querySelector('button');
querySelector.onclick = function () {
alert('点我');
}
3,ES6建议的方式
不要带on,直接写事件名
querySelector.addEventListener('click', function () {
alert('dsssssss');
})
方式2和方式3的不同,addEventListener可以添加多个同名事件,并且多个都会执行;但是通过JS访问属性的方式 事件名重复就会被覆盖
代码演示:
<body>
<!--方式一:行内式-->
<!--<button onclick="alert('按钮被点击了')">注册</button>-->
<!--方式二:-->
<button id='btn2'>注册</button>
<!--方式三-->
<button id="btn3">登录</button>
<script>
//方式二
let btn2 = document.querySelector("#btn2");
btn2.onclick = function () {
alert('注册按钮被点击1');
}
btn2.onclick = function () {
alert('注册按钮被点击2');
}
//方式三
let btn3 = document.querySelector('#btn3');
btn3.addEventListener('click',function () {
alert('登录按钮被点击1');
})
btn3.addEventListener('click',function () {
alert('登录按钮被点击2');
})
</script>
</body>
JS事件小练习—聚焦失焦
<body>
<form action="">
user:<input type="text">
</form>
<script>
var user = document.querySelector('input');
user.addEventListener('focus',function () {
console.log('input focus');
});
user.addEventListener('blur',function () {
console.log('input blur');
})
</script>
</body>
效果:
JS事件小练习—小人物显示
点击小人物图片,就会单独显示出来…
<body>
<div>
<img src="" alt="" id="show">
</div>
<div class="content">
<img src="../images/pic1.png" alt="">
<img src="../images/pic2.png" alt="">
<img src="../images/pic3.png" alt="">
<img src="../images/pic4.png" alt="">
<img src="../images/pic5.png" alt="">
<img src="../images/pic6.png" alt="">
<img src="../images/pic7.png" alt="">
<img src="../images/pic8.png" alt="">
</div>
<script>
let imgList = document.querySelectorAll('.content>img');
let showImg = document.querySelector('#show');
console.log(imgList);
// forEach遍历添加事件
/*imgList.forEach(img => {
img.addEventListener('click', function () {
showImg.src= img.src;
})
})*/
// 增强for循环遍历添加事件
for (let img of imgList) {
img.addEventListener('click', function () {
showImg.src = img.src;
})
}
</script>
</body>
JS操作表单元素
-
checked:表示复选框或者单选框的选中状态,在属性checked="checked"表示选中 与checked等价的
-
disabled:表示标签的可点击状态 ,disabled="disabled"表示不可用的
js操作这些属性的时候可以使用true false
<body>
<input type="checkbox" name="" id="hobby">JS <br>
<button id="btn1">选择</button>
<script>
let btn1 = document.querySelector('#btn1');
let hobby = document.querySelector('#hobby');
btn1.addEventListener('click',function () {
// hobby.checked=true;
//取反进行设置
hobby.checked = !hobby.checked;
//取反设置不可用
// hobby.disabled = !hobby.disabled;
})
</script>
</body>
JS表单验证
- focus 聚焦
- blur 失去焦点
<body>
手机号:<input type="text" id="phone"> <br>
<span id="content"></span>
<script>
let phone = document.querySelector('#phone');
// 正则RegExp 对象
let regEX= /^1[3|4|5|7|8]\d{9}$/;
let span = document.querySelector('#content');
//添加失焦事件
phone.addEventListener('blur',function () {
// console.log(phone.value);
// test方法正则匹配 返回true
if(regEX.test(phone.value)){
span.innerText='手机号码格式匹配';
span.style.color='green';
// console.log('格式匹配')
}else {
span.innerText='手机号码格式不匹配';
span.style.color='red';
// console.log('格式不匹配')
}
})
</script>
</body>
JS节点的查找
节点的查询
- 父找子,只能是儿子不是隔代 children
- 子找父,parentNode
- 找哥哥,previousElementSibling,只能找一级 紧挨着的
- 找弟弟,nextElementSibling,只能找一级
<div id="fa">
<p></p>
<div id="son">
<div id="grandson"></div>
</div>
<img src="" alt="">
</div>
<div id="fa2"></div>
<script>
let fa = document.querySelector('#fa');
let son = document.querySelector('#son');
//父找子
console.log(fa.children);
//子找父
console.log(son.parentNode);
//找哥哥 只能找一级 紧挨着的
console.log(son.previousElementSibling);
//找弟弟 只能找一级 紧挨着的
console.log(son.nextElementSibling);
//找弟弟的弟弟
console.log(son.nextElementSibling.nextElementSibling);
</script>
JS节点的操作
节点的操作:
增删修
- A.appendChild(B)剪切移动的效果,B添加到A标签结束之前
- A.insertBefore(B,C),把B添加到A中,放到C之前
- A.replaceChild(B,C),在A中用B替换C
- A.removeChild(D),从A中把D给删除了
<body>
<div id="fa">
<p></p>
<div id="son"></div>
<img src="" alt="">
</div>
<a href="" id="a1"></a>
<script>
let fa = document.querySelector('#fa');
let a1 = document.querySelector('#a1');
let son = document.querySelector('#son');
// fa.appendChild(a1);
// fa.insertBefore(a1,son);
// fa.replaceChild(a1,son);
fa.removeChild(son);
</script>
</body>
JS手动创建节点
- createElement(‘标签名’) 新增节点的方法
<body>
<script>
let ul = document.createElement('ul');
let li = document.createElement('li');
li.innerText = '哈哈1';
let body = document.querySelector('body');
ul.appendChild(li);
body.appendChild(ul);
</script>
</body>
DOM是一个树形结构。操作一个DOM节点实际上就是这么几个操作:
- 更新:更新该DOM节点的内容,相当于更新了该DOM节点表示的HTML的内容;
- 遍历:遍历该DOM节点下的子节点,以便进行进一步操作;
- 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点;
- 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及它包含的所有子节点。
在操作一个DOM节点前,我们需要通过各种方式先拿到这个DOM节点。
获得Dom节点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="father">
<h1>标题一</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
//对应css选择器
var h1 = document.getElementsByTagName('h1');
var p1 = document.getElementById('p1');
var p2 = document.getElementsByClassName('p2');
var father = document.getElementById('father');
var childrens = father.children;//获取父节点下所有的子节点
//father.firstChild
//father.lastChild
</script>
</body>
</html>
以上是原生代码,之后尽量使用jQuery();
更新节点
拿到一个DOM节点后,我们可以对它进行更新。
可以直接修改节点的文本,方法有两种:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="id1">
</div>
<script>
var id1 = document.getElementById('id1');
</script>
</body>
</html>
操作文本
id1.innerText='hello';
修改文本的值
id1.innerHTML='<strong>hello</strong>';
可以解析HTML文本标签
操作js
<div id="id1">
</div>
<script>
var id1 = document.getElementById('id1');
id1.innerText = 'abc'
</script>
id1.style.color='red';
"red"
id1.style.fontSize='100px';
"100px"
id1.style.padding= '2em';
"2em"
通过js修改百度首页的设置按钮:
1.获取修改对象的id
2.定义变量
3.进行修改
删除节点
要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的 removeChild 把自己删掉:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="father">
<h1>标题1</h1>
<p id="p1">p1</p>
<p class="p2">p2</p>
</div>
<script>
// 拿到待删除节点:
var self = document.getElementById('p1');
//拿到父节点:
var parent = self.parentElement;
// 删除:
parent.removeChild(self);
//删除是一个动态的过程
parent.removeChild(parent.children[0]);
parent.removeChild(parent.children[1]);
parent.removeChild(parent.children[2])
</script>
</body>
</html>
浏览器报错: parent.children[1] 不是一个有效的节点。原因就在于,当 First 节点被删除后, parent.children 的节点数量已经从2变为了1,索引 [1] 已经不存在了。因此,删除多个节点时,要注意 children 属性时刻都在变化。
注意:删除多个节点的时候,children是在时刻变化的。
插入节点
appendChild
当我们获得了某个DOM节点,想在这个DOM节点内插入新的DOM,应该如何做?如果这个DOM节点是空的,那么,直接使用 innerHTML = ‘child’ 就可以修改DOM节点的内容,相当于“插入”了新的DOM节点。
如果这个DOM节点不是空的,那就不能这么做,因为 innerHTML 会直接替换掉原来的所有子节点。有两个办法可以插入新的节点。
一个是使用 appendChild ,把一个子节点添加到父节点的最后一个子节点。例如:
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js = document.getElementById('js');
var list = document.getElementById('list');
list.appendChild(js);//把js追加到list后面
</script>
追加之后结果:
创建一个新的标签,实现插入
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js = document.getElementById('js');//已经存在的节点
var list = document.getElementById('list');
//通过js创建一个新的节点
var newP = document.createElement('p');//创建一个p标签
newP.id = 'newP';
newP.innerText = '我是新创建的newP标签';
list.appendChild(newP);//把newP追加到list后面
</script>
追加后效果如图:
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js = document.getElementById('js');//已经存在的节点
var list = document.getElementById('list');
//通过js创建一个新的节点
var newP = document.createElement('p');//创建一个p标签
newP.id = 'newP';
newP.innerText = '我是新创建的newP';
//创建一个标签节点(通过这个属性,可以设置任意的值)
var myScript = document.createElement('script');
myScript.setAttribute('type','text/javascript');
list.appendChild(myScript);
</script>
动态创建一个节点然后添加到DOM树中,可以实现很多功能。举个例子,下面的代码动态创建了一个节点,然后把它添加到 节点的末尾,这样就动态地给文档添加了新的CSS定义:
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var js = document.getElementById('js');//已经存在的节点
var list = document.getElementById('list');
//通过js创建一个新的节点
var newP = document.createElement('p');//创建一个p标签
newP.id = 'newP';
newP.innerText = '我是新创建的newP';
//创建一个标签节点
var myScript = document.createElement('script');
myScript.setAttribute('type','text/javascript');
//可以创建一个style标签
var myStyle = document.createElement('style');
myStyle.setAttribute('type','text/css');
myStyle.innerHTML = 'body{background-color:red;}';
document.getElementsByTagName('head')[0].appendChild(myStyle)
</script>
观察页面样式的变化,变为红色。
insertBefore
如果我们要把子节点插入到指定的位置怎么办?可以使用parentElement.insertBefore(newElement, referenceElement); ,子节点会插入到referenceElement 之前。
假定我们要把 js插入到 ee之前:
<p id="js">JavaScript</p>
<div id="list">
<p id="se">JavaSE</p>
<p id="ee">JavaEE</p>
<p id="me">JavaME</p>
</div>
<script>
var ee = document.getElementById('ee');
var js = document.getElementById('js');
var list = document.getElementById('list');
//要包含的节点.insertBefore(newNode,targetNode)
list.insertBefore(js,ee);
</script>
浏览器控制台效果图: