JavaScript(黑马程序员)——第一篇
目录
- 一、JS基础语法
-
- 1、JS书写位置
- 2、JS注释
- 3、JS结束符
- 4、JS输入输出语法
- 5、JS变量和常量
- 6、JS数据类型
- 7、JS运算符
- 8、JS语句
- 9、JS函数
- 10、JS术语
- 11、DOM
一、JS基础语法
1、JS书写位置
1.1、行内
1.1.1、概念
- 含义:在html标签属性中编写的js代码,即为行内写法
1.1.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- js行内写法,用于阻止a标签的默认跳转行为 -->
<a href="javascript:void(0)">点击我,不跳转</a>
</body>
</html>
1.1.3、页面效果

1.2、内部
1.2.1、概念
- 含义:js代码写在html文件内部
- 书写位置:必须放在body标签中最后的位置,避免标签未加载时js代码已经执行。
1.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- js代码写在html文件内容 -->
<script>
alert("hello, world~")
</script>
</body>
</html>
1.2.3、页面效果

1.3、外部
1.3.1、概念
- 含义:单独编写js文件,然后使用
script标签引入html文件之中
1.3.2、代码示例
helloworld.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>
</head>
<body>
<!-- 引入外部js文件 -->
<script src="./helloworld.js"></script>
</body>
</html>
helloworld.js:
alert('hello, world~')
1.3.3、页面效果

2、JS注释
2.1、概念
- 划分:
- 单行注释://
- 多行注释:/* */
2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 引入外部js文件 -->
<script>
// 1、单行注释
/*
2、多行注释
*/
</script>
</body>
</html>
3、JS结束符
- 作用:使用英文的分号,代表语句结束
- 必须要写:否,可以写也可不写,浏览器(Javascript引擎)会自动推断语句的结束位置
- 约定:为了团队编程风格统一,结束符要么都写,要么都不写,需要按照团队要求来
- 特殊情况:如果有多个连续的立即执行-匿名函数
(function(){})(),那就必须使用分号分隔
4、JS输入输出语法
- 输入:
- 在页面弹出弹框,让用户输入内容:
let name = prompt("请输入您的名字:")
- 在页面弹出弹框,让用户输入内容:
- 输出:
- 在控制台输出内容:
console.log("hello world~") - 使用弹窗形式输出内容:
alert("hello world~") - 在Dom文档中输出内容,当输出html标签时,页面还会自动渲染html标签:
document.write("hello world~")
- 在控制台输出内容:
5、JS变量和常量
5.1、变量
5.1.1、声明、赋值、更新变量
- 语法:
let 变量名(只声明,不赋值)、let 变量名 = 变量值(声明 + 赋值)、let 变量名1 = 变量值1, 变量名2 = 变量值2(多个变量同时声明 + 赋值) - 声明变量:
let name。如果没有直接赋值,此时name是undefined - 变量赋值:
name = "明快de玄米61" - 声明变量 + 赋值:
let name = "明快de玄米61" - 更新变量:
name = "明天会更好~" - 其他操作:
- 一次定义多个变量:
let name = "明快de玄米61", age = 18
- 一次定义多个变量:
5.1.2、命名规则和规范
- 规则(必须遵守,不遵守就出错):
- 只能使用数字、字母、下划线、
$符,并且不能以数字开头 - 不能使用关键字。即JS内置的一些英文词汇,例如left、var、if、for、while、switch、case、break、continue等
- 变量名称中的字母严格区分大小写,例如age和Age是不同的变量
- 只能使用数字、字母、下划线、
- 规范(建议遵守,不遵守也不会报错)
- 变量命名需要见名知意
- 变量命名遵守小驼峰命名法(第一个首字母小写,后面每一个首字母大写,例如:userName)
5.1.3、let和var的区别
- 我们使用谁:使用let,不使用var
- 使用var的缺点:
- 可以先使用,然后在声明

- 可以重复声明

- 可以先使用,然后在声明
5.2、常量
- 语法:
const 常量名 = 常量值 - 命名:基本和常量一致,不过一般采用字母全大写方式,单词中间使用
下划线_分隔 - 声明、赋值、更新:声明的时候必须赋值,不能进行更新,写法:
const PI = 3.14 - let和const用哪个?如果一个数据的值以后不会改变,那就使用const,所以优先使用const。其中数组或者对象优先使用const来声明
6、JS数据类型
6.1、分类
- 基本数据类型:
- 数字型(number)
- 字符串型(string)
- 布尔型(boolean)
- 未定义型(undefined)
- 引用数据类型(统一为object类型):
- 数组
- 对象
6.2、基本数据类型
6.2.1、数字类型(Number)
-
含义:即我们数学中学习到的数字,可以是整数、小数,无论正负都可以
-
NaN:
- 当计算错误或者出现一个未定义的数学操作,将返回NaN。例如:
console.log('老师' - 2) - 任何针对NaN的操作都会返回NaN。例如:
console.log(NaN - 2)
- 当计算错误或者出现一个未定义的数学操作,将返回NaN。例如:
-
常见的属性和方法(以下属性和方法其实是字符串的包装类Number对象的)
-
实例方法
toFixed()可以用于设置小数位数const num = 12.345 // 保留两位小数,遵循四舍五入原则 console.log(num.toFixed(2)) // 12.35
-
6.2.2、字符串类型(String)
6.2.2.1、概念
-
含义:使用单引号(
')、双引号(")、反引号(`)包裹起来的都是字符串。- 单引号和双引号没有本质上的区别,推荐使用单引号
- 反引号(`)里面可以写模板字符串,其中模板字符串可以使用变量,也支持表达式计算,也可以结合document.write(XXX)将html代码写到body标签中
-
使用注意事项:
- 无论单引号或者双引号,必须成对使用
- 单引号/双引号可以相互嵌套,但是不能自己嵌套自己(不支持
console.log('我的名字是'明快de玄米61''))。支持外单内双(console.log('我的名字是"明快de玄米61"')),或者外双内单console.log("我的名字是'明快de玄米61'") - 在必要的时候,可以使用转义符\,用于输出单引号或者双引号,例如:
console.log('我的名字是\'明快de玄米61\'')或者console.log("我的名字是\"明快de玄米61\"")
-
字符串和数字的区别:如果使用
console.log(XXX),其中字符串是黑色字,数字是蓝色字
-
常见的属性和方法(以下属性和方法其实是字符串的包装类String对象的)
-
实例属性
length可以获取字符串的长度(重点)const str = 'hello world' console.log(str.length) // 11 -
实例方法
split('分隔符')可以用来将字符串拆分成数组(重点)const str = "The quick brown fox jumps over the lazy dog."; const words = str.split(" "); console.log(words[3]); // "fox" const chars = str.split(""); console.log(chars[8]); // "k" const strCopy = str.split(); console.log(strCopy); // ["The quick brown fox jumps over the lazy dog."] -
实例方法
substring()返回该字符串从起始索引到结束索引(不包括)的部分,如果未提供结束索引,则返回到字符串末尾的部分。其作用等价于slice(start, end),但是slice功能更加强大,所以推荐使用(重点)const str = "Mozilla"; console.log(str.substring(1, 3)); // "oz" console.log(str.substring(2)); // "zilla" -
实例方法
startsWith()用来判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 true 或 false。const str1 = "Saturday night plans"; console.log(str1.startsWith("Sat")); // true console.log(str1.startsWith("Sat", 3)); // false -
实例方法
includes()执行区分大小写的搜索,以确定是否可以在一个字符串中找到另一个字符串,并根据情况返回 true 或 false。const sentence = "The quick brown fox jumps over the lazy dog."; const word = "fox"; console.log(sentence.includes(word)); // true -
实例方法
toUpperCase()将该字符串转换为大写形式。const sentence = "The quick brown fox jumps over the lazy dog."; console.log(sentence.toUpperCase()); // THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG. -
实例方法
toLowerCase()将该字符串转换为小写形式。const sentence = "The quick brown fox jumps over the lazy dog."; console.log(sentence.toLowerCase()); // the quick brown fox jumps over the lazy dog. -
实例方法
indexOf()在字符串中搜索指定子字符串,并返回其第一次出现的位置索引。它可以接受一个可选的参数指定搜索的起始位置,如果找到了指定的子字符串,则返回的位置索引大于或等于指定的数字。如果没有找到,则返回 -1。const paragraph = "I think Ruth's dog is cuter than your dog!"; const searchTerm = "dog"; console.log(paragraph.indexOf(searchTerm)) // 15 -
实例方法
startsWith()用来判断当前字符串是否以另外一个给定的子字符串开头,并根据判断结果返回 true 或 false。const str1 = "Saturday night plans"; console.log(str1.startsWith("Sat")); // true -
实例方法
endsWith()用于判断一个字符串是否以指定字符串结尾,如果是则返回 true,否则返回 false。const str1 = "Cats are the best!"; console.log(str1.endsWith("best!")); // true -
实例方法
replace(pattern, replacement)返回一个新字符串,其中一个、多个或所有匹配的 pattern 被替换为 replacement。pattern 可以是字符串或 正则表达式,replacement 可以是字符串或一个在每次匹配时调用的函数。如果 pattern 是字符串,则只会替换第1个匹配项。字符串模式只会被替换一次。要执行全局搜索和替换,请使用带有 g 标志的正则表达式或使用replaceAll()。const paragraph = "I think Ruth's dog is cuter than your dog!"; console.log(paragraph.replace("Ruth's", "my")); // I think my dog is cuter than your dog! const regex1 = /Dog/i; console.log(paragraph.replace(regex1, "ferret")); // I think Ruth's ferret is cuter than your dog! const regex2 = /Dog/ig; console.log(paragraph.replace(regex2, "ferret")); // I think Ruth's ferret is cuter than your ferret! -
实例方法
replaceAll(pattern, replacement)方法返回一个新字符串,其中所有匹配 pattern 的部分都被替换为 replacement。pattern 可以是一个字符串或一个 正则表达式(注意:正则表达式必须使用g全局搜索),replacement 可以是一个字符串或一个在每次匹配时调用的函数。const paragraph = "I think Ruth's dog is cuter than your dog!"; console.log(paragraph.replaceAll("dog", "monkey")); // I think Ruth's monkey is cuter than your monkey! // 正则表达式必须使用g全局搜索 const regex = /Dog/ig; console.log(paragraph.replaceAll(regex, "ferret")); // I think Ruth's ferret is cuter than your ferret! -
实例方法
match(regexp)检索字符串与正则表达式进行匹配的结果。如果没有匹配,则返回 null。- 如果使用 g 标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组。
- 如果没有使用 g 标志,则只返回第一个完整匹配及其相关捕获组。
const paragraph = "The quick brown fox jumps over the lazy dog. It barked."; const regex = /[A-Z]/g; const found = paragraph.match(regex); console.log(found); // ["T", "I"]
-
6.2.2.2、模板字符串
概念: 支持在字符串中使用变量,并且支持进行表达式计算
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 1、使用变量
let name = '明快de玄米61'
console.log(`我的名字是${name}`)
// 2、使用计算表达式
let age = 18
console.log(`我明年的年纪是${age + 1}`)
// 3、打印html标签
document.write(`
<h3>${name}</h3>
<p>年龄:${age}</p>
`)
</script>
</body>
</html>
页面示例:

6.2.3、布尔值类型(Boolean)
- 含义:true代表真,false代表假
6.2.4、未定义类型(undefined)
6.2.4.1、概念
- 含义:未定义是比较特殊的类型,只有一个值undefined。
- 什么情况下会出现未定义类型:只声明变量,但是没有赋值,那么变量的默认值是
undefined,但是很少直接为某个变量undefined - 工作中的使用场景:我们开发中经常声明一个变量,等待数据传送过来,如果我们不知道这个数据是否传递过来,可以检测这个变量是不是undefined,就可以进行判断
6.2.4.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let a
console.log(`a = ${a}`)
let b = undefined
console.log(`b = ${b}`)
let f = function(c) {
console.log(`c = ${c}`)
}
f()
</script>
</body>
</html>
6.2.4.3、页面效果

6.3、引用数据类型
6.3.1、数组(Array)
6.3.1.1、概念
-
含义:将一组数据存储到单个变量名中的方式
-
写法:
let 变量名 = [值1, 值2……],如果不写值let 变量名 = []就是空数组。例如:let arr = [](空数组)、let arr = [1, '中国', true](有值数组,支持多个不同类型的数据) -
另外一种写法(了解即可):
let 变量名 = new Array(值1, 值2……),例如:let arr = new Array(1, '中国', true) -
获取数组长度:
数组变量名.length,例如:arr.length -
从数组中取值:
数组变量名[数组下标],其中数组下标从0开始,例如:arr[0] -
更新数组值:
数组变量名[数组下标] = 新值,例如:arr[0] = 2 -
新增数组值:
- 在数组尾部新增值:示例
arr.push(100, 'hello world') - 在数组头部新增值:示例
arr.unshift(20, 'my world')
- 在数组尾部新增值:示例
-
删除数组值:
- 在数组尾部删除值:示例
arr.pop() - 在数组头部删除值:示例
arr.shift()
- 在数组尾部删除值:示例
-
支持新增、删除、修改功能:
splice()- 语法:
array.splice(start, deleteCount, item1, item2, ...) - 参数说明:
start(必需):开始修改的索引(从 0 开始)。- 若为负数,则从数组末尾开始计数(例如 -1 表示最后一个元素)。
- 若绝对值超过数组长度,则根据正负决定起始位置(正数超长则从末尾追加,负数则从 0 开始)。
deleteCount(可选):要删除的元素个数。- 如果省略,则从 start 一直删除到数组末尾。
- 如果为 0 或负数,则不删除任何元素。
item1, item2, ...(可选):要插入到数组的新元素,从start位置开始依次插入。
- 返回值:
- 返回一个由被删除元素组成的新数组。如果没有删除元素,则返回空数组。
- 特点:
splice()会直接修改原数组。
- 补充说明:
- 如果
start超出数组长度,且deleteCount为 0,插入操作会在数组末尾进行。 - 如果
deleteCount大于start到末尾的实际元素个数,则删除到末尾为止。 - 负索引同样有效,例如
arr.splice(-2, 1)表示从倒数第二个元素开始删除 1 个。
- 如果
- 三种主要用法的代码示例:
-
- 删除元素(示例:只指定前两个参数,从指定位置开始删除指定数量的元素。)
let arr = ['a', 'b', 'c', 'd']; arr.splice(2, 1); // 从索引 2 开始删除 1 个元素 console.log(arr); // ['a', 'b', 'd'] -
- 插入元素(示例:将
deleteCount设为 0,然后传入要插入的元素。)
let arr = ['a', 'b', 'c']; arr.splice(1, 0, 'x', 'y'); // 在索引 1 处插入 'x', 'y' console.log(arr); // ['a', 'x', 'y', 'b', 'c'] - 插入元素(示例:将
-
- 替换元素(示例:先删除指定数量的元素,再在相同位置插入新元素。删除的数量和插入的数量可以不同。)
let arr = ['a', 'b', 'c', 'd']; arr.splice(1, 2, 'x', 'y', 'z'); // 从索引 1 开始删除 2 个元素,再插入 3 个新元素 console.log(arr); // ['a', 'x', 'y', 'z', 'd']
-
- 语法:
-
for循环遍历数组:let result = '' for (let i = 0; i < arr.length; i++) { const element = arr[i]; result += element result += ',' } console.log(`遍历数组:${result}`) -
forEach()遍历数组(参数index可以省略):const foodArr = ['牛肉', '土豆', '玉米'] foodArr.forEach(function(element, index) { console.log(element, index) }) -
使用
join()方法借助特定字符串,然后将数组元素连接起来,最终返回连接后的字符串:// 原材料 const oldArr = ['牛肉', '土豆', '玉米'] // 中间不分隔 console.log(oldArr.join('')) // 中间以分号分隔 console.log(oldArr.join(';')) -
使用
map()方法遍历数组,当处理数据后,返回新的数组(参数index可以省略):// 原材料 const oldArr = ['牛肉', '土豆', '玉米'] // 处理结果 const newArr = oldArr.map(function(element, index) { // 模拟数据处理的过程 if(element === '牛肉') { return '汉堡包' } else if(element === '土豆') { return '薯条' } else if(element === '玉米') { return '爆米花' } return '' }) console.log(newArr) // ['汉堡包', '薯条', '爆米花'] -
使用
filter()方法过滤数组元素,当处理数据后,返回符合条件的新数组(参数index可以省略):// 原材料 const arr = [1, 2, 3, 4, 5, 6] // 过滤结果 const newArr = arr.filter((element, index) => { return element > 3 }) console.log(newArr) // [4, 5, 6] -
使用
reduce()进行数值累加操作// 求和(注意:如果不设置起始值,那么第一次累加时prev=arr[0],current=arr[1]) const arr = [1, 2, 3, 4, 5, 6] const result1 = arr.reduce((prev, current) => { return prev + current; }) console.log(result1) // 21 // 求和(注意:如果设置起始值,那么第一次累加时prev=起始值,current=arr[0]) const result2 = arr.reduce((prev, current) => { return prev + current; }, 10) console.log(result2) // 31 // 加薪 30%,计算总工资(综合案例) const info = [ { name: '张三', salary: 1000 }, { name: '李四', salary: 2000 }, { name: '王五', salary: 3000 } ] const result3 = info.reduce((prev, current) => prev + current.salary * 1.3, 0) // 初始值0是必须存在的,在上面例子中已经说明了作用 console.log(result3) // 7800 -
find()方法返回数组中符合要求的第一个元素的值。否则返回 undefined。const array1 = [5, 12, 8, 130, 44]; const found = array1.find((element) => element > 10); console.log(found); // 12 -
findIndex()方法返回数组中符合要求的第1个元素的索引。若没有找到对应元素则返回 -1。const array1 = [5, 12, 8, 130, 44]; const isLargeNumber = (element) => element > 13; console.log(array1.findIndex(isLargeNumber)); // 3 -
every()方法:如果数组内的所有元素都满足要求,那返回值是true,否则是falseconst array1 = [1, 30, 39, 29, 10, 13]; const isBelowThreshold = (currentValue) => currentValue < 40; console.log(array1.every(isBelowThreshold)); // true -
some()方法:只要数组中有任意一个元素符合要求,那返回值是true,否则是falseconst array = [1, 2, 3, 4, 5]; const even = (element) => element % 2 === 0; console.log(array.some(even)); // true -
concat()方法用于合并两个或多个数组,最终返回一个新数组。const array1 = ["a", "b", "c"]; const array2 = ["d", "e", "f"]; const array3 = array1.concat(array2); console.log(array3); // ["a", "b", "c", "d", "e", "f"] -
sort()方法就地对数组的元素进行排序,并返回对相同数组的引用。如果想要不改变原数组的排序方法,可以使用toSorted()。const months = ["March", "Jan", "Feb", "Dec"]; months.sort(); console.log(months); // ["Dec", "Feb", "Jan", "March"] const array1 = [1, 30, 4, 21, 100000]; array1.sort(); console.log(array1); // [1, 100000, 21, 30, 4] -
reverse()方法就地反转数组中的元素,并返回同一数组的引用。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。换句话说,数组中的元素顺序将被翻转,变为与之前相反的方向。如果要在不改变原始数组的情况下反转数组中的元素,使用toReversed()。const array1 = ["one", "two", "three"]; console.log("array1:", array1); // "array1:" Array ["one", "two", "three"] const reversed = array1.reverse(); console.log("reversed:", reversed); // "reversed:" Array ["three", "two", "one"] // reverse()方法会改变原数组 console.log("array1:", array1); // "array1:" Array ["three", "two", "one"] -
用于判断一个数组是否包含某个指定的值,根据情况返回 true 或 false:
arr.includes(valueToFind[, fromIndex])-
参数:
- valueToFind:需要查找的元素值,其中查找时使用严格相等(===)比较。
- fromIndex(可选):从该索引位置开始查找(默认 0)。若为负数,表示从倒数第 abs(fromIndex) 位开始往后查找。
-
示例:
// 基本用法 const arr = [1, 2, 3, 'a', 'b']; console.log(arr.includes(2)); // true console.log(arr.includes(4)); // false console.log(arr.includes('a')); // true console.log(arr.includes('A')); // false(大小写敏感) // 使用 fromIndex const arr = ['apple', 'banana', 'orange']; console.log(arr.includes('banana', 1)); // true(从索引1开始查) console.log(arr.includes('apple', 1)); // false(从索引1开始查,找不到 apple) console.log(arr.includes('orange', -1)); // true(-1 表示从倒数第1个,即索引2开始) console.log(arr.includes('banana', -2)); // true(-2 表示从倒数第2个,即索引1开始)
-
-
转换成数据类型:
Array.from(liEls)、[...liEls](扩展运算符)- 使用场景:
document.querySelectorAll返回的是NodeList对象,它没有数组的map方法。 - 示例:
// 1、使用Array.from(liEls) function updateTodoList() { const liEls = document.querySelectorAll('.todoList li'); // 修正类名 const todoList = Array.from(liEls).map(element => { // 转换为数组再 map return { content: element.innerText, del: element.classList.contains('del') }; }); localStorage.setItem('todos', JSON.stringify(todoList)); } // 2、使用扩展运算符 const todoList = [...liEls].map(element => ({ ... }));
- 使用场景:
6.3.1.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 定义空数组
let emptyArr = []
console.log(`定义空数组:${emptyArr}`)
// 定义有值数组
let arr = [1, '中国', true]
console.log(`定义有值数组:${arr}`)
// 从数组中取值,数组下标从0开始
console.log(`获取数组下标为0的值:${arr[0]}`)
// 更新数组值
arr[0] = 2
console.log(`更新数组值:${arr}`)
// 在数组尾部新增值
arr.push(100, 'hello world')
console.log(`在数组尾部新增值:${arr}`)
// 在数组头部新增值
arr.unshift(20, 'my world')
console.log(`在数组头部新增值:${arr}`)
// 在数组尾部删除值
arr.pop()
console.log(`在数组尾部删除值:${arr}`)
// 在数组头部删除值
arr.shift()
console.log(`在数组头部删除值:${arr}`)
// 删除数组中特定下标的数组值
// splice()方法一共有2个参数,第2个参数非必填,第1个参数代表数组下标,第二个参数代表数量
// 方法含义:从特定数组下标开始,删除指定数量的元素。如果没有填写第2个参数,那就直接从数组下标删除到最后一个元素
arr.splice(2, 1)
// 遍历数组
let result = ''
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
result += element
result += ','
}
console.log(`遍历数组:${result}`)
</script>
</body>
</html>
6.3.1.3、页面效果

6.3.2、对象(Object)
6.3.2.1、概念
- 含义:支持设置属性和方法
- 写法:
let 变量名 = {属性名: 属性值, 方法: 函数……},如果不写值let 变量名 = {}就是空对象。例如:let obj = {}(空对象)、let obj = {"name":"明快de玄米61","age":18,"isMan":true}(有值对象) - 另外一种写法(了解即可):
let 变量名 = new Object(属性名: 属性值, 方法: 函数……),例如:let obj = new Object("name":"明快de玄米61","age":18,"isMan":true) - 属性名:除非名称中存在特殊符号或者中横线等,一般不使用双引号或者单引号将属性名括起来
- 从对象中取值:
对象变量名.属性名或者对象变量名['属性名'],第1种方式比较常用,第2种方式在使用forin方式遍历对象时会使用到,并且也只能使用方式2 - 调用对象的方法:
对象变量名.方法名()或者对象变量名.方法名(实参列表) - 新增对象值、更新对象值:
对象变量名.属性名 = 新属性值,对于对象来说,有则更新,无则新增 - 删除对象值:
delete 对象变量名.属性名,示例:delete obj.age - 遍历对象:
// 遍历对象 for (const key in obj) { // 在这里不使用obj.key的原因:key是一个字符串,相当于'name',所以不能使用,因此只能使用这种方法 let val = obj[key] console.log(`属性名:${key},属性值:${val}`) } - 特殊类型
null:- 代表无的意思,如果
let a = null,此时a的类型是object - null和undefined的区别:
- null:代表空,啥都没有。例如:
console.log(null + 1)的结果是1,原因是数据类型转换之后null是0 - undefined:代表未定义。例如:
console.log(undefined + 1)的结果是NaN,原因是数据类型转换之后undefined是NaN
- null:代表空,啥都没有。例如:
- 代表无的意思,如果
- 注意事项:字符串、数值、布尔等基本数据类型也有对应的构造函数,例如字符串对应
String,这也被我们也称为包装类型。那就可以解释在部分情况下,我们使用的是基本数据类型,但是依然可以直接调用属性和方法(例如:const str = 'hello'; console.log(str.length)),其实JS底层将基本数据类型自动转换成了包装类型对象,所以我们才能调用包装类型的属性和方法
6.3.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 定义空对象
let emptyObj = {}
console.log(`定义空对象:${JSON.stringify(emptyObj)}`)
// 定义有值对象
let obj = {
name: '明快de玄米61',
age: 18,
isMan: true,
run: function() {
console.log('调用对象run方法')
},
eat: function(food) {
console.log(`调用对象eat方法,传参:${food}`)
}
}
console.log(`定义有值对象${JSON.stringify(obj)}`)
// 从对象中取值
console.log(`从对象中取值-方式1:${obj.name}`)
console.log(`从对象中取值-方式2:${obj['name']}`)
// 调用对象的方法
console.log(`调用对象的方法-不传参-返回值:${obj.run()}`)
console.log(`调用对象的方法-传参-返回值:${obj.eat('汉堡')}`)
// 更新对象值
obj.name = '张三'
console.log(`更新对象值:${obj.name}`)
// 新增对象值
obj.address = '湖北省武汉市'
console.log(`新增对象值:${obj.address}`)
// 删除对象值
delete obj.age
console.log(`删除对象值:${JSON.stringify(obj)}`)
// 遍历对象
console.log('遍历对象:')
for (const key in obj) {
// 在这里不使用obj.key的原因:key是一个字符串,相当于'name',所以不能使用,因此只能使用这种方法
let val = obj[key]
console.log(`属性名:${key},属性值:${val}`)
}
</script>
</body>
</html>
6.3.2.3、页面效果

6.4、类型检测
6.4.1、概念
- 含义:typeof运算符可以返回被检测的数据类型。
- 语法:
- 运算符形式(常用语法):
typeof 变量名 - 函数形式:
typeof(变量名)
- 运算符形式(常用语法):
6.4.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let num = 1
console.log(typeof num)
let str = ''
console.log(typeof str)
let bol = true
console.log(typeof bol)
let arr = []
console.log(typeof arr)
let obj = {}
console.log(typeof obj)
console.log(typeof null)
console.log(typeof undefined)
</script>
</body>
</html>
6.4.3、页面效果
数组居然也是object类型
6.5、数据类型转换
6.5.1、数据类型转换的作用
当使用prompt()方法的时候(例如:let age = prompt('您今年多大了')),我们本意想获取数字,但是现在获取的是字符串类型,这分明不是我们想要的结果,如下图:

以及获取form表单元素时,获取到的输入值都是字符串,但是这可能不是我们需要的类型,所以需要进行数据类型转换,最终得到我们需要的数据类型
6.5.2、显式转换
6.5.2.1、概念
- 含义:隐式转换是程序语言自动转换的,但是有些时候的转换效果并不是我们想要的,所以就需要显式转换告诉程序语言应该怎么转换
6.5.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 将字符串转换成数字类型
console.log(`Number('1') = ${Number('1')}`)
// 将字符串转换成整数类型(数字类型),但是仅保留数字,并且单位等字符串信息必须在最后面,不能在最前面
console.log(`parseInt('1.5px') = ${parseInt('1.5px')}`)
// 将字符串转换成小数类型(数字类型),但是仅保留数字,并且单位等字符串信息必须在最后面,不能在最前面
console.log(`parseFloat('1.5px') = ${parseFloat('1.5px')}`)
// 将其他数据类型转换成布尔值。
// 注意:''、0、undefined、null、false、NaN转换成布尔值后都是flase,其他情况是true
console.log(`Boolean(undefined) = ${Boolean(undefined)}`)
console.log(`Boolean('1') = ${Boolean('1')}`)
</script>
</body>
</html>
6.5.2.3、页面效果

6.5.3、隐式转换
6.5.3.1、概念
- 含义:在计算过程中,根据计算符号的不同,可能发生数据类型转换。比如
1 + '1',前面的数字1就会被隐式转换成字符串
6.5.3.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 将数字1转换成字符串'1'
// 注意:+加号两边只要有一个是字符串,都会把另外一个数据转换成字符串
console.log(`'1' + 1 = ${'1' + 1}`)
// 在字符串前面加一个+,可以将字符串类型转换成数字类型,这个加号其实是正号,做了强制转换
// 如果字符串不是数字,那结果是NaN
console.log(`+'1' = ${+'1'}`)
// 根据加号执行顺序,先执行加法,在执行字符串拼接
console.log(`1 + 1 + '1' = ${1 + 1 + '1'}`)
// 除了加法之外的符号,例如-、*、/、%,都会将字符串转换为数字进行计算
console.log(`2 - '2' = ${2 - '2'}`)
</script>
</body>
</html>
6.5.3.3、页面效果

7、JS运算符
7.1、算术运算符
- 含义:数学运算符也叫做算术运算符,主要包括加、减、乘、除、取余
- 分类:
- 加:加法或者拼接符(字符串拼接),例如:
console.log(1 + 1)的结果是2,console.log(1 + '1')的结果是字符串11 - 减:减法,例如:
console.log(1 - 1)的结果是0 - 乘:减法,例如:
console.log(1 * 1)的结果是1 - 除:减法,例如:
console.log(1 / 1)的结果是1 - 取余:减法,例如:
console.log(6 % 4)的结果是2,可以用于判断是否可以整除某个数字
- 加:加法或者拼接符(字符串拼接),例如:
7.2、赋值运算符
- 含义:对变量进行赋值的运算符
- 分类:
- =:直接赋值,例如:
let a = 1 - +=:等于
= X + Y,例如:let a = 1; a+=1,此时a=2 - -=:等于
= X + Y,例如:let a = 1; a-=1,此时a=0 - *=:等于
= X + Y,例如:let a = 1; a*=1,此时a=1 - /=:等于
= X + Y,例如:let a = 1; a/=1,此时a=1 - %=:等于
= X + Y,例如:let a = 1; a%=1,此时a=0
- =:直接赋值,例如:
7.3、自增 / 自减 运算符
- 含义:进行++或者–,其中++或者–可以放在变量前面,也可以放在变量后面
- 分类:
- 变量++:自增1,等价于变量 = 变量 + 1;例如:
let a = 1; a++,此时a是2 - 变量–:自减1,等价于变量 = 变量 - 1;例如:
let a = 1; a--,此时a是0 - ++变量:自增1,和前面不同的地方是“前面是先赋值在自增,这里是先自增,在赋值”,例如:
let a = 1, b = 1; a = a++; b = ++b;,此时a是1,b是2 - –变量:自减1,和前面不同的地方是“前面是先赋值在自减,这里是先自减,在赋值”,例如:
let a = 1, b = 1; a = a--; b = --b;,此时a是1,b是0
- 变量++:自增1,等价于变量 = 变量 + 1;例如:
7.5、三元运算符
- 语法:条件 ? 当条件为真时执行的代码 : 当条件为假时执行的代码
- 示例:
let a = 3 > 5 ? 1 : 2,由于3>5条件为假,此时a是2
7.6、比较运算符
- 含义:比较两个数据是否相等、大小
- 分类:
-
:左边是否大于右边,例如:
let a = 3 > 5的结果是false - <:左边是否小于右边,例如:
let a = 3 < 5的结果是true -
=:左边是否大于等于右边,例如:
let a = 3 >= 5的结果是false - <=:左边是否小于等于右边,例如:
let a = 3 <= 5的结果是true - ==:左右两边的值是否相等,和数据类型无关,例如:
let a = 3 == '3'的结果是true - ===:左右两边的值和类型是否相等,例如:
let a = 3 === '3'的结果是false - !=:左右两边的值是否不相等,和数据类型无关,例如:
let a = 3 != '3'的结果是false - !==:左右两边的值和类型是否不相等,例如:
let a = 3 !== '3'的结果是true
-
7.7、逻辑运算符
-
含义:逻辑与、或、非,当然也叫做短路与(如果前一个值是false,那后面的就不用计算了,最终结果就是false)、或(如果前一个值是true,那后面的就不用计算了,最终结果就是true)
-
分类:
- 逻辑与:两边都是真,结果才是真。例如:
let a = true && true的结果是true - 逻辑或:有任意一个为真,结果就是真。例如:
let a = true || false的结果是true - 逻辑非:将结果反过来。例如:
let a = !true的结果是false
- 逻辑与:两边都是真,结果才是真。例如:
-
特殊情况:
console.log(`3 > 5 && 20 = ${3 > 5 && 20}`) // 结果是false console.log(`10 && 20 = ${10 && 20}`) // 结果是20,两边都是真,那么最后一个值作为最终返回值
7.8、可选链操作符(?.)
说明: 当操作符前面的元素值为null或者undefined时,后面的就不会执行,常用语axios获取返回值中使用
用法:
import axios from 'axios';
axios.get('/api/user/info')
.then(res => console.log('请求成功:', res))
.catch(error => {
// 安全获取 HTTP 状态码,等同于:error && error.response && error.response.status;
const statusCode = error?.response?.status;
// 根据状态码做不同处理
switch (statusCode) {
case 401:
// 未授权:跳转登录页
console.log('登录状态过期,请重新登录');
window.location.href = '/login';
break;
case 403:
// 禁止访问:提示权限不足
console.log('您暂无该操作权限');
break;
case 404:
// 接口不存在:提示资源未找到
console.log('请求的资源不存在');
break;
case 500:
// 服务器错误:提示系统异常
console.log('服务器内部错误,请稍后重试');
break;
default:
// 其他状态码/无状态码(如网络错误)
console.log('请求失败:', error.message);
}
});
7.9、运算符优先级
说明: 当根据运算符优先级进行数据处理之后,从左到右依次计算

8、JS语句
8.1、概念
8.1.1、表达式和语句的区别

8.1.2、程序三大流程控制语句

8.2、if
8.2.1、单分支
-
语法:
if (条件) { 满足条件需要执行的代码 } -
使用说明:
- 当条件执行的结果不是布尔类型时,将隐式转换为布尔类型,相当于执行Boolean()方法
- 如果大括号中只有一条语句,那么大括号可以省略,但是不提倡这么做
8.2.2、双分支
-
语法:
if (条件) { 满足条件需要执行的代码 } else { 不满足条件需要执行的代码 } -
使用说明:
- 当条件执行的结果不是布尔类型时,将隐式转换为布尔类型,相当于执行Boolean()方法
8.2.2、多分支
-
语法:
if (条件1) { 满足条件1需要执行的代码 } else if (条件2) { 满足条件2需要执行的代码 } else if (条件3) { 满足条件3需要执行的代码 } else { 以上所有条件都不满足时需要执行的代码 } -
使用说明:
- 当条件执行的结果不是布尔类型时,将隐式转换为布尔类型,相当于执行Boolean()方法
- 最后一个else语句不是必须的,可以省略
- 只要满足任何一个条件,那么下面的条件都不会在判断了
8.3、break、continue
- 含义:break代表跳出循环,continue代表结束本次循环,然后开始下一次循环
- 使用位置:常常和switch、while语句一起使用
8.4、switch
- 语法:
switch (待比较值) {
case 值1:
代码1
break
case 值2:
代码2
break
default:
代码n
break
}
- 使用说明:
- 每一个case一定要以break结尾,如果满足case1,然后也满足case2,如果case1最后不写break,那么也会执行case2中的代码2
- 只有case后面的值和待比较值完全相等,包括数据和类型,类似于
===判断标准,才能执行对应case中的代码。如果所有case都不满足,那么将执行default中的代码 - default语句不是必须写的
8.5、while
- 含义:只要满足循环条件,代码都会重复执行
- 语法:
while (循环条件) {
循环体
}
- 使用注意:当条件执行的结果不是布尔类型时,将隐式转换为布尔类型,相当于隐式执行Boolean()方法
8.6、for
8.6.1、普通for循环
8.6.1.1、概念
- 含义:经常用于遍历数组
8.6.1.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let arr = [1, 2, 3]
for (let index = 0; index < arr.length; index++) {
const element = arr[index];
console.log(element)
}
</script>
</body>
</html>
8.6.1.3、页面效果

8.6.2、forin循环
8.6.2.1、概念
- 含义:经常用于遍历对象
8.6.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let obj = {
name: '明快de玄米61',
age: 18
}
for (const key in obj) {
const val = obj[key];
console.log(`属性名 = ${key}, 属性值 = ${val}`)
}
</script>
</body>
</html>
8.6.2.3、页面效果

9、JS函数
9.1、概念
-
作用:执行特定任务的代码块,可以一次编写,多次执行
-
分类:
- 无参函数:
function 函数名() { 函数体 }- 有参函数:
// 定义 function 函数名(形式参数1, 形式参数2, 形式参数3) { 函数体 } // 使用 // 注意:实参和形参个数不需要完全一致,如果形参不对应实参,那么形参的值是undefined 函数名(实际参数1, 实际参数2, 实际参数3) -
为形参设置默认值的函数:
// 如果实参数量不够,部分形参没有设置值,那默认值就会生效 function 函数名(形式参数1, 形式参数2 = '小明', 形式参数3 = 18) { 函数体 } // 使用 // 注意:实参和形参个数不需要完全一致,如果形参不对应实参,那么形参的值是undefined 函数名(实际参数1, 实际参数2, 实际参数3)- 带返回值的函数
function 函数名(形式参数1, 形式参数2, 形式参数3) { 函数体 return XXX } // 使用 // 注意:实参和形参个数不需要完全一致,如果形参不对应实参,那么形参的值是undefined let result = 函数名(实际参数1, 实际参数2, 实际参数3) // 打印结果 console.log(result)- 另外一种函数声明方式—匿名函数:
// 定义 let 变量名 = function(形式参数1, 形式参数2, 形式参数3) { 函数体 } // 使用 // 注意:实参和形参个数不需要完全一致,如果形参不对应实参,那么形参的值是undefined 变量名(实际参数1, 实际参数2, 实际参数3) -
立即执行函数(作用:立即执行函数中是的全局变量只在函数体内有效,所以可以避免多个js文件的全局变量污染)
// 语法1-无参 (function(){ console.log('没有参数') })(); // 语法1-有参 (function(window, document){ console.log(window) console.log(document) })(window, document); // 语法2-无参 (function(){ console.log('没有参数') }()); // 语法2-有参 (function(window, document){ console.log(window) console.log(document) }(window, document));- 在对象中如何定义函数:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> let obj = { name: '明快de玄米61', age: 18, eat: function() { console.log('吃零食') }, run: function(time) { console.log(`${time}奔跑`) }, info: function() { return this.name + ' ' + this.age } } console.log(obj.eat()) console.log(obj.run('2025年11月30日')) console.log(obj.info()) </script> </body> </html>
9.2、内置函数
9.2.1、数学内置对象—Math

9.2.2、随机数函数
9.2.2.1、概念
Math.random()可以生成0~1(包括0,不包括1)的随机数,例如:0.1443634636
9.2.2.2、案例1—打印随机数
9.2.2.2.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
console.log(`0~1(包括0,不包括1)的随机数:${Math.random()}`)
// 生成start~end的随机数
function generateRandomNum(start, end) {
return Math.floor(Math.random() * (end - start + 1)) + start
}
console.log(`生成5~10的随机数:${generateRandomNum(5, 10)}`)
</script>
</body>
</html>
9.2.2.2.2、页面效果

9.2.2.3、案例2—从数组中随机选出一个元素
9.2.2.3.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 从数组中随机选出一个元素
let arr = ['赵云', '张飞', '马超', '刘备', '关羽']
let randomIndex = Math.floor(Math.random() * arr.length)
document.write(`本次选出的是:${arr[randomIndex]}`)
</script>
</body>
</html>
9.2.2.3.2、页面效果

9.2.2.4、案例3—猜数字
9.2.2.4.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let start = 1,
end = 10;
let randomNum = Math.floor(Math.random() * (end - start + 1)) + start
console.log(`本次选中的随机数字是:${randomNum}`)
while (true) {
let userInput = +prompt(`请输入一个数字(${start}~${end}):`);
if (userInput > randomNum) {
alert('数字猜大了,继续猜')
} else if (userInput < randomNum) {
alert('数字猜小了,继续猜')
} else {
alert('猜对了,程序结束')
break
}
}
</script>
</body>
</html>
9.2.2.4.2、页面效果

9.2.2.5、案例4—输出两种格式颜色
9.2.2.5.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 输出两种格式颜色
document.write(`16进制颜色:${getRandomColor(true)}<br>`)
document.write(`rgb格式颜色:${getRandomColor(false)}`)
// 获取随机颜色,输入flag=true返回16进制颜色,输入flag=false返回rgb格式颜色
function getRandomColor(flag) {
if (flag) {
return getHexRandomColor()
} else {
return getRgbRandomColor()
}
}
// 输出16进制颜色
function getHexRandomColor() {
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']
let result = "#"
for (let index = 0; index < 6; index++) {
const randomIndex = Math.floor(Math.random() * arr.length)
result += arr[randomIndex]
}
return result
}
// 输出rgb格式颜色
function getRgbRandomColor() {
let r = Math.floor(Math.random() * 256)
let g = Math.floor(Math.random() * 256)
let b = Math.floor(Math.random() * 256)
return `rgb(${r}, ${g}, ${b})`
}
</script>
</body>
</html>
9.2.2.5.2、页面效果

10、JS术语
10.1、常用术语

10.2、环境对象this
10.2.1、概念
- 含义:函数内部特殊的变量this,代表当前函数运行时所处的环境
- 作用:this可以帮助我们让代码更加简洁。
- 判断this指向的粗略规则:谁调用,this就是谁
10.2.2、案例1—普通案例
10.2.2.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button class="btn">点击我</button>
<script>
// this指代window
alertHello()
function alertHello() {
console.log(this)
}
// this指代btnDom
const btnDom = document.querySelector('.btn')
btnDom.addEventListener('click', function(event) {
console.log(this)
})
</script>
</body>
</html>
10.2.2.2、页面效果

10.2.3、案例2—页签切换案例
10.2.3.1、代码示例
<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
a {
text-decoration: none; /* 去掉下划线 */
color: inherit; /* 继承父级颜色,避免默认蓝/紫 */
/* 可选:保留手型 cursor: pointer; 其实浏览器默认就是 pointer */
}
.goods {
margin: 50px 100px;
}
.goods .tab {
width: 300px;
height: 30px;
}
.goods .tab ul {
display: flex;
}
.goods .tab li {
width: 100px;
height: 30px;
border: 1px solid #ccc;
background-color: pink;
text-align: center;
line-height: 30px;
color: black;
font-family: '楷体';
}
.goods .tab li a.active {
color: red;
}
.goods .content div {
width: 300px;
height: 100px;
text-align: center;
line-height: 100px;
font-size: 30px;
display: none;
background-color: goldenrod;
}
.goods .content div.active {
display: block;
}
.goods .content div.remen {
background-color: rgb(255, 0, 0, 0.5);
}
.goods .content div.yifu {
background-color: rgb(173, 255, 47, 0.5);
}
.goods .content div.jiushui {
background-color: rgb(138, 43, 226, 0.5);
}
</style>
</head>
<body>
<div class="goods">
<div class="tab">
<ul>
<li><a class="active" href="#">热门</a></li>
<li><a href="#">衣服</a></li>
<li><a href="#">酒水</a></li>
</ul>
</div>
<div class="content">
<div class="remen active">热门</div>
<div class="yifu">衣服</div>
<div class="jiushui">酒水</div>
</div>
</div>
<script>
// 启用标签和内容所用的class类
const ACTIVE_CLASS_NAME = 'active'
// 遍历所有标签列表
const tabDomArr = document.querySelectorAll('.goods .tab a')
for (let index = 0; index < tabDomArr.length; index++) {
const tabDom = tabDomArr[index]
tabDom.addEventListener('mouseenter', function() {
// 1、处理标签
// 移除其他标签已有效果
const tabActiveDom = document.querySelector('.goods .tab a.active')
if(tabActiveDom) tabActiveDom.classList.remove(ACTIVE_CLASS_NAME)
// 为当前标签添加效果
this.classList.add(ACTIVE_CLASS_NAME)
// 2、处理内容
// 移除其他内容已有效果
const contentActiveDom = document.querySelector('.goods .content div.active')
if(contentActiveDom) contentActiveDom.classList.remove(ACTIVE_CLASS_NAME)
// 为当前内容添加效果
document.querySelector(`.goods .content div:nth-child(${index + 1})`).classList.add(ACTIVE_CLASS_NAME)
})
}
</script>
</body>
</html>
10.2.3.2、页面效果

10.2.4、案例3—复选框全选反选案例
10.2.4.1、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 表头 -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>你好,春天~</title>
<style>
* {
margin: 0;
padding: 0;
}
table {
width: 500px;
margin: 50px 100px;
border-radius: 20px;
overflow: hidden;
/* 新增:消除单元格间距 */
border-collapse: collapse;
}
thead {
background-color: yellowgreen;
}
tbody {
background-color: #ccc;
}
input {
width: 22px;
height: 22px;
/* 让复选框与旁边的文本居中对齐 */
vertical-align: middle;
/* 可选:增加 margin-right 让复选框和文字间距更舒适 */
margin-right: 6px;
}
th {
padding: 16px 12px;
font-weight: 500;
letter-spacing: 0.5px;
text-align: left;
white-space: nowrap;
}
td {
padding: 14px 12px;
border-bottom: 1px solid #d0e0d0;
color: #1e3a1e;
}
tbody tr:hover {
background-color: grey;
}
</style>
</head>
<body>
<table>
<thead>
<tr>
<th>
<input type="checkbox" class="checkAll"> 全选
</th>
<th>商品</th>
<th>商家</th>
<th>价格</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="checkbox" class="check">
</td>
<td>小米14手机</td>
<td>小米</td>
<td>1999元</td>
</tr>
<tr>
<td>
<input type="checkbox" class="check">
</td>
<td>SK-II</td>
<td>铂兰娜</td>
<td>2020元</td>
</tr>
<tr>
<td>
<input type="checkbox" class="check">
</td>
<td>牤牛模型车</td>
<td>牤牛</td>
<td>176元</td>
</tr>
</tbody>
</table>
<script>
const checkAllDom = document.querySelector('.checkAll')
const checkDomArr = document.querySelectorAll('.check')
// 全选/取消全选
checkAllDom.addEventListener('change', function(event) {
const isChecked = event.target.checked
checkDomArr.forEach(cb => cb.checked = isChecked);
})
// 单个复选框变化时更新全选状态
for(let index = 0; index < checkDomArr.length; index++) {
checkDomArr[index].addEventListener('change', function() {
const allChecked = Array.from(checkDomArr).every(c => c.checked);
checkAllDom.checked = allChecked
})
}
</script>
</body>
</html>
10.2.4.2、页面效果

10.3、回调函数
10.3.1、概念
- 含义:如果将函数A作为参数,然后传给函数B,此时我们称函数A为回调函数
10.3.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
setInterval(fn, 1000)
function fn() {
console.log('我是回调函数~')
}
</script>
</body>
</html>
10.3.3、页面效果

10.4、日期对象
10.4.1、概念
- 创建日期对象:
- 获取当前日期对象:
new Date() - 手动指定时间,创建日期对象:
new Date('2026-2-22 12:13:00')
- 获取当前日期对象:
- 获取年、月、日、时、分、秒、星期
- 获取四位年份:
日期对象.getFullYear() - 获取月份(取值为0~11。注意:真实月份等于取值+1):
日期对象.getMonth() + 1 - 获取月份中的每一天(不同月份取值也不相同):
日期对象.getDate() - 获取小时(取值0~23):
日期对象.getHours() - 获取分钟(取值0~59):
日期对象.getMinutes() - 获取秒(取值0~59):
日期对象.getSeconds() - 获取星期(取值为0~6。注意:除了星期日对应0,其他正常对应):
日期对象.getDay() !== 0 ? 日期对象.getDay() : 7
- 获取四位年份:
- 快速展示本地时间
- 日期+时间(取值示例:2026/3/5 12:54:09):
日期对象.toLocaleString() - 日期(取值示例:2026/3/5):
日期对象.toLocaleDateString() - 时间(取值示例:12:54:09):
日期对象.toLocaleTimeString()
- 日期+时间(取值示例:2026/3/5 12:54:09):
- 获取时间戳(毫秒数):
- 获取任意时间时间戳:
日期对象.getTime() - 获取任意时间时间戳:
+日期对象 - 获取当前时间的时间戳:
Date.now()
- 获取任意时间时间戳:
10.4.2、案例1—功能演示
10.4.2.1、代码示例
<!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>
* {
margin: 0;
padding: 0;
}
.btn {
position:relative;
width: 50px;
height: 50px;
padding: 10px;
border: 2px solid black;
margin: 10px;
background-color: pink;
text-align: center;
line-height: 50px;
left: 30px;
top: 1000px;
cursor: pointer;
}
.btn:hover {
background-color: yellowgreen;
}
</style>
</head>
<body>
<script>
console.log('1、创建日期对象:')
console.log(' - 获取当前日期对象:new Date()')
console.log(new Date())
console.log(' - 手动指定时间,创建日期对象:new Date("2026-2-22 12:13:00")')
console.log(new Date("2026-2-22 12:13:00"))
console.log('2、获取年、月、日、时、分、秒、星期')
console.log(' - 获取四位年份:日期对象.getFullYear()')
const time = new Date()
console.log(time.getFullYear())
console.log(' - 获取月份(取值为0~11。注意:真实月份等于取值+1):日期对象.getMonth() + 1')
console.log(time.getMonth() + 1)
console.log(' - 获取月份中的每一天(不同月份取值也不相同):日期对象.getDate()')
console.log(time.getDate())
console.log(' - 获取小时(取值0~23):日期对象.getHours()')
console.log(time.getHours())
console.log(' - 获取分钟(取值0~59):日期对象.getMinutes()')
console.log(time.getMinutes())
console.log(' - 获取秒(取值0~59):日期对象.getSeconds()')
console.log(time.getSeconds())
console.log(' - 获取星期(取值为0~6。注意:除了星期日对应0,其他正常对应):日期对象.getDay() !== 0 ? 日期对象.getDay() : 7')
console.log(time.getDay() !== 0 ? time.getDay() : 7)
console.log('3、快速展示本地时间')
console.log(' - 日期+时间(取值示例:2026/3/5 12:54:09):日期对象.toLocaleString()')
console.log(time.toLocaleString())
console.log(' - 日期(取值示例:2026/3/5):日期对象.toLocaleDateString()')
console.log(time.toLocaleDateString())
console.log(' - 时间(取值示例:12:54:09):日期对象.toLocaleTimeString()')
console.log(time.toLocaleTimeString())
console.log('4、获取时间戳(毫秒数):')
console.log(' - 获取任意时间时间戳:日期对象.getTime()')
console.log(time.getTime())
console.log(' - 获取任意时间时间戳:+日期对象')
console.log(+time)
console.log(' - 获取当前时间的时间戳:Date.now()')
console.log(Date.now())
</script>
</body>
</html>
10.4.2.2、页面效果

10.4.3、案例2—开奖倒计时
10.4.3.1、代码示例
<!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>
</style>
</head>
<body>
<h1 class="info"></h1>
<script>
// 倒计时
const deadline = new Date('2026-12-18 14:10:00')
// 当前时间
const now = new Date()
// 剩余秒数
let remainSecond = parseInt((deadline.getTime() - now.getTime()) / 1000)
// 使用定时器完成倒计时
let timer = setInterval(function(){
if(remainSecond === 0) {
// 清除定时器
clearInterval(timer)
document.querySelector('.info').innerText = `
开奖时间是${deadline.toLocaleString()},现在开奖,恭喜你中奖了~
`
} else {
const day = parseInt(remainSecond / 60 / 60 / 24 % 365)
const hour = parseInt(remainSecond / 60 / 60 % 24)
const minute = parseInt(remainSecond / 60 % 60)
const second = parseInt(remainSecond % 60)
document.querySelector('.info').innerText = `
开奖时间是${deadline.toLocaleString()},现在还有${day}天${hour}小时${minute}分${second}秒
`
remainSecond--
}
}, 1000)
</script>
</body>
</html>
10.4.3.2、页面效果

11、DOM
11.1、概念
- 作用:使用JS语法操作网页标签和浏览器
- 分类:DOM(文档对象模型,即操作网页内容使用的)、BOM(浏览器对象模型,即操作浏览器执行动作使用的)
- DOM和BOM的关系:

- DOM树:将网页标签通过树状结构表示出来,我们称之为文档树或者DOM树

- DOM对象:
- 概念:html标签对应的JS对象。在DOM对象上可以找到标签的所有属性,然后修改DOM对象的属性也会自动映射到标签身上
- 核心思想:将网页内容当做对象来处理
- document对象:这是DOM中提供的一个对象,网页所有内容都在document对象里面
11.2、查找、增加、删除Dom节点
11.2.1、概念
- Dom节点:Dom树中每一个内容都可以被称之为节点
- 节点类型:
- 元素节点:所有的标签都是元素节点,例如html、body、div等。注意:我们基本只会关注这种节点
- 属性节点(了解概念即可):元素属性,例如src
- 文本节点(了解概念即可):文本内容
- 其他节点(了解概念即可)

11.2.2、获取DOM对象
11.2.2.1、概念
- 语法:
- 查找匹配的第1个元素:
document.querySelector(CSS选择器)。示例:const box = document.querySelector('.box ul li')。说明:使用该方法得到的是第1个符合要求的DOM对象 - 查找匹配的全部元素(数组):
document.querySelectorAll(CSS选择器)。示例:const liArr = document.querySelectorAll('.box ul li')。说明:使用该方法得到的是一个DOM对象数组- 注意点1: 通过
querySelectorAll()方法最终得到的数组经过了改造,拥有长度和索引号,但是没有pop()和push()等数组方法,可以通过for循环得到数组中的DOM对象 - 注意点2:
querySelector()、querySelectorAll()不仅可以被document元素调用,也可以普通Dom元素调用,例如:const noteEl = document.createElement('div') noteEl.innerHTML = ` <div class="function"> <button class="btn editBtn"><i class="fas fa-edit"></i></button> <button class="btn deleteBtn"><i class="fas fa-trash-alt"></i></button> </div> <div class="markdown ${text ? '' : 'hidden'}"></div> <textarea class="${text ? 'hidden' : ''}">${text}</textarea> ` noteEl.className = 'note' notesEl.appendChild(noteEl) // 学习点:从Dom节点中可以获取里面的元素,不一定非要是document const editBtnEl = noteEl.querySelector('.editBtn'); const deleteBtnEl = noteEl.querySelector('.deleteBtn'); const markdownEl = noteEl.querySelector('.markdown'); const textareaEl = noteEl.querySelector('textarea'); markdownEl.innerHTML = marked(text); // 绑定事件 editBtnEl.addEventListener('click', () => { markdownEl.classList.toggle('hidden'); textareaEl.classList.toggle('hidden'); }) deleteBtnEl.addEventListener('click', () => { noteEl.remove(); addToLocalStorage(); }) textareaEl.addEventListener('input', () => { markdownEl.innerText = marked(textareaEl.value); addToLocalStorage(); })
- 注意点1: 通过
- 查找父节点(不存在父节点时结果为null):
Dom节点对象.parentNode - 查找子节点(数组):
Dom节点对象.children - 查找上一个兄弟节点(不存在上一个兄弟节点时结果为null):
Dom节点对象.previousElementSibling - 查找上一个兄弟节点(不存在上一个兄弟节点时结果为null):
Dom节点对象.nextElementSibling
- 查找匹配的第1个元素:
- 其他语法(了解即可,不在使用):

11.2.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="box">
<ul>
<li>hello</li>
<li>你好</li>
<li>Ni Hao</li>
</ul>
</div>
<script>
console.log('————————查找单个节点——————————')
const liDom = document.querySelector('.box ul li')
console.dir(liDom)
console.log('————————查找节点数组——————————')
const liDomArr = document.querySelectorAll('.box ul li')
console.dir(liDomArr)
console.log('————————查找父节点(不存在父节点时结果为null)——————————')
const firstLiDom = document.querySelector('ul li:nth-child(1)')
console.dir(firstLiDom.parentNode)
console.log('————————查找子节点——————————')
const ulDom = document.querySelector('ul')
console.dir(ulDom.children)
console.log('————————查找上一个兄弟节点(不存在上一个兄弟节点时结果为null)——————————')
const secondLiDom = document.querySelector('ul li:nth-child(2)')
console.dir(secondLiDom.previousElementSibling)
console.log('————————查找上一个兄弟节点(不存在上一个兄弟节点时结果为null)——————————')
console.dir(secondLiDom.nextElementSibling)
</script>
</body>
</html>
11.2.2.3、页面效果

11.2.3、创建、追加、克隆、删除节点
11.2.3.1、概念
- 语法:
- 创建节点:
document.createElement('标签名称'),例如document.createElement('li') - 追加节点:
- 在父元素最后面追加一个节点:
父元素.appendChild(新Dom节点) - 在父元素最后追加多个节点或字符串:
父元素.append(新Dom节点, '一些文本', 其他新的Dom节点); - 在父元素中指定子元素前面追加节点:
父元素.insertBefore(新Dom元素, 指定子Dom元素)
- 在父元素最后面追加一个节点:
- 克隆节点:
Dom元素.cloneNode(是否深度克隆【非必填】)- 参数:是否深度克隆,该参数非必填,默认是false。true:代表克隆时会包括后代节点,也就是深克隆。false:和true相关,代表克隆时不会包括后代节点,也就是浅客隆
- 删除节点:
- 方式1:
父元素.removeChild(需要删除的元素本身)- 注意:必须通过父元素才能删除子元素,如果不存在父子关系,那么删除失败
- 方式2:
当前元素.remove()- 注意:remove() 是元素自身的方法,直接在该元素上调用,它会将自己从其父节点中移除。
- 方式1:
- 创建节点:
11.2.3.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="box">
<ul>
<li>hello</li>
<li>你好</li>
<li>Ni Hao</li>
</ul>
</div>
<script>
const ulDom = document.querySelector('ul')
const liDomArr = document.querySelectorAll('ul li')
console.log('————————创建节点——————————')
const newLiDom1 = document.createElement('li')
newLiDom1.innerText = '萨瓦迪卡'
console.log('————————追加节点——————————')
// 在父元素最后面追加节点
ulDom.appendChild(newLiDom1)
// 在父元素中指定子元素前面追加节点
const newLiDom2 = document.createElement('li')
newLiDom2.innerText = 'HaHa'
ulDom.insertBefore(newLiDom2, liDomArr[0])
console.log('————————克隆节点——————————')
// 浅克隆
console.dir(liDomArr[2].cloneNode())
// 深克隆
console.dir(liDomArr[2].cloneNode(true))
console.log('————————删除节点——————————')
console.dir(ulDom.removeChild(liDomArr[0]))
</script>
</body>
</html>
11.2.3.3、页面效果

11.2.4、综合案例—学员录入表
代码示例:
<!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>
* {
margin: 0;
padding: 0;
}
ul {
list-style: none;
}
a {
text-decoration: none; /* 去掉下划线 */
color: inherit; /* 继承父级颜色,避免默认蓝/紫 */
/* 可选:保留手型 cursor: pointer; 其实浏览器默认就是 pointer */
}
table {
width: 800px;
margin: 0 auto;
/* 新增:消除单元格间距 */
border-collapse: collapse;
}
thead {
background-color: yellowgreen;
}
tbody {
background-color: #ccc;
}
th {
padding: 16px 12px;
font-weight: 500;
letter-spacing: 0.5px;
text-align: center;
white-space: nowrap;
border: 1px solid #d0e0d0;
}
td {
padding: 14px 12px;
border: 1px solid #d0e0d0;
color: #1e3a1e;
}
.title {
margin: 30px auto;
text-align: center;
}
.inputRegion {
text-align: center;
}
.inputRegion button {
background-color: rgb(64, 224, 208, 0.5);
border: 0;
padding: 3px 10px;
margin-left: 10px;
border-radius: 5px;
cursor: pointer;
}
.inputRegion button:hover {
background: rgb(64, 224, 208);
}
.showInfo a {
padding: 10px;
background-color: #555;
color: white;
border-radius: 20%;
}
.showInfo a:hover {
background-color: black;
}
</style>
</head>
<body>
<h2 class="title">新增学员</h2>
<form class="inputRegion" autocomplete="off">
姓名:<input type="text" name="name" class="name">
年龄:<input type="text" name="age" class="age">
性别:
<select name="gender" class="gender">
<option value="男">男</option>
<option value="女">女</option>
</select>
薪资:<input type="text" name="salary" class="salary">
就业城市:
<select name="city" class="city">
<option value="北京">北京</option>
<option value="上海">上海</option>
</select>
<button type="submit">录入</button>
</form>
<h2 class="title">就业榜</h2>
<table class="showInfo">
<thead>
<tr>
<th>学号</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>薪资</th>
<th>就业城市</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script>
const tbodyDom = document.querySelector('.showInfo tbody')
const formDom = document.querySelector('.inputRegion')
const nameDom = document.querySelector('.inputRegion .name')
const ageDom = document.querySelector('.inputRegion .age')
const genderDom = document.querySelector('.inputRegion .gender')
const salaryDom = document.querySelector('.inputRegion .salary')
const cityDom = document.querySelector('.inputRegion .city')
const inputDomArr = document.querySelectorAll('.inputRegion [name]')
const infoArr = []
// 监听表单提交操作
formDom.addEventListener('submit', function(event) {
// 阻止默认提交行为
event.preventDefault()
// 校验参数完整性
for(let index = 0; index < inputDomArr.length; index++) {
if(!inputDomArr[index].value) {
alert('请将数据填写完整~')
return
}
}
// 创建对象
const infoObj = {
'no': Date.now(),
'name': nameDom.value,
'age': ageDom.value,
'gender': genderDom.value,
'salary': salaryDom.value,
'city': cityDom.value
}
// 将对象添加到数组中
infoArr.push(infoObj)
// 重置表单
this.reset()
// 重新渲染数据
resetTable()
})
// 监听删除操作
tbodyDom.addEventListener('click', function(event) {
if(event.target.tagName === 'A' && event.target.dataset && event.target.dataset.index) {
const info = infoArr[+event.target.dataset.index]
const answer = confirm(`您确定要删除【姓名:${info.name}】吗?`)
if(answer) {
// 删除数据
infoArr.splice(+event.target.dataset.index, 1)
// 重新渲染数据
resetTable()
}
}
})
function resetTable() {
// 清空原有数据
tbodyDom.innerHTML = ''
// 展示新数据
for(let index = 0; index < infoArr.length; index++) {
const newTrDom = document.createElement('tr')
newTrDom.innerHTML = `
<td>${infoArr[index].no}</td>
<td>${infoArr[index].name}</td>
<td>${infoArr[index].age}</td>
<td>${infoArr[index].gender}</td>
<td>${infoArr[index].salary}</td>
<td>${infoArr[index].city}</td>
<td>
<a href="#" data-index="${index}">删除</a>
</td>
`
tbodyDom.appendChild(newTrDom)
}
}
</script>
</body>
</html>
页面效果:

11.3、操作元素内容
11.3.1、innerText属性
11.3.1.1、概念
- 语法:
innerText:将文本内容添加/更新到任意标签位置,只会显示纯文本,不解析标签。也可用于获取标签文本内容
11.3.1.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>当前网站已经迁移到新网址,<span style="color: red;"><span class="second">10</span>s</span>后将跳转到新网址</h2>
<script>
// 获取显示倒计时的Dom元素
const secondDom = document.querySelector('.second')
// 倒计时
let countdownSecond = 10
// 定时器
let timer = setInterval(function(){
// 每隔1s倒计时减1
countdownSecond--
/*
情况1:当倒计时不等于0,需要改变显示倒计时的元素内容
情况2:当倒计时等于0,停止定时器,跳转到新网址
*/
if(countdownSecond === 0) {
clearInterval(timer)
location.href = 'https://www.baidu.com'
} else {
secondDom.innerText = countdownSecond + ''
}
}, 1000)
</script>
</body>
</html>
11.3.1.3、页面效果

11.3.2、innerHtml属性
11.3.2.1、概念
- 语法:
innerHtml:将文本内容添加/更新到任意标签位置,会解析html标签,多标签建议使用模板字符串。也可用于获取标签html内容
11.3.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 模拟数据加载的效果 -->
<span class="loading"></span>
<!-- 展示数据加载的结果 -->
<div>
<ul></ul>
</div>
<script>
// 模拟数据加载的效果
const loadingDom = document.querySelector('.loading')
loadingDom.innerText = '数据加载中,请耐心等待~'
// 模拟数据请求的效果
setTimeout(function() {
// 加载完成,清空加载效果
loadingDom.innerText = ''
// 展示数据加载结果
const likeArr = ['抽烟', '喝酒', '烫头']
const ulDom = document.querySelector('ul')
// 使用模板字符串
likeArr.forEach(function(like) {
const liStr = `
<li> ${like} </li>
`
ulDom.innerHTML += liStr
});
}, 1000)
</script>
</body>
</html>
11.3.2.3、页面效果

11.4、操作元素属性
11.4.1、操作元素常用属性
11.4.1.1、概念
- 语法:
- 概念:通过JS可以设置/修改标签元素属性,例如常见属性:src、href、title、alt等
- 写法:
Dom对象.属性 = 值
- 举例:

11.4.1.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img style="width: 300px;" src="big.png" title="大图片">
<script>
// 3秒之后,将改变图片路径
setTimeout(function(){
const imgDom = document.querySelector('img')
imgDom.src = '刘亦菲头像.jpg'
imgDom.title = '刘亦菲头像'
}, 3000)
</script>
</body>
</html>
11.4.1.3、页面效果

11.4.2、操作元素样式属性
11.4.2.1、概念
- 语法:通过style属性操作样式属性,包括设置、删除、获取等操作
- 写法:
Dom对象.style.样式属性 = 值 - 注意:
- 样式属性存在连接符:需要转换成小驼峰命名法,例如:将
background-color改成backgroundColor - 赋值添加单位:例如为字体大小赋值,记得添加px单位
- 样式属性存在连接符:需要转换成小驼峰命名法,例如:将
- 举例:

11.4.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div style="width: 300px;height: 300px;background-color: blueviolet;color: red; font-size: 30px;">你好</div>
<script>
// 1秒之后,将随机改变盒子颜色、文字颜色
setInterval(function(){
const divDom = document.querySelector('div')
// 单个单词情况:直接使用即可
divDom.style.color = getHexRandomColor()
// 多单词情况:使用小驼峰命名法,例如将background-color改成backgroundColor
divDom.style.backgroundColor = getHexRandomColor()
// 多属性值:支持多属性值的情况
divDom.style.border = '5px solid black'
}, 1000)
// 输出16进制颜色
function getHexRandomColor() {
const arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']
let result = "#"
for (let index = 0; index < 6; index++) {
const randomIndex = Math.floor(Math.random() * arr.length)
result += arr[randomIndex]
}
return result
}
</script>
</body>
</html>
11.4.2.3、页面效果

11.4.3、操作类名(class)属性
11.4.3.1、概念
- 方案1:直接设置class属性值(使用className直接赋值)
- 作用:有些情况下,css样式变化比较复杂,如果使用
Dom元素.style.XXX一点点操作,那太麻烦了,所以有些时候也会设置class属性,从而完成一次修改多个style标签的目的 - 注意:
- 1、className用途:由于class属性名称是关键字,所以不能直接使用
Dom元素.class设置class属性值,因此延伸出了className用于操作class属性值 - 2、替换class属性值:直接赋值就是替换操作,如果想留下原来的class属性值,那就需要执行追加操作吧
- 1、className用途:由于class属性名称是关键字,所以不能直接使用
- 用法:
Dom元素.className = 'XXX'
- 作用:有些情况下,css样式变化比较复杂,如果使用
- 方案2:通过数组方式来操作class属性(使用classList进行追加、删除、切换类名操作)
- 作用:如果Dom元素的class属性存在值,那么上面直接替换class属性值的方案就不太合适了,但是可以使用classList方案
- 用法:
- 追加类:
Dom元素.classList.add('类名') - 删除类:
Dom元素.classList.remove('类名') - 切换类(有则删除,无则添加):
Dom元素.classList.toggle('类名')
- 追加类:
11.4.3.2、方案1:直接设置class属性值(使用className直接赋值)
11.4.3.2.1、代码示例
<!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>
div {
width: 300px;
height: 300px;
background-color: pink;
border: 1px solid black;
}
.active {
background-color: greenyellow;
border: 1px solid red;
}
</style>
</head>
<body>
<div></div>
<script>
// 1秒之后,将改变盒子颜色、边框颜色
setTimeout(function(){
const divDom = document.querySelector('div')
divDom.className = 'active'
}, 2000)
</script>
</body>
</html>
11.4.3.2.2、页面效果

11.4.3.3、方案2:通过数组方式来操作class属性(使用classList进行追加、删除、切换类名、判断是否包含类名的操作)
11.4.3.3.1、概念
// 获取元素的 classList 对象
const classList = element.classList;
// 追加类名(可多个)
element.classList.add('class1', 'class2', ...);
// 删除类名(可多个)
element.classList.remove('class1', 'class2', ...);
// 切换类名:有则删除,无则添加,返回布尔值表示切换后是否存在
element.classList.toggle('className', [force]); // 可选 force 参数强制添加/删除
// 判断是否包含某个类名,返回 true/false
element.classList.contains('className');
// 替换类名(较新方法)
element.classList.replace('oldClass', 'newClass');
11.4.3.3.2、代码示例
<!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>
.box {
width: 300px;
height: 300px;
background-color: pink;
border: 1px solid black;
}
.active {
background-color: greenyellow;
border: 1px solid red;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
// 1秒之后,将改变盒子颜色、边框颜色
setTimeout(function(){
const divDom = document.querySelector('div.box')
divDom.classList.add('active')
}, 2000)
</script>
</body>
</html>
11.4.3.3.3、页面效果

11.4.4、操作表单元素属性
11.4.4.1、概念
- 语法:表单元素的部分属性不太一样,所以特殊讲一下
- 用法:
- 字符串类型:
- value:可以用于获取文本框(type=text、textarea)、密码框(type=password)中的文本,例如:
document.querySelector('.text').value - text:可以获取select下拉列表某个选项的文本:
document.querySelector('.select option:nth-child(2)').text - type:获取表单元素类型,这个就是获取普通属性的用法了,不在赘述
- value:可以用于获取文本框(type=text、textarea)、密码框(type=password)中的文本,例如:
- 布尔值类型:
- checked:对于
input框的type类型是radio、checkbox类型的情况,用于判断选中状态 - selected:对于
select下拉列表,可以用于判断option元素按钮的选中状态
- checked:对于
- 字符串类型:
11.4.4.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input class="text" type="text" value="小王">
<br>
<input class="password" type="password" value="123456">
<br>
<input class="checkbox1" type="checkbox" checked>喝酒
<br>
<input class="checkbox2" type="checkbox">烫头
<br>
<input class="radio" type="radio">男
<br>
<select class="select" name="like">
<option value="apple" selected>苹果</option>
<option value="banana">香蕉</option>
<option value="orange">橘子</option>
</select>
<br>
<button class="button">按钮</button>
<script>
// 1、获取值、选中状态、下拉列表选择情况、按钮置灰状态
console.log('1、初次获取值、选中状态、下拉列表选择情况、按钮置灰状态')
showInfo()
// 2、设置值、选中状态、下拉列表选择情况、按钮置灰状态
console.log('————————————————————————————————————')
document.querySelector('.text').value = '小李'
document.querySelector('.password').value = '654321'
document.querySelector('.checkbox1').checked = false
document.querySelector('.checkbox2').checked = true
document.querySelector('.radio').checked = false
document.querySelector('.select option:nth-child(2)').selected = true
document.querySelector('.button').disabled = true
console.log('2、设置值、选中状态、下拉列表选择情况、按钮置灰状态后,再次获取值、选中状态、下拉列表选择情况')
showInfo()
function showInfo() {
console.log('文本框:', document.querySelector('.text').value)
console.log('密码框:', document.querySelector('.password').value)
console.log('复选框1选中状态:', document.querySelector('.checkbox1').checked)
console.log('复选框2选中状态:', document.querySelector('.checkbox2').checked)
console.log('单选框选中状态:', document.querySelector('.radio').checked)
console.log('下拉列表选项1选中状态:', document.querySelector('.select option:nth-child(1)').selected)
console.log('下拉列表选项2选中状态:', document.querySelector('.select option:nth-child(2)').selected)
console.log('下拉列表选项3选中状态:', document.querySelector('.select option:nth-child(3)').selected)
console.log('下拉列表选中value:', document.querySelector('.select').value)
console.log('按钮不可用状态:', document.querySelector('.button').disabled)
}
</script>
</body>
</html>
11.4.4.3、页面效果

11.4.5、操作自定义元素属性
11.4.5.1、概念
- 语法:
- 标准属性:标签自带的属性,比如class、id、title等
- 自定义属性:在html5中推出了自定义属性,在标签上一律以
data-XXX开头,通过DOM对象.dataset.XXX获取属性值
- 注意:如果
data-后面是通过-拼接的多个单,那就需要使用小驼峰命名法取值
11.4.5.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div data-id="1" data-name="机器人" data-bg-color="red"></div>
<script>
const divDom = document.querySelector('div')
console.dir(divDom.dataset)
console.dir(divDom.dataset.id)
console.dir(divDom.dataset.name)
console.dir(divDom.dataset.bgColor)
</script>
</body>
</html>
11.4.5.3、页面效果

11.5、事件监听
11.5.1、使用方法
11.5.1.1、概念
- 概念:当监听到Dom / Bom(例如window对象)对象上发生了一些事件(例如click点击、resize改变窗口大小等),就会触发函数执行,这就是事件监听
- 语法:
元素对象.addEventListener('事件类型', 函数),含义解释如下:- 元素对象:事件源头,可能是Dom元素,也可能是Bom元素
- 事件类型:也就是触发方式,比如鼠标单击click、鼠标经过mouseover等
- 函数:当监听到事件发生后,便会执行这个函数。其中函数中可以添加参数event,event对象中记录着事件信息,包括事件类型、鼠标点击位置等
11.5.1.2、代码示例
<!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>
.advertisement {
position: relative;
width: 500px;
height: 200px;
background-color: pink;
margin: 100px auto;
text-align: center;
line-height: 200px;
font-size: 50px;
font-weight: 700;
}
.advertisement .close {
position: absolute;
right: 10px;
top: 10px;
width: 30px;
height: 30px;
background-color: black;
border-radius: 100%;
text-align: center;
line-height: 30px;
font-size: 15px;
color: white;
user-select: none;
cursor: pointer;
transition: all 0.5s;
}
.advertisement .close:hover {
background-color: white;
color: red;
font-size: 20px;
}
</style>
</head>
<body>
<div class="advertisement">
我是广告
<div class="close">X</div>
</div>
<script>
// 需要关闭的大盒子
const advertisementDom = document.querySelector('.advertisement')
// 事件源
const closeDom = document.querySelector('.advertisement .close')
// 添加click监听时间
closeDom.addEventListener('click', function(event) {
// 关闭大盒子
console.dir(event)
advertisementDom.style.display = 'none'
})
</script>
</body>
</html>
11.5.1.3、页面效果
点击广告右上角的关闭按钮后,广告关闭
11.5.2、事件监听版本

11.5.3、事件类型
11.5.3.1、概念
- 鼠标事件(点击鼠标触发):
- click:鼠标点击
- dblclick:鼠标双击
- mouseenter:鼠标指针进入元素时触发1次(不冒泡,进入子元素不会重复触发父元素的进入事件)
- mouseleave:鼠标指针离开元素时触发1次(不冒泡,进入子元素不会重复触发父元素的进入事件)
- mouseover(不推荐使用):鼠标指针进入元素时触发1次(mouseover。会冒泡,进入子元素也会触发父元素的 mouseover)。注意:如果目标元素含有子元素,那么进出子元素也会触发父元素的进入操作,所以可能就触发多次触发操作,建议不要使用
- mouseout(不推荐使用):鼠标指针离开元素时触发1次(mouseout。会冒泡,进入子元素也会触发父元素的 mouseout)
- mousemove:鼠标指针在元素内移动时持续触发(mousemove。会冒泡,进入子元素也会触发父元素的mousemove。 常用于实时跟踪鼠标位置)。注意:在计算鼠标位置时需要特别注意,不能直接使用offsetX和offsetY,可以看下示例
- 文本事件:
- input:用户输入事件。发生时机:每当元素的值发生变化时立即触发。
- change:对于文本输入框,当元素的值被修改且失去焦点(blur)时触发;
- 焦点事件(表单控件获得/失去光标):
- focus:获得焦点
- blur:失去焦点
- 键盘事件(敲击键盘触发):
- keydown:键盘按下
- keyup:键盘抬起
- 单选框/复选框事件
- change:对于单选按钮、复选框、下拉列表等,当用户直接选择新选项时立即触发(无需失去焦点)。
- 页面加载事件(一般用于window对象、document对象,也支持普通Dom元素使用):
- load:当全部资源加载完成时触发
- DOMContentLoaded:当HTML标签加载完成时触发
- scroll:页面滚动事件
11.5.3.2、案例1—多事件实测
代码示例:
<!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>
div {
width: 300px;
height: 300px;
margin-bottom: 30px;
background-color: pink;
text-align: left;
line-height: 20px;
overflow: auto;
}
</style>
</head>
<body>
<div class="cursor">
<h1>鼠标事件</h1>
<p>鼠标点击(click)</p>
<p>鼠标双击(dblclick)</p>
<p>鼠标指针进入元素时触发1次(mouseenter。不冒泡,进入子元素不会重复触发父元素的进入事件)</p>
<p>鼠标指针离开元素时触发1次(mouseleave。不冒泡,进入子元素不会重复触发父元素的进入事件)</p>
<p>鼠标指针进入元素时触发1次(mouseover。会冒泡,进入子元素也会触发父元素的 mouseover)</p>
<p>鼠标指针离开元素时触发1次(mouseout。会冒泡,进入子元素也会触发父元素的 mouseout)</p>
<p>鼠标指针在元素内移动时持续触发(mousemove。会冒泡,进入子元素也会触发父元素的mousemove。 常用于实时跟踪鼠标位置)</p>
</div>
<div class="text">
<h1>文本事件</h1>
<p>用户输入事件</p>
<input type="text" placeholder="用户输入事件"/>
</div>
<div class="focus">
<h1>焦点事件</h1>
<p>获得焦点(focus)</p>
<p>失去焦点(blur)</p>
<input type="text" placeholder="焦点事件"/>
</div>
<div class="keyboard">
<h1>键盘事件</h1>
<p>键盘按下(keydown)</p>
<p>键盘抬起(keyup)</p>
<input type="text" placeholder="键盘事件"/>
</div>
<div class="check">
<h1>单选框/复选框事件</h1>
<p>当选择改变时触发(change)</p>
<input type="radio" />爱吃苹果
<input type="checkbox">喜欢梨子
</div>
<div class="load">
<h1 style="font-size: 20px;">页面加载事件(一般用于window对象、document对象,也支持普通Dom元素使用)</h1>
<p>当全部资源加载完成时触发(load)</p>
<p>当HTML标签加载完成时触发(DOMContentLoaded)</p>
<p>页面滚动事件(scroll)</p>
</div>
<script>
// 鼠标事件
const cursorDom = document.querySelector('.cursor')
cursorDom.addEventListener('click', function(event) {
console.log(`用户单击鼠标,在盒子内的坐标:${event.offsetX} ${event.offsetY}`)
})
cursorDom.addEventListener('dblclick', function() {
console.log(`用户双击鼠标`)
})
cursorDom.addEventListener('mouseenter', function() {
console.log(`鼠标指针进入元素时触发1次(mouseenter。不冒泡,进入子元素不会重复触发父元素的进入事件)`)
})
cursorDom.addEventListener('mouseleave', function() {
console.log(`鼠标指针离开元素时触发1次(mouseleave。不冒泡,进入子元素不会重复触发父元素的进入事件)`)
})
// 当鼠标进入子元素时,mouseover 事件在子元素上生成,然后冒泡到父元素(因为事件会沿着 DOM 树向上传播)。
// 父元素监听了 mouseover,自然就会捕获到这个冒泡上来的事件。
// 同样,鼠标离开子元素进入另一个子元素时,mouseout 事件也会从子元素冒泡到父元素。
// 因此下面代码就隐藏了,避免控制台出现太多打印内容
// cursorDom.addEventListener('mouseover', function() {
// console.log(`鼠标指针进入元素时触发1次(mouseover。会冒泡,进入子元素也会触发父元素的 mouseover)`)
// })
// cursorDom.addEventListener('mouseout', function() {
// console.log(`鼠标指针离开元素时触发1次(mouseout。会冒泡,进入子元素也会触发父元素的 mouseout)`)
// })
cursorDom.addEventListener('mousemove', function(event) {
const rect = cursorDom.getBoundingClientRect();
const x = event.clientX - rect.left; // 相对于父元素左边界的偏移
const y = event.clientY - rect.top; // 相对于父元素上边界的偏移
console.log(`鼠标指针在元素内移动时持续触发(mousemove。常用于实时跟踪鼠标位置),在盒子内的坐标:${x} ${y}`)
})
// 文本事件
const textTextDom = document.querySelector('.text input')
textTextDom.addEventListener('input', function(event) {
console.log(`文本内容改变,当前输入框内容是:${textTextDom.value}`)
})
// 焦点事件
const focusTextDom = document.querySelector('.focus input')
focusTextDom.addEventListener('focus', function(event) {
console.log(`输入框获得焦点,当前输入框内容是:${focusTextDom.value}`)
})
focusTextDom.addEventListener('blur', function(event) {
console.log(`输入框失去焦点,当前输入框内容是:${focusTextDom.value}`)
})
// 键盘事件(可以将keyboardTextDom换成window,那就可以监听全部按键了)
const keyboardTextDom = document.querySelector('.keyboard input')
keyboardTextDom.addEventListener('keydown', function(event) {
console.log(`用户按下按键${event.key}`)
})
keyboardTextDom.addEventListener('keyup', function(event) {
console.log(`用户抬起按键${event.key}`)
})
// 单选框/复选框事件
const radioDom = document.querySelector('.check input[type="radio"]')
const checkboxDom = document.querySelector('.check input[type="checkbox"]')
radioDom.addEventListener('change', function(event) {
console.log(`用户改变单选框值:${event.target.checked}`)
})
checkboxDom.addEventListener('change', function(event) {
console.log(`用户改变复选框值:${event.target.checked}`)
})
// 页面加载事件(一般用于window对象、document对象,也支持普通Dom元素使用)
// 注意:在window上添加load事件,代表整个页面资源加载完毕,包括图片、外联CSS、外链JS等
window.addEventListener('load', function() {
console.log('全部页面资源都加载完成了~~~')
})
// 注意:在document上添加DOMContentLoaded时间,代表HTML标签加载完成,不包括图片、外联CSS、外链JS等
document.addEventListener('DOMContentLoaded', function() {
console.log('页面HTML标签加载完成了~~~')
})
// document.documentElement代表html标签,只有html标签才进行了滚动操作,然后html标签需要这么写才能获取到,不要惊讶
window.addEventListener('scroll', function() {
console.log(`页面滚动坐标:${document.documentElement.scrollLeft} ${document.documentElement.scrollTop}`)
})
</script>
</body>
</html>
页面效果:
11.5.3.3、案例—拖拽案例
代码实例:
1、index.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>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="empty">
<!-- 默认情况下图片、链接等是可以拖拽的,但普通 div 需要显式设置 draggable="true" -->
<div class="fill" draggable="true"></div>
</div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
<div class="empty"></div>
<script src="script.js"></script>
</body>
</html>
2、script.js
/* 总结:拖拽工作流
1. 用户按住 `draggable=true` 的元素 → 触发 `dragstart`。
2. 开始移动鼠标 → 根据 `dragover` 的 `preventDefault` 寻找可放置目标。
3. 进入目标区域 → 触发 `dragenter`(高亮);离开目标区域 → `dragleave`(取消高亮)。
4. 在目标区域内松开鼠标 → 触发 `drop`(执行移动或数据存储)。
5. 无论成功与否 → 触发 `dragend`(清理状态)。 */
const fillEl = document.querySelector('.fill')
const emptyEls = document.querySelectorAll('.empty')
fillEl.addEventListener('dragstart', dragstart)
fillEl.addEventListener('dragend', dragend)
emptyEls.forEach(emptyEl => {
emptyEl.addEventListener('dragenter', dragenter)
emptyEl.addEventListener('dragover', dragover)
emptyEl.addEventListener('dragleave', dragleave)
emptyEl.addEventListener('drop', drop)
})
function dragstart() {
fillEl.classList.add('hold') // 给被拖拽元素加一个半透明边框等效果
// 隐藏被拖拽元素
setTimeout(() => fillEl.className = 'invisible', 0) // 加一个延迟到下一个宏任务,确保拖拽镜像已经生成后再隐藏原元素。
}
function dragenter() {
this.classList.add('hovered') // 高亮提示:可以松手
}
function dragover(event) {
event.preventDefault(); // 这行必不可少!告诉浏览器这是一个有效的放置目标
}
function dragleave() {
this.classList.remove('hovered'); // 离开时移除高亮
}
function drop() {
this.classList.remove('hovered') // 移除高亮
this.appendChild(fillEl) // 把被拖拽元素移动到当前容器中
}
function dragend() {
fillEl.className = 'fill' // 拖拽结束,恢复原始样式,让方块重新可见
}
3、style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
}
li {
list-style: none;
}
body {
background-image: linear-gradient(to bottom, #eafbff, #5290f9);
height: 100vh;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.empty {
width: 100px;
height: 100px;
border: 3px solid black;
margin: 30px;
background-color: white;
}
.hovered {
background-color: #333;
border-color: white;
border-style: dashed;
}
.fill {
width: 100%;
height: 100%;
background-color: pink;
}
.hold {
border: 3px solid #ccc;
}
.invisible {
opacity: 0;
}
页面效果:

11.5.3.4、常用事件汇总表格
说明:
- “大多数可视元素”指能够显示并接收鼠标/触摸事件的元素,不包括如
<head>、<title>等非可视元素。 - 对于键盘事件,若希望全局捕获按键,通常将监听器添加到
document或window上,因为只有获得焦点的元素才能触发键盘事件。 wheel事件可以在任意元素上触发,即使元素不可滚动;默认滚动行为只发生在可滚动区域(如页面主体或overflow容器),可通过preventDefault阻止默认滚动,实现自定义滚轮效果。- 拖拽事件的放置目标需要监听
dragover并调用preventDefault()才能允许 drop 事件触发。
表格:
| 分类 | 事件名称 | 触发时机 | 常见用途 | 适用对象 |
|---|---|---|---|---|
| 鼠标 | click |
单击鼠标左键 | 按钮点击、链接跳转 | 大多数可视元素(如 div、button、a 等) |
dblclick |
双击鼠标左键 | 编辑操作、放大视图 | 同上 | |
mousedown |
按下鼠标任意键 | 拖拽开始、绘画应用 | 同上 | |
mouseup |
释放鼠标按键 | 拖拽结束、释放操作 | 同上 | |
mousemove |
鼠标在元素上移动 | 绘图工具、鼠标跟随效果 | 同上 | |
mouseenter |
鼠标进入元素(不冒泡) | 悬停提示、菜单展开 | 同上(不冒泡,适合精确控制) | |
mouseleave |
鼠标离开元素(不冒泡) | 隐藏提示、菜单收起 | 同上 | |
mouseover |
鼠标进入元素或子元素(冒泡) | 复杂悬停交互 | 同上(注意冒泡影响) | |
mouseout |
鼠标离开元素或子元素(冒泡) | 复杂离开交互 | 同上 | |
contextmenu |
右键点击打开上下文菜单 | 自定义右键菜单 | 同上 | |
wheel |
鼠标滚轮滚动 | 缩放、自定义滚动行为 | 任何可视元素(鼠标指针位于元素上时触发,常用于 window 或可滚动容器) |
|
| 键盘 | keydown |
按下任意键 | 快捷键、游戏控制 | 可获得焦点的元素(input、textarea、button、[tabindex]),或 document、window(全局监听) |
keyup |
释放按键 | 表单输入验证、实时搜索触发 | 同上 | |
| 表单 | input |
输入框内容变化(实时) | 实时搜索、字数统计 | <input>、<textarea>、<select>(现代浏览器支持) |
change |
元素失去焦点且值变化 / 复选框等切换 | 表单验证、选项保存 | <input>、<textarea>、<select> |
|
submit |
提交表单 | 表单提交处理 | <form> |
|
reset |
重置表单 | 重置表单数据 | <form> |
|
focus |
元素获得焦点 | 高亮当前输入框 | 可获得焦点的元素(如 input、a、button、[tabindex]) |
|
blur |
元素失去焦点 | 输入验证、隐藏提示 | 同上 | |
select |
选中输入框中的文本 | 提示用户选中文本 | <input>、<textarea> |
|
| 窗口/文档 | load |
页面及所有资源加载完成 | 初始化页面、加载动画结束 | window(也可用于 <img>、<script> 等资源元素) |
DOMContentLoaded |
HTML 解析完成(无需等待样式、图片) | 提前执行脚本、操作 DOM | document |
|
resize |
窗口大小改变 | 响应式布局调整 | window |
|
scroll |
窗口或元素滚动 | 无限滚动、返回顶部按钮显示 | window、可滚动的元素(设置了 overflow: auto/scroll 的容器) |
|
beforeunload |
页面即将卸载 | 提醒用户保存更改 | window |
|
hashchange |
URL 哈希部分变化 | 单页应用路由 | window |
|
popstate |
浏览器历史记录变化(如前进/后退) | 单页应用导航 | window |
|
| 拖拽 | dragstart |
开始拖拽元素 | 记录拖拽数据 | 设置了 draggable="true" 的元素 |
drag |
拖拽过程中持续触发 | 实时反馈 | 同上 | |
dragend |
拖拽结束 | 清理状态 | 同上 | |
dragenter |
拖拽元素进入目标元素 | 高亮目标区域 | 作为放置目标的元素,需监听 dragover 并阻止默认行为 |
|
dragover |
拖拽元素在目标元素上悬停 | 阻止默认行为以允许放置 | 同上 | |
dragleave |
拖拽元素离开目标元素 | 取消高亮 | 同上 | |
drop |
在目标元素上释放鼠标(放置) | 处理放置的数据 | 同上,需监听 dragover 并阻止默认行为 |
|
| 触摸 | touchstart |
手指触摸屏幕 | 移动端交互开始 | 大多数可视元素(移动端) |
touchmove |
手指在屏幕上移动 | 滑动操作、手势识别 | 同上(移动端常需调用 preventDefault 阻止页面滚动) |
|
touchend |
手指离开屏幕 | 交互结束 | 同上 | |
touchcancel |
触摸被中断(如来电) | 异常处理 | 同上 | |
| 动画/过渡 | transitionend |
CSS 过渡完成后触发 | 执行后续动画 | 应用了 CSS transition 的元素(属性值变化且过渡结束后触发) |
animationstart |
CSS 动画开始 | 动画同步 | 应用了 CSS animation 的元素 |
|
animationend |
CSS 动画结束 | 清理状态、循环控制 | 同上 | |
| 剪贴板 | copy |
复制操作 | 自定义复制内容 | 大多数可视元素(常用于全局监听 document) |
cut |
剪切操作 | 自定义剪切行为 | 同上 | |
paste |
粘贴操作 | 处理粘贴的图片或文本 | 同上 |
11.5.4、事件对象event
11.5.4.1、概念
- 语法:监听到事件发生之后,程序会自动调用函数,可以在函数中传入一个形参event,这就是事件对象event,用于记录事件发生时的相关信息
- 用途:
-
判断用户的按键信息,比如监听密码输入框的按键按下事件,进而通过事件对象event获取按键信息,从而判断用户按下的是否是回车键,进而决定是否发送登录请求

-
判断鼠标点击的那个元素,比如一个列表展示多条数据,每一条数据后面都有删除按钮,当点击删除按钮的时候,我们可以监听点击事件,通过事件对象event.target找到那个删除按钮元素,通过在元素上记录的data-id信息,从而执行删除操作

-
11.5.4.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button class="btn">点击我</button>
<script>
const btnDom = document.querySelector('.btn')
btnDom.addEventListener('click', function() {
console.dir(event)
})
</script>
</body>
</html>
11.5.4.3、页面效果

11.5.5、事件流
11.5.5.1、概念
-
含义:事件完整执行过程中的流动路径。假设页面中有个div,当触发div的点击事件时,会经历两个阶段,分别是捕获阶段和冒泡阶段

-
捕获阶段(基本不用):从外向内的过程
-
冒泡阶段(开发常用):从内向外的过程。一般情况下,我们会利用事件冒泡特性,将事件处理维度拔高,以便统一处理,当然也是要判断事件event.target对象是否是预期的Dom对象,避免误处理。
11.5.5.2、事件捕获(很少使用)
11.5.5.2.1、概念
- 含义:从DOM的根元素开始去执行对应的事件
- 代码:
DOM对象.addEventListener(事件类型, 事件处理函数, 是否使用捕获机制)- 参数含义:
- 参数3:非必填。默认值是false,代表使用冒泡机制。填写为true代表使用捕获机制
- 参数含义:
11.5.5.2.2、代码示例
在事件冒泡的代码示例一致,这里不在赘述
11.5.5.3、事件冒泡
11.5.5.2.1、概念
- 含义:当一个元素触发事件后,会一次向上调用所有父级元素的同名事件。事件冒泡是默认存在的,不需要特殊传参
11.5.5.2.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 表头 -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>你好,春天~</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: rebeccapurple;
}
.son {
width: 100px;
height: 100px;
background-color: pink;
text-align: center;
line-height: 100px;
cursor: pointer;
}
.son:hover {
color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son">点击我</div>
</div>
<script>
const fatherDom = document.querySelector('.father')
const sonDom = document.querySelector('.son')
// 捕获阶段
document.addEventListener('click', function() {
console.log('捕获阶段:我是document')
}, true)
fatherDom.addEventListener('click', function() {
console.log('捕获阶段:我是父亲')
}, true)
sonDom.addEventListener('click', function() {
console.log('捕获阶段:我是儿子')
}, true)
// 冒泡阶段
sonDom.addEventListener('click', function() {
console.log('冒泡阶段:我是儿子')
})
fatherDom.addEventListener('click', function() {
console.log('冒泡阶段:我是父亲')
})
document.addEventListener('click', function() {
console.log('冒泡阶段:我是document')
})
</script>
</body>
</html>
11.5.5.2.3、页面效果
点击粉红色盒子后,控制台效果如下:

11.5.5.3、阻止事件传播(捕获+冒泡)
11.5.5.3.1、概念
-
含义:将事件限制在当前元素内,阻止继续传播,一旦阻止后,后面的捕获或者冒泡阶段都不会执行

-
代码:
event事件对象.stopPropagation() -
作用:我们在某些情况下需要阻止事件传播(捕获/冒泡)
11.5.5.3.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 表头 -->
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>你好,春天~</title>
<style>
.father {
width: 200px;
height: 200px;
background-color: rebeccapurple;
}
.son {
width: 100px;
height: 100px;
background-color: pink;
text-align: center;
line-height: 100px;
cursor: pointer;
}
.son:hover {
color: red;
}
</style>
</head>
<body>
<div class="father">
<div class="son">点击我</div>
</div>
<script>
const fatherDom = document.querySelector('.father')
const sonDom = document.querySelector('.son')
// 捕获阶段
document.addEventListener('click', function(event) {
console.log('捕获阶段:我是document')
}, true)
fatherDom.addEventListener('click', function(event) {
// 阻止事件传播,那么后面的捕获或者冒泡阶段都不会执行了
event.stopPropagation()
console.log('捕获阶段:我是父亲')
}, true)
sonDom.addEventListener('click', function(event) {
console.log('捕获阶段:我是儿子')
}, true)
// 冒泡阶段
sonDom.addEventListener('click', function(event) {
console.log('冒泡阶段:我是儿子')
})
fatherDom.addEventListener('click', function() {
console.log('冒泡阶段:我是父亲')
})
document.addEventListener('click', function() {
console.log('冒泡阶段:我是document')
})
</script>
</body>
</html>
11.5.5.3.3、页面效果
一旦阻止后,后面的捕获或者冒泡阶段都不会执行

11.5.6、阻止元素默认行为
11.5.6.1、概念
- 含义:在某些情况下,需要阻止默认行为的发生,比如阻止链接的跳转,表单域发请求
- 语法:
event事件对象.preventDefault()
11.5.6.2、代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>文章标题</h1>
<p>测试一下<a href="https://www.baidu.com">百度一下</a>测试一下</p>
<script>
document.addEventListener('click', function (event) {
if (
event.target.tagName === 'A' &&
event.target.href &&
!event.target.href.startsWith('https://XXX.com')
) {
const answer = confirm(`您确定需要跳转到该网址【${event.target.href}】`)
if(answer) {
window.open(event.target.href, '_blank');
}
event.preventDefault()
}
})
</script>
</body>
</html>
11.5.6.3、页面效果
点击网页中的超链接,如果域名不是我们网站的,那就需要询问用户是否要跳转到该网站,如果用户点击确定,那就新开一个页签用于展示超链接网站内容,否则不执行任何操作。当然当前网页的网址不会发生改变。
11.5.7、事件解绑
11.5.7.1、on方式绑定事件(了解即可)
注意: 对于同一个dom对象来说,on方式绑定事件可以被覆盖,所以直接赋值为null就可以实现时间的解绑,代码如下:

11.5.7.1、addEventListener方式绑定事件
注意: 仅支持解绑具名函数,不支持解绑匿名函数。并且支持通过第3个参数决定解绑捕获阶段(设置为true),还是冒泡阶段的事件(使用默认值false或者直接设置成false),默认解绑冒泡阶段的事件。代码如下:

11.5.8、事件委托
11.5.8.1、概念
- 含义:利用事件冒泡特点,为父元素注册事件,当我们触发元素的时候,事件会冒泡到父元素身上,从而触发父元素的事件(例如: 将click事件加到ul身上,那么所有li身上的click事件都会被ul接收到)
- 实现方式:通过
event.target.tagName可以获取真正触发事件的元素,然后判断是否是目标Dom元素,进而执行相关操作,当然也可以加其他判断条件哈
11.5.8.2、代码示例(标签切换—事件委托版本)
<!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>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul {
list-style: none;
}
a {
text-decoration: none; /* 去掉下划线 */
color: inherit; /* 继承父级颜色,避免默认蓝/紫 */
/* 可选:保留手型 cursor: pointer; 其实浏览器默认就是 pointer */
}
.goods {
margin: 50px 100px;
}
.goods .tab {
position: relative;
width: 300px;
height: 30px;
}
.goods .tab ul {
display: flex;
}
.goods .tab li {
width: 100px;
height: 30px;
border: 1px solid #ccc;
background-color: pink;
text-align: center;
line-height: 30px;
color: black;
font-family: '楷体';
}
.goods .tab li a.active {
color: red;
}
.goods .line {
transform: translateY(-4px);
width: 0px;
height: 2px;
background-color: red;
transition: all 0.3s;
}
.goods .content div {
width: 300px;
height: 100px;
text-align: center;
line-height: 100px;
font-size: 30px;
display: none;
background-color: goldenrod;
}
.goods .content div.active {
display: block;
}
.goods .content div.remen {
background-color: rgb(255, 0, 0, 0.5);
}
.goods .content div.yifu {
background-color: rgb(173, 255, 47, 0.5);
}
.goods .content div.jiushui {
background-color: rgb(138, 43, 226, 0.5);
}
</style>
</head>
<body>
<div class="goods">
<div class="tab">
<ul>
<li><a data-index="0" class="active" href="#">热门</a></li>
<li><a data-index="1" href="#">衣服</a></li>
<li><a data-index="2" href="#">酒水饮料</a></li>
</ul>
<div class="line">
</div>
</div>
<div class="content">
<div class="remen active">热门</div>
<div class="yifu">衣服</div>
<div class="jiushui">酒水饮料</div>
</div>
</div>
<script>
// tab栏文字滚动条
const tabLineDom = document.querySelector('.goods .tab .line')
// 启用标签和内容所用的class类
const ACTIVE_CLASS_NAME = 'active'
// 事件委托(本来需要监听a标签的移入事件,现在变成了监听ul标签的移入事件,这正是利用了mouseover会冒泡的特性)
const tabUlDom = document.querySelector('.goods .tab ul')
tabUlDom.addEventListener('mouseover', function(event) {
// 判断是否是我们所需元素
if(event.target.tagName === 'A' && event.target.dataset.index) {
const currentTabDom = event.target
const index = +currentTabDom.dataset.index
// 1、处理标签
// 移除其他标签已有效果
const oldTabActiveDom = document.querySelector('.goods .tab a.active')
if(oldTabActiveDom) oldTabActiveDom.classList.remove(ACTIVE_CLASS_NAME)
// 为当前标签添加效果
currentTabDom.classList.add(ACTIVE_CLASS_NAME)
// 2、处理tab栏文字滚动条
setTabLine(currentTabDom)
// 3、处理内容
// 移除其他内容已有效果
const contentActiveDom = document.querySelector('.goods .content div.active')
if(contentActiveDom) contentActiveDom.classList.remove(ACTIVE_CLASS_NAME)
// 为当前内容添加效果
document.querySelector(`.goods .content div:nth-child(${index + 1})`).classList.add(ACTIVE_CLASS_NAME)
}
})
// 2、初始化tab栏文字滚动条
setTabLine(document.querySelector('.goods .tab a.active'))
function setTabLine(currentActiveTabDom) {
const rect = currentActiveTabDom.getBoundingClientRect();
const leftDistance = rect.left + window.scrollX;
console.log(leftDistance)
tabLineDom.style.width = `${currentActiveTabDom.offsetWidth}px`
// 由于距离a标签最近的定位父级就是tab标签,所以才能使用offsetLeft
tabLineDom.style.transform = `translate(${currentActiveTabDom.offsetLeft}px, -4px)`
}
</script>
</body>
</html>
11.5.8.3、页面效果

更多推荐


所有评论(0)