一、JavaScript 运行过程及组成
- 编写的代码是保存在文件中的, 也就是存储在硬盘(外存上).
- 双击 .html 文件浏览器(应用程序)就会读取文件, 把文件内容加载到内存中(数据流向: 硬盘 => 内存)
- 浏览器会解析用户编写的代码, 把代码翻译成二进制的, 能让计算机识别的指令(解释器的工作)
- 得到的二进制指令会被 CPU 加载并执行(数据流向: 内存 => CPU)
\
JavaScript 的组成:
ECMAScript(简称 ES) :JavaScript 语法。
DOM: 页面文档对象模型,对页面中的元素进行操作。
BOM: 浏览器对象模型,对浏览器窗口进行操作。
\
二、JavaScript 的书写形式
2.1 行内式
直接嵌入到 html 元素内部:
<!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>
<input type="button" value="点击我" onclick="alert('prprpr!')">
</body>
</html>
运行结果:
注意, JS 中字符串常量可以使用单引号表示, 也可以 使用双引号表示.
HTML 中推荐使用双引号, JS 中推荐使用单引号
2.2 内嵌式
写到 script 标签中:
<body>
<script>
alert('prprpr!');
</script>
</body>
运行结果:
\
2.3 外部式
写到单独的 .js 文件中
alert('prprpr~~~');
<body>
<script src="demo7.js"></script>
</body>
运行结果:
注意, 这种情况下 script 标签中间不能写代码. 必须空着(写了代码也不会执行).
适合代码多的情况.
\
三、输入输出
3.1 输入:prompt
弹出一个输入框
<body>
<script>
prompt("请输入你的姓名:");
</script>
</body>
运行结果:
3.2 输出:alert
弹出一个警示对话框,输出结果:
<body>
<script>
alert("hello world!");
</script>
</body>
运行结果:
3.3 输出:console.log
在控制台打印一个日志(供程序员看)
<body>
<script>
console.log("这是一条日志");
</script>
</body>
注意: 在 VSCode 中直接输入 "log" 再按 tab 键, 就可以快速输入 console.log
打开开发者工具(F12)==》Console(控制台) 标签页才能看到结果:
重要概念:console
console 是一个 js 中的 "对象"
. 表示取对象中的某个属性或者方法, . 可以直观理解成 "的"
console.log 就可以理解成: 使用 "控制台" 对象 "的" log 方法
四、语法介绍
4.1 变量的使用
JS 中创建的变量,不需要显式指定类型。
变量的实际类型,根据初始化/赋值来确定。
var name = 'zhangsan';
var age = 20;
使用变量:
console.log(age); // 读取变量的内容
age = 100; // 修改变量的内容
console.log(age);
\
4.2 理解动态类型
- JS 的变量类型式程序运行过程中才确定的。
var a = 10; // 数字
var b = "hello"; // 字符串
- 随着程序运行,变量的类型可能会发送改变。
var a = 10; // 数字
a = "world"; // 字符串
\
4.3 基本数据类型
JS 中内置的几种类型
- number: 数字. 不区分整数和小数.
- boolean: true 真, false 假.
- string: 字符串类型.
- undefined: 只有唯一的值 undefined. 表示未定义的值.
- null: 只有唯一的值 null. 表示空值.
number 数字类型
JS 中不区分整数和浮点数, 统一都使用 "数字类型" 来表示。
数字进制表示
var a = 07; // 八进制整数,以 0 开头
var b = 0xa; // 十六进制整数,以 0x 开头
var c = 0b10; // 二进制整数,以 0b 开头
注意:
- 一个八进制数字对应三个二进制数字。
- 一个十六进制数字对应四个二进制数字. (两个十六进制数字就是一个字节)。
\
特殊的数字值
- Infinity: 无穷大, 大于任何数字. 表示数字已经超过了 JS 能表示的范围.
- -Infinity: 负无穷大, 小于任何数字. 表示数字已经超过了 JS 能表示的范围.
- NaN: 表示当前的结果不是一个数字.
var max = Number.MAX_VALUE;
// 得到 Infinity
console.log(max * 2);
// 得到 -Infinity
console.log(-max * 2);
// 得到 NaN
console.log('hello' - 10);
注意:
- 负无穷大 和 无穷小 不是一回事. 无穷小指无限趋近与 0, 值为
1 / Infinity - 'hehe' + 10 得到的不是 NaN, 而是 'hehe10', 会把数字隐式转成字符串, 再进行字符串拼接.
- 可以使用 isNaN 函数判定是不是一个非数字.
console.log(isNaN(10));
console.log(isNaN('hello'-10));
\
string 字符串类型
var a = "hello";
var b = 'hello';
var c = hello; // 运行出错
var msg = "My name is "zhangsan""; // 出错
var msg = "My name is "zhangsan""; // 正确, 使用转义字符. " 来表示字符串内部的引号.
var msg = "My name is 'zhangsan'"; // 正确, 搭配使用单双引号
var msg = 'My name is "zhangsan"'; // 正确, 搭配使用单双引号
\
求长度
使用 string 的 length 属性即可:
var a = 'hello';
console.log(a.length);
var b = '啊啊';
console.log(b.length);
结果如下:
单位为 字符 的数量。
字符串拼接
使用 + 进行拼接:
var a = "my name is ";
var b = "zhangsan";
console.log(a + b); // my name is zhangsan
注意, 数字和字符串也可以进行拼接:
var c = "my score is ";
var d = 100;
console.log(c + d); // my score is 100
注意, 要认准相加的变量到底是字符串还是数字:
console.log(100 + 100); // 200
console.log('100' + 100); // 100100
boolean 布尔类型
Boolean 参与运算时当做 1 和 0 来看待:
console.log(true + 1); // 2
console.log(false + 1); // 1
这样的操作其实是不科学的. 实际开发中不应该这么写.
undefined 未定义数据类型
如果一个变量没有被初始化过, 结果就是 undefined, 是 undefined 类型:
var a;
console.log(a);
undefined 和字符串进行相加, 结果进行字符串拼接:
console.log(a + "10"); // undefined10
undefined 和数字进行相加, 结果为 NaN:
console.log(a + 10);
\
null 空值类型
null 表示当前的变量是一个 "空值".
var b = null;
console.log(b + 10); // 10
console.log(b + "10"); // null10
注意:
null 和 undefined 都表示取值非法的情况, 但是侧重点不同.
null 表示当前的值为空. (相当于有一个空的盒子)
undefined 表示当前的变量未定义. (相当于连盒子都没有)
\
运算符
JavaScript 中的运算符和 Java 用法基本相同. 此处不做详细介绍了。
注意:
- 比较运算符:
==比较相等,会进行隐式类型转换===比较相等,不会进行隐式类型转换
var a = 10;
var b = '10'
console.log(a == b);
console.log(a === b);
||运算符:
JS 中的逻辑或 和 Java 差别很大。
java || 运算返回的一定式 boolean 值
JS 的或运算,a || b
- 若 a 为 true,整个表达式的值就为 a 的值。
- 若 b 为 true,整个表达式的值就为 b 的值。
// 若 b 值为非空,就把 a 设为 b
// 若 b 值为空(null/undefined),就把 a 设为 0
let a = b || 0;
\
\
数组
创建数组
Java / C 中,要求数组中的变量是相同类型的!
但是 JS 中不要求(其他动态类型语言都不要求)。
有两种创建数组的方式:
- 通过
new关键字来创建,数组在 JS 中也就是一个 “对象”。
var arr = new Array();
- 实际开发中,更常用的是,通过 字面量 的方式来创建。
let arr = [];
//也可以在创建数组的时候,填入内容
let arr2 = [1,2,'hello',true,undefined];
// 查看数组
console.log(arr);
console.log(arr2);
获取数组元素
使用下标的方式访问数组元素(从 0 开始):
var arr = ['艾希','诺克萨斯','盖伦'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '塞拉斯';
console.log(arr);
console.log(arr[2]);
注意:
- 如果尝试 读取 数组中不存在的下标,就会出现 undefined 的结果:
var arr = ['艾希','诺克萨斯','盖伦'];
console.log(arr[3]);
- 如果尝试 写入 数组中不存在的下标,就会往这个下标插入元素,同时可能就会修改数组的长度,但是中间元素的值,相当于没有定义,仍然是 undefined的:
var arr = ['艾希','诺克萨斯','盖伦'];
arr[5] = '劫';
console.log(arr);
console.log(arr[3]); // 同时如果读取元素不存在的下标,还是会 undefined
- JS 可以给数组指定一个 字符串 类型的 “下标” 。此处的 “下标” 更应该理解成是 “属性” ,也就相当于 “键值对”:
let arr = [];
arr['hello'] = 'world'; // 跟 arr.hello = 'world' 等价
console.log(arr);
console.log(arr['hello']);
console.log(arr.hello);
对于上例,本质上是在创建一个 hello 属性,类似的,也可以通过 [] 或者 . 的方式都能访问属性!!
注意: 不要给数组名直接赋值,此时数组中的所有元素就都没了。
相当于本来 arr 是一个数组,重新赋值后变成字符串了。
var arr = ['盖伦','艾希','光辉'];
arr = '小丑';
\
新增数组元素
- 通过修改 length 新增:
相当于在末尾新增元素. 新增的元素默认值为 undefined
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
- 通过下标新增
如果下标超出范围赋值元素, 则会给指定位置插入新元素
var arr = [];
arr[2] = 10;
console.log(arr);
此时这个数组的 [0] 和 [1] 都是 undefined
- 使用 push 进行追加元素(常用)
代码示例: 给定一个数组,把数组中的奇数放到一个 newArr 中。
var arr = [1,2,3,4,5,6,7,8,9];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0) {
newArr.push(arr[i]);
}
}
console.log(newArr);
\
删除数组中的元素
使用 splice 方法删除元素:
var arr = [1,2,3,4,5,6];
// 第一个参数表示从下标为 2 的位置开始删除,
// 第二个参数表示要删除的元素个数为 3 个。
arr.splice(2,3);
console.log(arr);
\
\
4.4 函数
语法格式
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
\
- 函数定义并不会执行函数体内容, 必须要调用才会执行. 调用几次就会执行几次.
function hello() {
console.log("hello world!!");
}
// 如果不调用函数,则没有执行打印语句
hello();
\
- 调用函数的时候进入函数内部执行, 函数结束时回到调用位置继续执行. 可以借助调试器来观察.
- 函数的定义和调用的先后顺序没有要求. (这一点和变量不同, 变量必须先定义再使用)
// 调用函数
hello();
// 定义函数
function hello() {
console.log("hello");
}
\
参数个数
实参和形参之间的个数可以不匹配. 但是实际开发一般要求形参和实参个数要匹配
- 如果实参个数比形参个数多,则多出的参数不参与函数运算:
function add(a,b) {
return a+b;
}
console.log(add(10,20,30,40));
- 如果实参个数比形参个数少, 则此时多出来的形参值为 undefined:
function add(a,b) {
return a+b;
}
console.log(add(10));
\
函数表达式
var add = function() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add(10,20)); //30
console.log(add(1,2,3,4)); //10
console.log(typeof add); // function
此时形如 function() { } 这样的写法定义了一个匿名函数, 然后将这个匿名函数用一个变量来表示. 后面就可以通过这个 add 变量来调用函数了.
作用域链
背景:
- 函数可以定义在函数内部
- 内层函数可以访问外层函数的局部变量.
内部函数可以访问外部函数的变量. 采取的是链式查找的方式. 从内到外依次进行查找.
var num = 1;
function test1() {
var num = 10;
function test2() {
var num = 20;
console.log(num);
}
test2();
}
test1();
\
4.5 对象
- 使用 字面量 创建对象(常用)
使用 { } 创建对象
var a = {}; // 创建了一个空的对象
var student = {
name: '蔡徐坤',
height: 175,
weight: 170,
sayHello: function() {
console.log("hello");
}
};
- 使用 { } 创建对象
- 属性和方法使用键值对的形式来组织.
- 键值对之间使用 , 分割. 最后一个属性后面的 , 可有可无
- 键和值之间使用 : 分割.
- 方法的值是一个匿名函数.
使用对象的属性和方法:
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
\
- 使用
new Object创建对象
var student = new Object(); // 和创建数组类似
student.name = "蔡徐坤";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {
console.log("hello");
}
console.log(student.name);
console.log(student['weight']);
student.sayHello();
注意, 使用 { } 创建的对象也可以随时使用 student.name = "蔡徐坤"; 这样的方式来新增属性
- 使用 构造函数 创建对象
前面的创建对象方式只能创建一个对象. 而使用构造函数可以很方便 的创建 多个对象.
例如: 创建几个猫咪对象:
function Cat(name, type, sound) {
this.name = name;
this.type = type;
this.miao = function () {
console.log(sound); // 别忘了作用域的链式访问规则
}
}
var mimi = new Cat('咪咪', '中华田园喵', '喵');
var xiaohei = new Cat('小黑', '波斯喵', '猫呜');
var ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
console.log(mimi);
mimi.miao();
\
五、JS 的 DOM API
5.1 DOM
DOM =》Document 0bject Model - 文档对象模型
一个页面的结构是一个树形结构,称为 DOM 树。
DOM 树结构形如:
重要概念:
文档: 一个页面就是一个 文档, 使用 document 表示.
元素: 页面中所有的标签都称为 元素. 使用 element 表示.
节点: 网页中所有的内容都可以称为 节点(标签节点, 注释节点, 文本节点, 属性节点等). 使用 node表示.
这些文档等概念在 JS 代码中就对应一个个的对象.
所以才叫 “文档对象模型”
\
5.2 DOM API:获取元素
一个 DOM 树上有很多对象,到底要操作谁呢?
先选中这个对象!然后再操作对象!
DOM API 在提供了很多能够用来选中对象/元素的函数,此处介绍功能比较强大的两个API:
querySelectorquerySelectorAll
补充:关于 document
document就表示 “文档”,是每个页面都自带的一个默认的对象,这个相当于是一个 “全局变量”,可以在代码的任意位置来访问到 document。
querySelect
var element = document.querySelector(selectors);
querySelector的参数是一个 “字符串”,这个字符串是一个 CSS 选择器。如果不是一个选择器,则引发SYNTAX_ERR异常。querySelector会返回多个被选中元素中的第一个出现的元素。querySelectorAll就会把选中的多个元素以类似数组的形式,全都返回回来。
注意:
- 如果要是在 document 上调用这两个方法,相当于从这个页面的全局来查找符合要求的元素。
- 如果是在某个具体的 DOM 对象上调用这两个方法,相当于从这个元素里面来查找符合要求的元素。
\
举例1:使用单个选择器
<body>
<!-- 这就是一个 DOM 对象 -->
<div class="one">
hello
</div>
<div id="two">
hello world!!!
</div>
<script>
// 使用 document.querySelector('CSS选择器')来获取元素
let div = document.querySelector('.one');
console.log(div);
let id = document.querySelector('#two');
console.log(id);
</script>
</body>
运行结果:
举例2:使用复合选择器
<body>
<ul>
<li>
aaa
</li>
</ul>
<script>
let obj = document.querySelector('ul li');
console.log(obj);
</script>
</body>
运行结果:
如果上述代码中,无序列表中的列表项不止一个会怎么样?
<body>
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<script>
let obj = document.querySelector('ul li');
console.log(obj);
</script>
</body>
运行结果“
通过 querySelector来选择第一个元素。
querySelectorAll
<body>
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
</ul>
<script>
let obj = document.querySelectorAll('ul li');
console.log(obj);
</script>
</body>
\
5.3 事件初识
基本概念
JS 要构建动态页面, 就需要感知到用户的行为.
用户对于页面的一些操作(点击, 选择, 修改等) 操作都会在浏览器中产生一个个事件, 被 JS 获取到, 从而进
行更复杂的交互操作。
事件三要素
- 事件源: 哪个元素触发的
- 事件类型: 是点击, 选中, 还是修改?
- 事件处理程序: 进一步如何处理. 往往是一个回调函数.
举例:点击事件
<body>
<button>这是个按钮</button>
<script>
// 将获取到的对象 赋予 button
let button = document.querySelector('button');
// 通过 .onclick ,给 button 添加点击事件
// 事件源:button 对象/标签
// 事件类型:鼠标点击事件
// 事件处理程序:匿名函数里面执行:弹出一个对话框,显示 ”hello“
button.onclick = function() {
alert("hello");
}
</script>
</body>
点击按钮之后,就会弹出对话框:
- button 按钮就是事件源。
- 点击就是事件类型
- function 这个匿名函数就是事件处理程序。
- 其中
button.onclick = function() {}这个操作称为 注册事件/绑定事件 。
注意:这个匿名函数相当于一个回调函数,这个函数不需要程序员主动来调用,而是交给浏览器,由浏览器自动在合适的时机(触发点击操作时)进行调用。
5.4 操作元素
通过 .innerHTML
获取/修改元素内容
<body>
<div id="screen">hello</div>
<button id="button">这是一个按钮</button>
<script>
let button = document.querySelector('#button');
button.onclick = function() {
let screen = document.querySelector('#screen');
console.log(screen.innerHTML);
}
</script>
</body>
还未点击按钮的状态:
点击按钮之后,得到了 <div id="screen">对象里面的内容:
我们还可以修改元素的内容,比如下面,我们将 按钮 改成 一个文本框
<body>
<div id="screen">hello</div>
<button id="button">这是一个按钮</button>
<script>
let button = document.querySelector('#button');
// 读取页面内容
console.log(button.innerHTML);
// 修改页面内容
button.innerHTML = '<input type="text">';
</script>
</body>
\
\
示例:自制数字自增器:
<!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>手动计数器</title>
</head>
<body>
<div class="parent">
<div class="screen">0</div>
<div class="ctrl">
<button id="add">+</button>
<button id="minus">-</button>
</div>
</div>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.parent {
width: 500px;
height: 300px;
background-color:bisque;
margin: 0 auto;
}
.parent .screen {
width: 200px;
height: 150px;
font-size: 50px;
line-height: 150px;
color:purple;
margin: 0 auto;
text-align: center;
}
.parent .ctrl {
width: 300px;
height: 150px;
margin: 0 auto;
display: flex;
justify-content: space-between;
align-items: center;
}
.parent .ctrl button {
width: 100px;
height: 50px;
font-size: 20px;
line-height: 20px;
text-align: center;
background-color:cadetblue;
border-radius: 10px;
border: none;
}
.parent .ctrl button:active {
color:aliceblue;
background-color: black;
}
</style>
<script>
let addButton = document.querySelector('#add');
addButton.onclick = function() {
//1.选中 screen 元素
let screen = document.querySelector('.screen');
//2.取出其中的内容
let content = screen.innerHTML;
//3.把内容+1
let result = parseInt(content)+1;
//4.把内容写回
screen.innerHTML = result;
}
let minusButton = document.querySelector('#minus');
minusButton.onclick = function() {
//1.选中 screen 元素
let screen = document.querySelector('.screen');
//2.取出其中的内容
let content = screen.innerHTML;
//3.把内容-1
let result = parseInt(content)-1;
//4.把内容写回
screen.innerHTML = result;
}
</script>
</body>
</html>
获取/修改元素属性
可以通过 Element 对象的属性来直接修改, 就能影响到页面显示效果:
<body>
<img src="img/2.jpg" alt="这是一座山河">
<script>
let img = document.querySelector('img');
console.dir(img);
</script>
</body>
通过 console.dir() 可以看到元素很多的属性(此处只截取了一部分):
我们可以在代码中直接通过这些属性来获取属性的值:
<body>
<img src="img/2.jpg" alt="这是一座山河">
<script>
let img = document.querySelector('img');
console.log(img.src);
console.log(img.alt);
</script>
</body>
\
还可以直接修改属性:
通过点击图片,进行图片的切换
<body>
<img src="img/2.jpg" alt="这是一座山河">
<script>
let img = document.querySelector('img');
img.onclick = function() {
if (img.src.lastIndexOf('2.jpg') !== -1) {
img.src = 'img/1.jpg';
} else {
img.src = 'img/2.jpg';
}
}
</script>
</body>
未点击图片:
点击图片之后:
\
获取/修改表单元素属性
表单(主要是指 input 标签)的以下属性都可以通过 DOM 来修改
- value: input 的值.
- disabled: 禁用
- checked: 复选框会使用
- selected: 下拉框会使用
- type: input 的类型(文本, 密码, 按钮, 文件等)
代码示例: 切换按钮
一开始是个播放按钮,在 “播放” 和 “暂停” 之间切换
<body>
<input type="button" value="播放">
<script>
let button = document.querySelector('input');
button.onclick = function() {
if (button.value == '播放') {
button.value = '暂停';
} else {
button.value = '播放';
}
}
</script>
</body>
\
获取/修改样式属性
CSS 中指定给元素的属性, 都可以通过 JS 来修改.
行内样式操作
element.style.[属性名] = [属性值]; // 一般使用这种
element.style.cssText = [属性名+属性值];
"行内样式", 通过 style 直接在标签上指定的样式. 优先级很高. 适用于改的样式少的情况
代码示例: 点击文字则放大字体
注意:
script 中的属性都是使用 驼峰命名 的方式和 CSS 属性对应的.
例如: font-size => fontSize, background-color => backgroundColor 等
这种方式修改只影响到特定样式, 其他内联样式的值不变.
<body>
<div style="font-size: 10px;">越来越帅了</div>
<script>
let fontSize = document.querySelector('div');
fontSize.onclick = function() {
let size = parseInt(fontSize.style.fontSize) + 10;
fontSize.style.fontSize = size + 'px';
}
</script>
</body>
,此处第一行 parseInt 之后,去掉了 style 中属性 font-size 的单位 px,因此需要在 第二行 把 单位 px 加回来。
运行结果:
类名样式操作
element.className = [CSS 类名];
修改元素的 CSS 类名. 适用于要修改的样式很多的情况.
由于 class 是 JS 的保留字, 所以名字叫做 className
\
代码示例: 开启夜间模式
<body>
<div class="container light">
这是一段话 <br>
这是一段话 <br>
这是一段话 <br>
这是一段话 <br>
</div>
<style>
* {
margin: 0;
padding: 0;
}
html,body {
width: 100%;
height: 100%;
}
.container {
width: 100%;
height: 100%;
}
.light {
background-color: #f3f3f3;
columns: #333;
}
.dark {
background-color: #333;
color: #f3f3f3;
}
</style>
<script>
let container = document.querySelector('div');
container.onclick = function() {
console.log(container.className);
if (container.className.indexOf('light') != -1) {
container.className = 'container dark';
} else {
container.className = 'container light';
}
}
</script>
</body>
点击页面,实现日夜间的切换:
\
\
5.5 操作节点
新增节点
分成两个步骤
- 创建元素节点
- 把元素节点插入到 dom 树中.
第一步相当于生了个娃, 第二步相当于给娃上户口
1. 创建元素节点
使用 createElement 方法来创建一个元素. options 参数暂不关注.
var element = document.createElement(tagName[, options]);
代码示例:
<body>
<div class="container"></div>
<script>
let div = document.createElement('div');
div.id = 'mydiv';
div.className = 'box';
div.innerHTML = 'hello!';
console.log(div);
</script>
</body>
此时发现, 虽然创建出新的 div 了, 但是 div 并没有显示在页面上. 这是因为新创建的节点并没有加入到 DOM 树中.
上面介绍的只是创建元素节点, 还可以使用:
- createTextNode 创建文本节点
- createComment 创建注释节点
- createAttribute 创建属性节点
我们以 createElement 为主即可.
\
2. 插入节点到 DOM 树中
这里有两种不同的方法来插入节点:
- 使用
appendChild将节点插入到指定节点的 最后一个孩子之后
element.appendChild(aChild)
代码示例:
<body>
<div class="container"></div>
<script>
let div = document.createElement('div');
div.id = 'mydiv';
div.className = 'box';
div.innerHTML = 'hello!';
let container = document.querySelector('.container');
container.appendChild(div);
</script>
</body>
\
- 使用
insertBefore将节点插入到 指定节点之前 :
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
insertedNode被插入节点 (newNode)parentNode新插入节点的父节点newNode用于插入的节点referenceNodenewNode将要插在这个节点之前
如果 referenceNode 为 null 则 newNode 将被插入到子节点的末尾.
注意: referenceNode 引用节点不是可选参数
\
代码示例:
<body>
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
let newDiv = document.createElement('div');
newDiv.innerHTML = '这是一个新的节点';
let container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv,container.children[0]);
</script>
</body>
注意1:如果针对一个节点插入两次, 则只有最后一次生效(相当于把元素移动了)
<body>
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
let newDiv = document.createElement('div');
newDiv.innerHTML = '这是一个新的节点';
let container = document.querySelector('.container');
console.log(container.children);
// 此时插入后元素为:
//此处为坐标: 0 1 2 3 4
// 这是一个新的节点 11 22 33 44
container.insertBefore(newDiv,container.children[0]);
// 此时插入后元素为:
//此处为坐标: 0 1 2 3 4
// 11 这是一个新的节点 22 33 44
container.insertBefore(newDiv,container.children[2]);
</script>
</body>
\
注意2: 一旦一个节点插入完毕, 再针对刚刚的节点对象进行修改, 能够同步影响到 DOM 树中的内容.
<body>
<div class="container">
<div>11</div>
<div>22</div>
<div>33</div>
<div>44</div>
</div>
<script>
let newDiv = document.createElement('div');
newDiv.innerHTML = '这是一个新的节点';
let container = document.querySelector('.container');
console.log(container.children);
container.insertBefore(newDiv,container.children[0]);
// 插入完毕后再次修改 newDiv 的内容
newDiv.innerHTML = '这是新节点2号';
</script>
</body>
\
删除节点
使用 removeChild 删除子节点
oldChild = element.removeChild(child);
child为待删除节点element为 child 的父节点- 返回值为该被删除节点
- 被删除节点只是从 dom 树被删除了, 但是仍然在内存中, 可以随时加入到 dom 树的其他位置.
- 如果上例中的child节点不是element 节点的子节点,则该方法会抛出异常
\
代码示例:
<body>
<!-- 创建一个空的 div -->
<div class="container"></div>
<button>此处是删除 div 的按钮</button>
<script>
// 首先创建一个 节点
let newDiv = document.createElement('div');
newDiv.className = 'newDiv';
newDiv.innerHTML = "hello world!!";
// 将 newDiv 打印在控制台上
console.log(newDiv);
// 将 新节点 挂到 DOM 树上
let container = document.querySelector('.container');
container.appendChild(newDiv);
// 让 按钮 实现删除功能
let button = document.querySelector('button');
button.onclick = function() {
// 删除节点
container.removeChild(newDiv);
}
</script>
</body>
未点击按钮之前,此时 新节点是挂在 DOM 树中的子节点上:
点击删除按钮之后,发现之前新创建的节点已经不在 DOM 树上了,即为删除了: