DOM、BOM简单介绍

2020-12-13 JavaScript

JavaScript的DOM,BOM简单介绍

# JavaScript能干什么

html:决定网页的结构(脑袋,身体,手脚)

css:决定网页的布局及样式(高矮,胖瘦,黑白)

JavaScript:定义网页的行为(走路,跑步,眨眼)

所以它究竟能干什么?

  1. 可以添加或删除HTML元素,改变其内容,属性和样式
  2. 对页面所有的事件作出反应,实现页面与用户之间实时、动态交互,如用户注册,登录验证
  3. 增强页面动态效果,如下拉菜单,图片轮播,信息滚动
  4. 可以操作数据库,写动画,写游戏,做一些网页特效
  5. ......

# DOM(文档对象模型)

当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。HTML DOM模型被构造成对象的树,页面的每一个组成部分都是一种节点,包含不同的数据:

DOM HTML tree

通过DOM树,开发者可以随心所欲地控制网页内容和结构,并轻松地删除、添加、替换、修改节点。

# 节点介绍

  • 节点的种类主要分为三种:元素节点,文本节点,属性节点
  • 节点关系:兄弟关系,父子关系

# 获取元素节点

<div class="intro" id="box"></div>
1
  1. 通过元素的id:var x = document.getElementById("box");
  2. 通过标签名:var y = document.getElementsByTagName("div");
  3. 通过类名:var z = document.getElementsByClassName("intro");

# 改变元素内容,属性,样式

  1. 直接向HTML输出流写内容:document.write("想写入的内容");
  2. 修改HTML内容(要先获取元素):document.getElementById("box").innerHTML = "新文本";
  3. 修改HTML元素属性:document.getElementById("box").attribute = 新属性值;
  4. 修改元素样式:document.getElementById(id).style.property = 新样式;

注:

  • 所谓的输出流,就是HTML渲染页面,实现输出的过程。HTML的加载过程是由上至下的,当遇到js脚本时,页面加载会被阻塞,浏览器会先去下载js脚本,当js脚本运行完之后,再继续渲染页面。
  • 绝对不要在文档(DOM)加载完成之后使用 document.write(),这会覆盖该文档。(文档加载后不是指在文档后使用script标签进行文档内容写入,而是通过按钮响应等方式在全部页面加载完毕之后进行文本写入)
 <span>行内元素</span>
  <p id="second">我是唯一的</p>
  <div class="box">那我加一</div>
  <div class="box">那我加一</div>
  <div class="box">那我加一</div>
  <a onclick="myFunction()">hello</a><br>
  <img id="image" src="gz.jpg" alt="" width="200">
  <script>
    //获取元素
    var x = document.getElementById('second');
    console.log(x);
    var y = document.getElementsByTagName("span");
    console.log(y);
    console.log(y.length);
    //y是HTMLCollection对象,类似包含HTML元素的一个数组,但它并不是数组,你可以通过索引来获取元素,但无法使用数组的方法,如pop(),push()等
    var z = document.getElementsByClassName("box");
    console.log(z);
    // z[1].innerHTML = "新文本";

    //修改输出流
    document.write("路过");
    function myFunction(){
      document.write("我会发生覆盖");
    }

    //修改属性
    // document.getElementById('image').src = 'th.jpg';
    
    // 修改样式
    // x.style.color = "red";
  </script>
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

# DOM事件

  1. 鼠标点击,移动事件
  2. 网页加载完成触发事件
  3. 当输入字段被改变及表单提交产生的事件等
<p>冬天了,应该多喝热水</p>
  <button id="myBtn">点这里</button><br>
  <input type="text" id="fname" onchange="upperCase()">
  <script>
    window.onload = function load(){
      alert("加载完成");
    }//onload事件在文档加载完成后能立即触发,所以即使是放头部也能执行

    console.log(document.getElementsByTagName('p')[0].innerHTML);//如果放头部就会报错
    
    document.getElementById('myBtn').onclick = function(){
      document.getElementsByTagName('p')[0].style.backgroundColor = "yellow";
    }

    function upperCase(){
      var fname = document.getElementById('fname');
      fname.value = fname.value.toUpperCase();
    }
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# addEventListener()方法

  1. addEventListener()方法用于向指定元素添加事件句柄
  2. 语法:element.addEventListener(event, function, useCapture);
  3. 第一个参数:事件类型,如'click'或'blur'(注意,不能使用"on"前缀)
  4. 第二个参数:事件触发后调用的函数
  5. 第三个参数:用于描述事件是冒泡还是捕获(该参数可省略,默认值为 false, 即冒泡传递,当值为 true 时, 事件使用捕获传递)

注:

  • 该方法可以给一个元素添加多个事件,也可添加多个相同类型的事件,如给一个按钮添加两个"click"事件
  • 该方法添加的事件句柄不会覆盖已存在的事件句柄
  • 可通过removeEventListener()方法来移除事件的监听

事件传递定义了元素事件触发的顺序。 如果你将 < p > 元素插入到 < div > 元素中,用户点击 < p > 元素, 哪个元素的 "click" 事件先被触发呢

  • 冒泡:内部元素的事件会先被触发,然后再触发外部元素,即: < p > 元素的点击事件先触发,然后会触发 < div > 元素的点击事件。
  • 捕获:外部元素的事件会先被触发,然后才会触发内部元素的事件,即: < div > 元素的点击事件先触发 ,然后再触发 < p > 元素的点击事件。
<style>
    #parent{
      background-color: yellow;
      width: 500px;
      height: 200px;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    #son{
      cursor: pointer;
    }
  </style>
  
<div id="parent">
    <p id="son">冬天了,应该多喝热水</p>
  </div>
  <script>
    var x = document.getElementById('parent');
    var y = document.getElementById('son');
    var p1 = 2;
    x.addEventListener('click',function(){
      console.log('我是一个div');
    },true);
    y.addEventListener('click',function(){
      console.log('我是一个p标签');
    },true);
  </script>
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

# 创建,移除,替换元素(节点)

  <div id="box">
    <p id="p1">这是一个段落</p>
    <p id="p2">这是另一个段落</p>
  </div>
  <script>
    //创建新元素
    var para = document.createElement("p");
    var node = document.createTextNode("这是一个新文本");
    para.appendChild(node);
    var divBox = document.getElementById("box");
    //在最后加入新元素
    //divBox.appendChild(para);
    //在指定元素前加入新元素
    var child = document.getElementById('p1');
    // divBox.insertBefore(para,child);
    var secchild = document.getElementById('p2');
    // divBox.insertBefore(para,secchild);

    // 移除已存在的元素
    // divBox.removeChild(child);
    //child.parentNode.removeChild(child);

    //替换元素
    //divBox.replaceChild(para,child);
  </script>
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

# BOM介绍

浏览器对象模型(Browser Object Model (BOM))使 JavaScript 有能力与浏览器"对话"。

  1. 所有浏览器都支持 window 对象。它表示浏览器窗口。
  2. 全局变量是 window 对象的属性。全局函数是 window 对象的方法。同时HTML DOM 的 document 也是 window 对象的属性之一

# window.location 对象

  1. 用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。(可不加window前缀)
    • location.hostname 返回 web 主机的域名
    • location.pathname 返回当前页面的路径和文件名
    • location.port 返回 web 主机的端口 (80 或 443)
    • location.protocol 返回所使用的 web 协议(http: 或 https:)
    • location.replace(url) : 通过加载 URL 指定的文档来替换当前文档 ,这个方法是替换当前窗口页面,前后两个页面共用一个窗口,所以是没有后退返回上一页的

# window.history对象

  1. 在编写时可不使用 window 这个前缀
  2. history.back() - 与在浏览器点击后退按钮相同
  3. history.forward() - 与在浏览器中点击向前按钮相同

# JavaScript弹窗

  1. JavaScript中三种消息框:警告框(alert),确认框(confirm),提示框(prompt)

# JavaScript计时事件

  1. setInterval() - 间隔指定的毫秒数不停地执行指定的代码。(循环执行)
  2. setTimeout() - 在指定的毫秒数后执行指定代码。(延迟执行)
  3. clearInterval() - 用于停止 setInterval() 方法执行的函数代码。
  4. clearTimeout() - 用于停止setTimeout()方法执行的函数代码。
<p>页面上显示时钟:</p>
  <p id="demo"></p>
  <button onclick="stop()">停止</button>
  <script>
    var cir = setInterval(getTime,1000);
    function getTime(){
      var t = new Date();
      var time = t.toLocaleTimeString();
      document.getElementById("demo").innerHTML = time;
    }
    function stop(){
      clearInterval(cir);
    }    
  </script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 最后敲个小栗子

todolist.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .bigBox input{
      outline: none;
    }
    .bigBox button{
      cursor: pointer;
      outline: none;
    }
    .bigBox{
      width: 450px;
      min-height: 300px;
      height: min-content;
      background-color: #F2F3F5;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%,-50%);
      text-align: center;
      padding: .5rem;
      box-sizing: border-box;
    }
    h2{
      letter-spacing: 0.1em;
    }
    .bigBox>input{
      width: 60%;
      border: 1px solid gray;
      padding: .3rem .5rem;
    }
    #add{
      border: none;
      color: white;
      background-color:#1B8FFB;
      padding: .3rem;
      border-radius: 5px;
    }
    #delayadd{
      padding:.3rem;
      border: 1px solid gray;
      border-radius: 5px;
    }
    #allBox > div{
      width: calc(100% - 2rem);
      background-color: white;
      padding: .5rem;
      margin: .5rem;
    }
    #allBox > div::after{
      content: "";
      display: block;
      clear: both;
    }
    #allBox label{
      position: relative;
      float: left;
      width: 20px;
      height: 20px;
      border: 1px solid gray;
    }
    #allBox label input{
      border: none;
      -webkit-appearance:none ;
    }    
    #allBox label span{
      width: 7px;
      height: 14px;
      border-bottom: 1px solid black;
      border-right: 1px solid black;
      transform: rotate(45deg);
      position: absolute;
      top: 2px;
      left: 5px;
      opacity: 0;
    }
    #allBox input:checked ~ span{
      opacity: 1;
    }
    #allBox div>span{
      font-size: 1rem;
      float: left;
      margin-left:.5rem ;
    }
    #allBox button{
      float: right;
      color: red;
      border-radius: 50%;
      border: 1px solid gray;
      outline: none;
    }
  </style>
</head>
<body>
  <div class="bigBox">
    <h2>Todolist</h2>
    <input type="text" id="inputElt" placeholder="请输入待办事项">
    <button id="add">+&nbsp;&nbsp;新增</button>
    <button id="delayadd">+&nbsp;&nbsp;延迟新增</button>
    <div id="allBox">
      <div class="todo">
        <label for="1">
          <input type="checkbox" id="1" onclick="checkItem(1)">
          <span></span>
        </label>
        <span>吃饭</span>
        <button class="btn" onclick="delItem(1)">&#10006;</button>
      </div>
    </div>
  </div>
  <script src="demo.js"></script>
</body>
</html>
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

demo.js

var total = 1;//总条数
var text = [{text:"吃饭",id:1,del:false}];
var box = document.getElementById('allBox');
var todoItem = document.getElementsByClassName("todo");
var inputElt = document.getElementById("inputElt");
var addBtn = document.getElementById("add");
var delayBtn = document.getElementById("delayadd");
var i;

//新增
addBtn.addEventListener('click',()=>{
  var text = inputElt.value;
  console.log(text);
  if(text != ""){
  // if(text.replace(/^\s+|\s+$/g,"") != ""){
    //匹配头尾的任何空白字符,包括空格、制表符、换页符等等  
    this.addContent(text);
    inputElt.value = "";
  }
})
//延迟新增
delayBtn.addEventListener('click',()=>{
  var text = inputElt.value;
  if(text.replace(/^\s+|\s+$/g,"") != ""){
    setTimeout(()=>{
      this.addContent(text);
    },500);
    inputElt.value = "";
  }
})

function addContent(text){
  this.total++;
  console.log(this.total);
  this.text.splice(0,0,{text:text,id:total,del:false});
  //splice()方法用于添加或删除数组元素
  this.add(text,total);
}
//添加待办事项
function add(x,id){
  var div = document.createElement('div');
  var label = document.createElement('label');
  var input = document.createElement('input');
  var span = document.createElement('span');
  var span1 = document.createElement('span');
  var button = document.createElement('button');

  input.type = "checkbox";
  input.setAttribute("id",id);
  input.addEventListener('click',()=>{
    checkItem(id);
  })
  label.appendChild(input); 
  label.appendChild(span); 

  // span1.textContent = x;
  span1.innerHTML = x;
  button.className = "btn";
  button.innerHTML = "&#10006;";
  //删除
  button.addEventListener('click',()=>{
    delItem(id);
  })
  div.appendChild(label);
  div.appendChild(span1);
  div.appendChild(button);
  div.className = "todo"; 
  box.prepend(div);
} 
//删除
function delItem(id){
  var length = this.text.length;
  console.log(this.text);
  for(i = length-1;i>=0;i--){
    if(this.text[i].id == id)
      this.text[i].del = true;
  }
  for(i = length-1;i>=0;i--){
    if(this.text[i].del){
      box.removeChild(todoItem[i]);
      this.text.splice(i,1);
    }
  }
}
//勾选删除项
function checkItem(id){
  for(i = 0;i<this.text.length;i++){
    if(this.text[i].id == id)
      this.text[i].del = !this.text[i].del;
  }
}
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91