1. 基本概念
文档对象模型(Document Object Model, 简称DOM),是W3C组织推荐的处理可扩展标记语言(HTML或XML)的标准编程接口。可以改变页面的内容结构和样式。
DOM 里面的专有名词
DOM 树
- 文档 :一个页面就是一个文档,在DOM中用document表示
- 元素:页面中的所有标签都是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示
DOM 把以上内容都看做对象
2. 获取页面元素
DOM在实际开发中主要用来操作元素
1. 根据ID获取元素
使用getElementById()方法获取
<div id="time">2022-3-10</div>
<script>
// 1.因为页面文档从上往下加载,所以得先有标签,所以script要写到标签的下面
// 2.参数 id 是大小写敏感的字符串
var timer = document.getElementById('time');
console.log(timer, typeof timer); // 3. 返回的是元素对象
// 4.console.dir 打印我们返回的元素对象 更好的查看里面的属性和方法
console.dir(timer);
</script>
2. 根据标签名获取
使用 getElementsByTagName()方法可以返回带有指定标签名的对象的集合
// 1. 返回的是 获取过来的元素对象的集合 以伪数组的形式存储的
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[2]); //<li>hhhhhhhhh3</li>
// 2.采取遍历 依次打印里面的元素对象
for(var i = 0; i < lis.length; i++){
console.log(lis[i]);
}
- 返回的是 获取过来的元素对象的集合 以伪数组的形式存储的
- 页面只有一个li或者没有li返回的依旧是伪数组形式
- element.getElementsByTagName(‘标签名’) 可以获取某个元素(父元素)内部所有指定标签名的子元素。 注意:父元素 必须是单个对象,获取的时候不包括父元素自己
var ol = document.getElementsByTagName('ol');
console.log(ol[0].getElementsByTagName('li')); //注意获取单个父元素ol[0] (即使只有一个ol也要这么写,因为是伪数组)
// 常用写法 给ol加id
var ol = document.getElementById('ol');
console.log(ol.getElementsByTagName('li'));
3. 根据H5新增的方法获取
H5新增:只兼容ie9以上
- getElementsByClassName()根据类名获取元素集合
// 返回的是伪数组 getElementsByClassName
var boxs = document.getElementsByClassName('box');
console.log(boxs);
- querySelector(‘选择器’) 根据指定选择器返回第一个元素对象(不分id标签类了,但里面的选择器要加对应符号)
// querySelector(‘选择器’) 根据指定选择器返回第一个元素对象(不分id标签类了)
var firstBox = document.querySelector('.box');
console.log(firstBox);
var firstNav = document.querySelector('#nav');
console.log(firstNav);
- querySelectorAll(‘选择器’); 根据指定选择器返回对应的所有对象 也是伪数组
// querySelectorAll('选择器'); 根据指定选择器返回对应的所有对象
var allBox = document.querySelectorAll('.box');
console.log(allBox); // 也是伪数组
4. 特殊元素获取(body,html)
- 获取body元素
document.body 返回body对象
var bodyEle = document.body;
console.log(bodyEle);
- 获取HTML元素
document.documentElement 返回html对象
var htmlEle = document.documentElement;
console.log(htmlEle);
3. 事件基础
JavaScript 使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为
触发 – 响应机制
网页中的每个元素都可以产生某些可以触发JavaScript的事件,如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作
事件三要素:事件源、事件类型、事件处理程序
执行事件的步骤
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值的方式)
<button id="btn">唐伯虎</button>
<div>123</div>
<script>
// 点击div 控制台输出 我被选中了
// 1. 获取事件源
var divFirst = document.querySelector('div'); // 获取第一个div对象
// 2. 注册(绑定)事件 divFirst.onclick
// 3. 添加事件处理程序
divFirst.onclick = function() {
console.log('我被选中了');
}
</script>
常见的鼠标事件
4.操作元素 (较核心)
1.改变元素内容
下面两个属性都是可读写的,可以获取里面的内容
-
element.innerText : 从起始位置到终止位置的内容,但它去除html标签,同时空格和换行也会去除。 非标准
-
element.innerHTML : 从起始位置到终止位置的全部内容,包括html标签,保留空格和换行,和innerText最大区别 :能识别html标签,推荐使用这个。 W3C标准。
<!-- innerText 和innerHTML区别 -->
<div></div>
<p>
我是文字
<span>123</span>
</p>
<script>
// 1.innerText 不识别html标签
var div = document.querySelector('div');
div.innerText = '<strong>今天是:</strong> 2022年';
// 可读写 获取元素里的内容 会去除标签 空格和换行
var p = document.querySelector('p');
console.log(p.innerText);
// 2.innerHTML 识别HTML标签
div.innerHTML = '<strong>今天是:</strong> 2022年';
// 可读写 获取元素里的内容 保留标签 空格和换行
console.log(p.innerHTML);
</script>
demo – 获取当前系统时间 结合函数
<button>显示当前系统时间</button>
<div>某个时间</div>
<script>
// 点击按钮 div里面的文字发生变化 innerText
var buttonFirst = document.querySelector('button');
var divFirst = document.querySelector('div');
buttonFirst.onclick = function() {
divFirst.innerHTML = getDate();
}
function getDate(){
var timer = new Date(); // 当前的系统时间
var year = timer.getFullYear();
var month = timer.getMonth() + 1; //注意0-11 要手动+1
month = addZero(month);
var date1 = timer.getDate();
date1 = addZero(date1);
var hour = timer.getHours();
hour = addZero(hour);
var min = timer.getMinutes();
min = addZero(min);
var second = timer.getSeconds();
second = addZero(second);
var dayArr = ['日', '一', '二', '三', '四', '五', '六']
var day = dayArr[timer.getDay()]; //getDay() 0-6 0是周日
return '现在是:'+year+'年'+month+'月'+date1+'日星期'+day+' '+hour+':'+min+':'
+second;
}
function addZero(x){
x = x < 10 ? '0' + x : x;
return x;
}
</script>
2. 常用属性操作
demo1 – src 点击不同的按钮 出现不同的图片 其他属性操作类似
<button>1111</button>
<button>2222</button>
<img src="../images/yexuan1.jpg" alt="">
<script>
// 点击不同的按钮 出现不同的图片
var btns = document.getElementsByTagName('button');
var img = document.querySelector('img');
btns[0].onclick = function() {
img.src = '../images/yexuan1.jpg'
}
btns[1].onclick = function() {
img.src = '../images/yexuan2.jpg'
}
</script>
demo2 – 根据时间不同显示不同的问候语和图片
<!-- demo 分时显示不同图片和问候语 -->
<div>上午好</div>
<img src="../images/yexuan1.jpg" alt="">
<script>
// 重点是 对当前时间的判断
// 1. 获取元素
var div = document.querySelector('div');
var img = document.querySelector('img');
// 2. 绑定事件 怎样用时间绑定呢?
// 得到当前的小时数 使用分支语句实现事件处理程序
var date = new Date();
var h = date.getHours();
if (h <= 5) {
div.innerHTML = '晚上好,早点休息';
img.src = '../images/yexuan1.jpg';
} else if (h <= 12) {
div.innerHTML = '上午好';
img.src = '../images/yexuan2.jpg';
} else if (h <= 18) {
div.innerHTML = '下午好';
img.src = '../images/yexuan3.webp';
} else {
div.innerHTML = '晚上好';
img.src = '../images/yexuan4.webp';
}
</script>
3. 表单元素的属性操作
- 表单里面的值不能通过innerHTML改变,而是通过value修改
- 如果想要某个表单被禁用 不能再点击 使用disabled
4. 样式属性操作
通过js修改元素的大小、颜色、位置等样式
- element.style 行内样式操作 适用于要修改的样式少 功能简单的情况
- js使用驼峰命名法 如: backgroundColor
- js修改style样式操作,产生的是行内样式,css权重较高
<!-- 样式属性操作 -->
<div style="width: 100px; height: 100px; background-color: pink;"></div>
<script>
var div = document.querySelector('div');
div.onclick = function(){
// 行内样式操作 element.style 注意js是驼峰命名法
div.style.backgroundColor = 'purple';
div.style.width = '50px';
}
</script>
- 表单属性事件 onfocus得到焦点 onblur 失去交掉
<!-- 表单属性事件 onfocus onblur -->
<input type="text" value="请输入" style="color: #999;">
<script>
// 1. 获取元素
var text = document.querySelector('input');
// 2. 注册事件 获得焦点 onfocus
text.onfocus = function() {
// 判断是不是默认字 是就清空
if (this.value === '请输入') {
this.value = '';
}
// 获得焦点 把文字颜色变深
this.style.color = 'black';
}
// 注册事件 失去焦点 onblur
text.onblur = function() {
// 判断 表单是否为空 为空就恢复默认字
if (this.value === ''){
this.value = '请输入';
}
// 失去焦点 把颜色变回#999
this.style.color = '#999';
}
</script>
- element.className 类名样式操作 适合于功能较多,样式复杂的情况
- 样式修改较多,使用这种方法
- class因为是个保留字,因此使用className来操作元素类名属性
- className会直接更改元素的类名,会覆盖原先的类名
<!-- element.className -->
<div class="first"></div>
<script>
var div = document.querySelector('div');
div.onclick = function(){
// 类名样式操做 element.className
// 将需要修改的一系列样式全部修改到change上
div.className = 'change';
// 如果想要保留原先的格式 使用如下写法 多类名选择器
div.className = 'first change';
}
</script>
5. 排他思想
如果有同一组元素,我们想要某一个元素实现某种样式,需要用到循环排它思想算法:
- 所有元素全部清除样式(干掉其他人)
- 给当前元素设置样式(留下我自己)
<!-- 排它思想 -->
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
// 1.获取所有的按钮元素
var btns = document.getElementsByTagName('button');
// 2.注册事件 使用for循环给每个按钮注册点击事件
for (var i = 0; i < btns.length; i ++) {
btns[i].onclick = function() {
// 排它思想:点击时,1.把其他背景颜色全部去除,2.给当前按钮设置背景色
for (var j = 0; j < btns.length; j ++) {
btns[j].style.backgroundColor = '';
}
this.style.backgroundColor = 'pink';
}
}
</script>
- 自定义属性的操作
自定义属性:程序员自己添加的属性
(1) 获取属性值:
- element.属性
获取内置属性值(元素本身自带的属性) - element.getAttribute(‘属性’)
主要获得自定义的属性(程序员自定义)
(2)设置属性值
- element.属性 = ‘值’ 设置内置属性
- element.setAttribute(‘属性’, ‘值’) 设置自定义属性
(3)移除属性
- element.removeAttribute(‘属性’)
- H5自定义属性–规范
自定义属性的目的:为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。 但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。
因此H5给我们新增了自定义属性:H5规定自定义属性以data- 开头作为属性名并且赋值
H5新增获取自定义属性:element.dataset.属性名(如果自定义属性里有多个-链接的单词,那么js中要使用驼峰命名法获取) 兼容ie11,兼容性较差,所以目前一般使用getAttribute()方法
5. 节点操作
1.节点操作的目的
获取元素通常使用两种方法
- 使用DOM提供的方法获取,如document.getElementById()等方式。逻辑性不强,繁琐
- 利用节点的层次关系来获取元素,逻辑性强,但兼容性稍差
这两种方法后面都会使用,但是节点操作更简单
节点:
页面中所有的内容都是节点,在DOM中,节点使用node来表示。HTML DOM 树中的所有节点均可以通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。
2.demo – 制作下拉列表
思路
- 一个nav,无序列表构成
- 一个对应内容sub-nav, .nav>ul>li.sub-nav=ul>li
- 获取元素:(1).nav ul子元素li (2) .sub-nav 子元素ul
- 注册事件 执行操作 for循环遍历(1),鼠标经过(1),显示(2);鼠标移开(1)且鼠标移开(2) 隐藏(2);
代码实现
<!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>Document</title>
<style>
/* flex布局 */
*{
margin: 0;
padding: 0;
}
a{
text-decoration: none;
color: black;
}
ul{
list-style: none;
}
.nav{
display: flex;
justify-content: center;
}
.nav>li{
position: relative;
width: 80px;
height: 60px;
line-height: 60px;
text-align: center;
font-size: 20px;
}
.nav li .sub-nav{
display: none;
position: absolute;
top: 60px;
}
.nav li .sub-nav li{
width: 80px;
height: 30px;
line-height: 30px;
font-size: 16px;
text-align: center;
}
</style>
</head>
<body>
<ul class="nav">
<li>
<a href="#">狸花猫</a>
<ul class="sub-nav">
<li>狸花猫</li>
<li>狸花猫</li>
<li>狸花猫</li>
<li>狸花猫</li>
<li>狸花猫</li>
</ul>
</li>
<li>
<a href="#">波斯猫</a>
<ul class="sub-nav">
<li>波斯猫</li>
<li>波斯猫</li>
<li>波斯猫</li>
<li>波斯猫</li>
<li>波斯猫</li>
</ul>
</li>
<li>
<a href="#">无毛猫</a>
<ul class="sub-nav">
<li>无毛猫</li>
<li>无毛猫</li>
<li>无毛猫</li>
<li>无毛猫</li>
<li>无毛猫</li>
</ul>
</li>
<li>
<a href="#">英短</a>
<ul class="sub-nav">
<li>英短</li>
<li>英短</li>
<li>英短</li>
<li>英短</li>
<li>英短</li>
</ul>
</li>
<li>
<a href="#">暹罗猫</a>
<ul class="sub-nav">
<li>暹罗猫</li>
<li>暹罗猫</li>
<li>暹罗猫</li>
<li>暹罗猫</li>
<li>暹罗猫</li>
</ul>
</li>
</ul>
<script>
// 制作下拉列表
// 1. 一个nav,无序列表构成 .nav=ul>li
// 2. 一个对应内容sub-nav, .nav=ul>li.sub-nav=ul>li
// 3. 获取元素:(1).nav ul子元素li (2) .sub-nav 子元素ul
// 4. 注册事件 执行操作 for循环遍历(1),鼠标经过(1),显示(2);鼠标移开(1) 隐藏(2);
var nav = document.querySelector('.nav');
lis = nav.children; // 获取子元素
for (var i = 0; i < lis.length; i ++){
lis[i].onmouseover = function(){
var subNav = this.children; // 这个获取元素要写在里面,写在外面经过for循环不断更新,结果subNav只能是获取到最后一个子元素
// console.log(subNav[1]);
subNav[1].style.display = 'block';
}
lis[i].onmouseout = function() {
var subNav = this.children;
// console.log(subNav[1]);
subNav[1].style.display = 'none';
}
}
</script>
</body>
</html>
效果呈现
3.demo – 制作留言板
思路
- 一个大盒子.leave-word装整个留言板块 一个.word-input框输入留言, 一个button控制发布留言, li添加留言
- 获取元素 .word-input button li
- 注册事件 button.onclick 点击发布
- 执行程序 添加元素li 先创建 document.createElement(‘li’) 再添加,保持最新评论置顶 parentNode.insertBefore(li, parentNode[2])
代码实现:
<!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>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
body{
display: flex;
justify-content: center;
}
.leave-word{
margin-top: 100px;
}
</style>
</head>
<body>
<div class="leave-word">
<!-- 多行文本 -->
<textarea name="留言框" id="word-input" cols="30" rows="10"></textarea>
<button>发布</button>
<ul>
<li>111</li>
</ul>
</div>
<script>
// 1. 一个大盒子.leave-word装整个留言板块 一个.word-input框输入留言, 一个button控制发布留言, li添加留言
// 2. 获取元素 .word-input button li
// 3. 注册事件 button.onclick 点击发布
// 4. 执行程序 添加元素li 先创建 document.createElement('li') 再添加,保持最新评论置顶 parentNode.insertBefore(li, parentNode[2])
var leaveWord = document.querySelector('.leave-word');
var wordInput = leaveWord.children[0];
var btn = leaveWord.children[1];
var ul = leaveWord.children[2];
// console.log(btn);
btn.onclick = function() {
// wordInput.innerText = '222'; // ?明明可以写入却无法读取
// console.log(wordInput.innerText); // ?就是说textarea里面的内容不可读取
// console.log(wordInput.textContent); // 好了 可以使用textContent读取
// 判断 wordInput 是否为空 为空弹出,你并未输入内容,无法发布
if(wordInput.value== ''){ // 好家伙 看了视频 居然是用value 前面全部推翻
alert('您并未输入内容,无法发布留言。');
} else{
// 不为空 1.创建元素
var li = document.createElement('li');
li.innerHTML = wordInput.value;
// 2.添加元素 使新添加的是内容始终保持置顶
ul.insertBefore(li, ul.children[0]);
// 3.添加成功后,清除留言框内容
wordInput.value = '';
}
}
</script>
</body>
</html>
效果呈现: