JavaScript - DOM 基础操作

一、 DOM

 web API 是浏览器 提供的一套操作 浏览器功能(BOM)和 页面元素(DOM)的 API。

 DOM:处理 HTML 的标准 编程接口

1. 获取元素

::: note

  1. 通过 document 查找元素,是查找整个页面所有的元素;
  2. 通过 标签元素查找,是查找的该标签元素下的 子元素

:::

id 获取 元素 ( getElementById()

  • 获取的元素的返回值是一个对象;
  • console.dir(元素对象) :可以查看元素的 属性 和方法;
  • 如果没有找到元素,则返回 null
1
2
3
4
5
6
<div id="time"></div>

<script type="text/javascript">
var el = document.getElementById('time')
console.log(el)
</script>

标签名 获取元素 ( getElementsByTagName()

  • getElementsByTagName() : 返回一个 元素 对象合集,以伪数组的形式存储;
  • 如果没有找到元素,则返回一个 空 数组

获取页面所有的 li 标签元素:

1
2
3
4
5
6
7
8
9
10
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>

<script type="text/javascript">
var el = document.getElementsByTagName('li')
console.log(el) // [li, li, li, li, li]
</script>

获取 父元素中 指定 标签名 的子元素:

::: warning

  1. 父元素必须是 单个对象(必须指明是哪一个元素对象);
  2. 获取的元素不包括父元素 自己;

:::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<ol>
<li>这是 ol 中的 li 元素</li>
<li>这是 ol 中的 li 元素</li>
<li>这是 ol 中的 li 元素</li>
<li>这是 ol 中的 li 元素</li>
<li>这是 ol 中的 li 元素</li>
</ol>
<ul>
<li>这是 ul 中的 li 元素</li>
<li>这是 ul 中的 li 元素</li>
<li>这是 ul 中的 li 元素</li>
<li>这是 ul 中的 li 元素</li>
<li>这是 ul 中的 li 元素</li>
</ul>

<script type="text/javascript">
var ol = document.getElementsByTagName('ol')

// 必须指明是哪一个元素对象 ol[0]
var li = ol[0].getElementsByTagName('li')
console.log(li)
</script>

类名 获取元素 (getElementsByClassName

  • 返回的是 一个 伪类集合;
  • 使用时需要指定具体的一个 对象;
1
2
3
4
5
6
7
<div class="box"></div>
<div class="box"></div>

<script type="text/javascript">
var box = document.getElementsByClassName('box');
console.log(box) // [div.box, div.box]
</script>

指定选择器 获取元素 (querySelector('选择器')

  • 返回的是 元素中 的 第一个对象;
  • 选择器参数 格式 和 css 格式一致, . 表示类, #表示id
1
2
3
4
5
6
7
<div class="box">元素1</div>
<div class="box">元素2</div>

<script type="text/javascript">
var box = document.querySelector('.box');
console.log(box) // <div class="box">元素1</div>
</script>

querySelectorAll('选择器') : 返回 选择器的 所有元素

  • 返回的是 一个 伪数组
1
2
3
4
5
6
7
<div class="box">元素1</div>
<div class="box">元素2</div>

<script type="text/javascript">
var box = document.querySelectorAll('.box');
console.log(box) // [div.box, div.box]
</script>

2. 获取 body 和 html 元素

获取 body 元素 : 返回 body 元素对象

1
var el_body = document.body;

获取 html 元素 : 返回 HTML 元素对象

1
var el_html = document.documentElement;

二、 操作元素

常见鼠标事件:

鼠标事件触发条件
onclick鼠标左键点击
onmouseover鼠标经过触发
onmouseout鼠标离开触发
onfocus获取鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmouseup鼠标弹出触发
onmousedown鼠标按下触发

1. 事件三要素

事件三要素:1. 事件源,2. 绑定事件,3. 事件处理程序

  • 事件源:事件触发的对象
  • 绑定事件:如何触发,什么时间
  • 事件处理程序: 通过 函数赋值的方式 完成
1
2
3
4
5
6
7
8
<button type="button" class="mui-btn mui-btn-blue">唐伯虎</button>

<script type="text/javascript">
var but = document.querySelector('.mui-btn');
but.onclick = function(){
alert('点秋香')
}
</script>

2. 修改元素内容

方法说明实例
element.innerText替换元素内容,不识别HTML 标签
去除空格 和 换行符
div.innerText = ‘你好’;
element.innerHTML
(w3c 推荐)
替换元素内容,可识别HTML 标签
保留空格 和 换行符
div.innerHTML = ‘你好’;

区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="demo1">
<strong>innerText</strong> 不识别 HTML 标签
</div>
<hr>
<div class="demo2">
<strong>innerHTML</strong> 识别 HTML 标签
</div>


<script>
var div1 = document.querySelector('.demo1')
var div2 = document.querySelector('.demo2')

console.log(div1.innerText); // innerText 不识别 HTML 标签
console.log(div2.innerHTML); // <strong>innerHTML</strong> 识别 HTML 标签
</script>

案例

::: details

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<!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>
</head>

<body>
<button>显示当前时间</button>
<div>123</div>

<p></p>

<script>
var bt = document.querySelector('button');
var div = document.querySelector('div');
var date = new Date();
bt.onclick = function() {
div.innerText = getDate();
}

var p = document.querySelector('p');
p.innerText = getDate();

function getDate() {
var day = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
var date = new Date();
var Y = date.getFullYear();
var M = date.getMonth();
var D = date.getDate();
var d = date.getDay();
d = day[d];
var h = date.getHours();
h = h < 10 ? '0' + h : h;
var m = date.getMinutes();
m = m < 10 ? '0' + m : m;
var s = date.getSeconds();
s = s < 10 ? '0' + s : s;
return Y + '年' + M + '月' + D + '日 ' + d + ' ' + h + ':' + m + ':' + s
}
</script>
</body>

</html>

:::

3. 操作元素属性

::: tip

自定义属性命名规范:以 data- 开头。

html5 新增的获取自定义属性的方法( ie 11 才支持):

  1. element.dataset ,返回的是所有自定义属性的集合
  2. element.dataset['index'], 返回的是所有自定义属性的集合
  3. 如果属性名是多个单词组成,获取属性值时需要用驼峰命名法,
    1. 如:属性名:data-time-set ,获取属性值时:timeSet
1
2
3
4
5
6
7
8
9
<div data-time='20' data-ind="2"></div>

<script>
var div = document.querySelector('div')

console.log(div.dataset); // {time: '20', ind: '2'}
console.log(div.dataset.ind); // 2
console.log(div.dataset['time']); // 20
</script>

:::

获取元素属性的方法:

::: note

  1. element.属性,如: console.log(div.id)
    1. 只能获得 元素的 内置 属性;
  2. element.getAttribute('属性'), 如: console.log(div.getAttribute('id'))
    1. 可以获得 元素的 自定义属性

:::

设置元素属性的方法:

::: note

  1. element.属性 ,如: div.className = 'bg'
    1. 主要用于设置 内置 属性
  2. element.setAttribute('属性', '值') , 如: div.setAttribute('index', 'bg')
    1. 主要用于设置 自定义 属性

:::

移除元素属性的方法:

::: note

element.removeAttribute('属性'),如: div.removeAttribute('index')

:::

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<button class="ldh">刘德华</button>
<button class="vxy">张学友</button>
<img src="https://img.pupper.cn/img/202112091653296.jpg" alt="">


<script>
var ldh = document.querySelector('.ldh');
var vxy = document.querySelector('.vxy');
var img = document.querySelector('img');

ldh.onclick = function() {
img.src = 'https://img.pupper.cn/img/202112091653296.jpg';
img.title = '刘德华';
}
vxy.onclick = function() {
img.src = 'https://img.pupper.cn/img/202112091653109.jpg';
img.title = '张学友';
}

案例1

::: details

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!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>
img {
margin: 10px;
display: block;
}

button {
margin: 10px;
}
</style>
</head>

<body>
<button class="ldh">刘德华</button>
<button class="vxy">张学友</button>
<img src="https://img.pupper.cn/img/202112091653296.jpg" alt="">


<script>
var ldh = document.querySelector('.ldh');
var vxy = document.querySelector('.vxy');
var img = document.querySelector('img');

ldh.onclick = function() {
img.src = 'https://img.pupper.cn/img/202112091653296.jpg';
img.title = '刘德华';
}
vxy.onclick = function() {
img.src = 'https://img.pupper.cn/img/202112091653109.jpg';
img.title = '张学友';
}
</script>
</body>

</html>

:::

案例2

::: details

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!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>
img {
margin: 10px;
display: block;
width: 200px;
}
</style>
</head>

<body>
<img src="https://img.pupper.cn/img/202112091713378.gif" alt="">
<p>上午好</p>


<script>
var img = document.querySelector('img')
var p = document.querySelector('p')

function getDate() {
var date = new Date();
var h = date.getHours();
return h;
}

if (getDate() < 12) {
img.src = 'https://img.pupper.cn/img/202112091713378.gif';
p.innerHTML = '上午好';
} else {
img.src = 'https://img.pupper.cn/img/202112091713834.gif';
p.innerHTML = '下午好';
}
</script>
</body>

</html>

:::

4. 操作表单 元素属性

利用 DOM 可以操作表单属性,type、value、checked、selected、disabled等

表单中的值 需要通过 value 才能修改,innerHTML 不能修改

this : 指向 时间函数的调用者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<button>按钮</button>
<input type="text">

<script>
var btn = document.querySelector('button');
var input = document.querySelector('input');

btn.onclick = function() {
input.value = '按钮被禁用了';

// `this` : 指向 时间函数的调用者
this.disabled = true;
}
</script>

案例 — 密码框

::: details

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<!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;
box-sizing: border-box;
}
.box {
position: relative;
margin: 100px auto;
background-color: rgb(248, 238, 238);
width: 200px;
height: 30px;
}
.box img {
position: absolute;
top: -5px;
right: 5px;
width: 40px;
}
.box input {
width: 100%;
height: 100%;
outline: none;
padding-left: 10px;
padding-right: 50px;
}
</style>
</head>

<body>
<div class="demo">
<div class="box">
<img src="https://img.pupper.cn/img/202112091853918.png" alt="">
<input type="password">
</div>
</div>

<script>
var img = document.querySelector('img');
var inp = document.querySelector('input');
var flag = 0;
img.onclick = function () {
switch (flag) {
case 0:
img.src = "https://img.pupper.cn/img/202112091853475.png";
inp.type = 'text';
flag = 1;
break;
case 1:
img.src = 'https://img.pupper.cn/img/202112091853918.png';
inp.type = 'password';
flag = 0;
break;
}
}
</script>

</body>

</html>

:::

5. 操作 样式属性

方法说明
element.style行内样式操作
element.className通过改变标签的 类名 来获取 新 的样式

注意:

js 修改的样式 为 行内样式,他的权重 最高

三、节点操作

一般时,节点至少拥有 nodeType(节点类型)、nodeName(节点名称)、nodeValue(节点值)三个基本属性

::: note

  • 元素节点: nodeType1
  • 属性节点: nodeType2
  • 文本节点: nodeType3 (文本节点包括:文字、空格、换行等)

:::

1. 父节点(parentNode)

使用父节点时,一般得到的是离他最近的 父节点,如果找不到父节点,就返回 null。

1
2
3
4
5
6
7
8
9
10
<div class="demo">
<div class="box">
<p class="set"></p>
</div>
</div>

<script>
var div = document.querySelector('.set')
console.log(div.parentNode); // <div class="box"><p class="set"></p></div>
</script>

2. 子节点(children)

children: 返回所有的子元素节点集合数组

childNode : 返回所有的子节点集合数组,包含元素节点、文本节点等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="demo">
<div class="box">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
</div>

<script>
var div = document.querySelector('.box').querySelector('ul');
console.log(div.childNodes); // [text, li, text, li, text, li, text, li, text]
console.log(div.children); // [li, li, li, li]
</script>
  1. firstChild: 获取第一个子节点,不管是文本节点还是元素节点,
  2. lastChild: 获取最后一个子节点,不管是文本节点还是元素节点,

    以下方法需要 ie9 以上才能支持:

  3. firstElementChild : 返回第一个 子 元素 节点

  4. lastElementChild : 返回 最后一个 子 元素 节点

::: note

实际开发中的写法: console.log(div.children[0])

1
2
3
// 获取最后一个子元素

console.log(div.children[div.children.length -1])

:::

3. 兄弟节点(nextSibling)

node.nextSibling : 返回下一个兄弟节点,找不到则返回null,返回中包含所有节点

1
2
3
4
5
6
7
<div>我是div</div>
<span>我是span</span>

<script>
var div = document.querySelector('div');
console.log(div.nextSibling); // #next
</script>

node.previousSibling : 返回上一个兄弟节点,找不到返回null, 返回中包含所有节点

1
2
3
4
5
6
7
<div>我是div</div>
<span>我是span</span>

<script>
var div = document.querySelector('div');
console.log(div.previousSibling); // #next
</script>

以下方法 需要 ie9 以上支持

nede.nextElementSibling : 返回下一个兄弟元素节点,找不到返回null

1
2
3
4
5
6
7
<div>我是div</div>
<span>我是span</span>

<script>
var div = document.querySelector('div');
console.log(div.nextElementSibling); // <span>我是span</span>
</script>

nede.previousElementSibling : 返回上一个兄弟元素节点,找不到返回null

1
2
3
4
5
6
7
<div>我是div</div>
<span>我是span</span>

<script>
var div = document.querySelector('div');
console.log(div.previousElementSibling); // null
</script>

兼容封装函数

1
2
3
4
5
6
7
8
function getNextElementSibling(element){
var el = element;
while (el = el.nextSibling) {
if (el.nodeTpye === 1) {
return el;
}
r
}

3. 创建及添加节点

语法:

1
2
3
4
5
6
// 创建节点
document.createElement('tagName');
// 后面添加节点
node.appendChild(child);

node.insertBefore(child, 指定元素)

createElement : 创建元素

appendChild : 在父元素后追加元素

insertBefore : 在指定 元素前 添加元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<ul>
<li>123</li>
</ul>

<script>
// 创建元素
var li = document.createElement('li');
// 在最后追加元素
var ul = document.querySelector('ul');
ul.appendChild(li)
// 在指定元素前添加元素
var li1 = document.createElement('li');
ul.insertBefore(li1, ul.children[0])
</script>

运行结果:

1
2
3
4
5
<ul>
<li></li>
<li>123</li>
<li></li>
</ul>

::: details

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!DOCTYPE html>
<html lang="zh">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.demo {
width: 600px;
margin: 100px auto;
}
</style>
</head>

<body>
<div class="demo">
<textarea name="" id="" cols="30" rows="10"></textarea>
<button>发布</button>
<ul></ul>
</div>

<script>
var text = document.querySelector('textarea');
var but = document.querySelector('button');
var ul = document.querySelector('ul');

but.onclick = function(){
var li = document.createElement('li');
li.innerHTML = text.value;
var li1 = ul.appendChild(li);
}
</script>
</html>

:::

3. 删除节点

语法:

1
node.removeChild(child);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div class="demo">
<button>删除</button>
<ul>
<li>熊大</li>
<li>熊二</li>
<li>光头强</li>
</ul>
</div>

<script>
var but = document.querySelector('button');
var ul = document.querySelector('ul');
but.onclick = function(){
if (ul.children.length != 0){
ul.removeChild(ul.children[0]);
}else {
this.disabled = true;
}
}
</script>

4. 复制节点

语法:

1
node.cloneNode()

cloneNode() : 返回调用该方法的节点的一个副本。

::: warning

  1. 如果括号里的参数为空 或为 false, 则是 浅拷贝,只复制节点本身,不复制里面的子元素;
  2. 如果括号里的参数为 true,则是 深拷贝,会复制他里边的所有内容

:::

1
2
3
4
5
6
7
8
9
10
11
12
13
<div class="demo">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</div>

<script>
var ul = document.querySelector('ul');
var li = ul.children[0].cloneNode(true);
ul.appendChild(li)
</script>

5. 三种动态创建元素的区别

1
2
3
document.write()
document.innerHTML()
document.createElement()

区别:

  1. document.write : 直接写入页面的内容流,会导致页面全部重绘
  2. innerHTML : 使用数字的形式 创建多个元素 时效率更高,但是结构复杂
  3. createElement : 创建多个元素时 效率稍低,但是结构清晰