JavaScript知识回顾
本文最后更新于 2024-12-08,文章内容可能已经过时。
JavaScript
js是运行在客户端(浏览器)的编程语言,可以在浏览器中实现交互特效,网页特效,表单验证等!
JavaScript特性
解释性语言
解释性语言就是读一行解释一行, 一般在开发JavaScript代码时候,计算机是无法直接认识的,需要经过编译或者解释后才能让计算机正确执行代码! 计算机只认识0101011001这样的二进制数字!
解释性语言:会将编写好的代码一行一行解释翻译成浏览器所认识的代码!编译性语言:会将编写好的代码完整过一遍后生成翻译文件,进行整体翻译!
单线程
单线程就是不能在同一个时间段内干多件事儿,只能同一时间内做一件事儿!
多线程就是可以在同一事件内处理很多事务!
JS三大部分
ECMAScript和DOM以及BOM
ECMAScript:是一种规范,用于制定js语法和规则,JavaScript是在ECMA规范上的一种实现!
DOM:是文档对象模型,是w3c的标准,提供了关于操作html元素dom的API方法!
BOM:是浏览器对象模型,是每个浏览器内部的一个实现,提供对浏览器操作的API方法!
ECMAScript
ECMAScript是JavaScript一套标准规范,ECMA会制定出方案结果,JS对方案进行的一个功能实现!
例如:循环 判断 变量声明 函数声明等基本语法!
字面量
字面量表示声明值的一部分,根据值的类型,有不同类型的字面量!
var age = 15;则15为数字字面量!
var name = "张三";则张三为字符串字面量!
变量
变量(容器):它可以将不同数据类型的值,存放到一个变量(容器)当中!
变量就是在程序中用来表示存储数据的!
声明变量
声明变量的方式有三种,分别为
varlet和const!
var name = "张三"
let name = "张三"
const name = "张三"这里以
var关键字举例说明:
var是一种声明变量的关键字,定义某个变量时,必须加入关键字进行声明,此处用来表示定义存储变量!
var 变量声明关键字!
name 变量名!
= "张三"; 对变量名进行赋值操作,并存储数据!
三者声明变量区别
var是属于早期的一种声明变量的一种方式,其中存在众多问题,例如变量提升,变量污染,重复定义等 !
变量提升:js引擎会在解析js代码时,将变量声明提取到作用域的最顶端,且初始值为undefind!
变量污染:var没有块级作用域,在块级作用域中定义的变量,依旧可以在上级或全局作用域中访问!
重复声明:var在同一个作用域内可以重复声明一个变量,会导致后面的变量值覆盖已有的变量值!
变量提升变量提升,就是js引擎在解析代码时,会将声明的所有变量提升在作用域顶部,这就意味着在变量赋值之前依旧可以访问变量,只不过该变量的值为undefind!console.log(name); // undefind var name = "张三"; console.log(name); // 张三变量污染变量污染, 就是var是属于函数作用域,不属于块级作用域,块级作用域包括(if for switch),这意味着,在块级内部定义的变量,在块级之外依旧可以访问!function demo(){ if(true){ // 块级内部 var name = "张三"; } // 块级外部 console.log(name); // 张三 }重复定义声明重复定义声明, 在代码中可以在同一个作用域下重复定义一个已存在声明变量的值!var age = 19; var age = 22; console.log(age); // 22
let 和 const
这两种
声明方式,是es6提出的标准,它们的出现就是为了解决var声明变量时所遗漏的一些问题 !
let:- 不能在
同一个作用域内重复定义变量! - 无法
在变量赋值前进行变量访问,不存在变量提升! - 属于
块级作用域,在块级之外无法访问,且不会对环境变量造成污染!
- 不能在
const:与
let关键字基本一致,则区别是,const是用来定义常量!- 常量在
声明变量时,必须有初始值! - 且
一旦被赋值,则无法在改变值!
- 常量在
变量的本质
定义变量的本质,就是
在内存中开辟一个空间,将变量值存储内存空间中!其
变量名则为内存空间的一个命名方式,通过命名可以获取对应空间中的存放数据!

命名规范
不能以关键字进行命名,例如let const if for等语法关键字!只能用下划线 字母 数字 $部分组成,不能以数字作为开头!首字母不能大写,驼峰命名,例如noProblem!
数据类型
在
js中数据类型为弱类型,弱类型就是根据赋值后来判定该值类型为某一个具体类型!
基本数据类型
基本类型: (字符串,布尔值,null,undefind,symbol,bigInt)
引用数据类型
引用数据类型: 也是复杂类型(Array_数组 Object_对象 Function_函数)
引用数据类型:在内存中会开辟一个新的空间用来存放这个地址,并将这个地址指向声明变量的变量名!
区别
基本数据类型:- 存放在
栈内存中,在内存中存放的是值,可以直接对值进行操作,和对比!
- 存放在
引用数据类型:- 存放在
堆内存中,在内存中会存放引用类型的地址,并将地址指向声明变量的变量名!
- 存放在
运算符
运算符包含(算数运算符和比较运算符以及赋值运算符和逻辑运算符)
算数运算符:+ - * / %(取模),算数优先级,先乘除后加减,若有括号先算括号里的表达式! %(取模) 就是两者相除剩余的余数!
比较运算符: 分为弱类型判断(== !=) 和 强类型判断(=== !==) 以及大小数值比较 (<= >=)!
赋值运算符:分为正常赋值( a = b ) 和 逻辑赋值( ??=, ||=, &&=, )
弱类型和强类型比较
弱类型:(== !=) 使用 弱类型判断 时,会做类型隐士转换,比如(“1” == 1)返回为 true,原因是,会将字符串1转换为 number类型后在进行判断!
强类型:(=== !==) 使用 强类型判断 时,类型不会做转换,("1"=== 1) 返回为 false,两者类型不一致,则结果不同!
逻辑赋值
逻辑与赋值(Logical AND Assignment)- &&=语法:x &&= y解释:如果x为真(truthy),则将y赋值给x。
逻辑或赋值(Logical OR Assignment)- ||=语法:x ||= y解释:如果x为假(falsy),则将y赋值给x。
逻辑空赋值(Logical Nullish Assignment)- ??=语法:x ??= y解释:如果x为null或undefined,则将y赋值给x。
类型转换
类型转换,通常就是将一种基本类型,转换成另一个基本类型,常用在
字符串转数字的场景!
"123" + 123 // 123123 不会进行算数运算,直接当作两个字符串进行拼接转换 字符串 为数字
+"123" + 1 // 124 在字符串前方加入 + 号会做隐式转换为数字作为
"-"号运算符时,例如:
"12" - 1 // 11 会默认将 字符串12 转换为数字12 在做运算条件判断
条件判断:就是根据表达式返回(true/false)分别进入不同分支代码块进行运行结果!
if语句
语法
if( true ){
// 条件为 true 时
} else {
// 条件为 false 时
}if(languageScore > mathScore){
// 语文 大于 数学时 进入该分支逻辑
console.log("语文成绩大于数学成绩!")
} else if(languageScore < mathScore){
// 语文 小于 数学时 进入该分支
console.log("语文成绩小于数学成绩!")
}switch语句
var languageScore = 50;
switch (languageScore) {
case 10:
console.log("匹配到 10!");
break;
case 20:
console.log("匹配到 20!");
break;
case 50:
console.log("匹配到 50!");
break;
default:
console.log("默认")
}循环语句
let __arr_ = [1, 43, 5, 65, 6, 3]
for (let i = 0; i < __arr_.length; i++) {
console.log("__arr_[i]" + __arr_[i]);
}冒泡排序
let arr = [1, 43, 5, 65, 6, 3]
// arr.length 长度为6 arr.length - 1 长度为5
// for循环 index 下标从0开始算. [1 的 index为0 到最后3 的index为5]
for (let i = 0; i < arr.length - 1; i++) {
// arr.length - i - 1
// [6-0-1 = 5]
// [6-1-1 = 4]
// [6-2-1 = 3]
for (let j = 0; j < arr.length - i - 1; j++) {
// arr[j] = 1;
// arr[j + 1] = 43;
// 判断前一个是否大于下一个数值,满足条件进行数据交换!
if (arr[j] > arr[j + 1]) {
let temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
console.log("arr", arr)函数
函数的作用就是将一些共用的业务逻辑进行抽离, 在不同的业务场景下进行函数调用处理!
封装冒泡函数案例
let __arr_ = [1, 43, 5, 65, 6, 3]
function sortArr(arr) {
let sortArr = [...arr];
for (let i = 0; i < sortArr.length - 1; i++) {
for (let j = 0; j < sortArr.length - i - 1; j++) {
if (sortArr[j] > sortArr[j + 1]) {
let temp = sortArr[j];
sortArr[j] = sortArr[j + 1];
sortArr[j + 1] = temp;
}
}
}
return sortArr;
}
let __result = sortArr(__arr_);
console.log("sort before", __arr_, "sort after", __result)
// 排序前[1,43,5,65,6,3] 排序后 [1,3,5,6,43,65]在
函数体内中包含,参数对象(arguments),动态绑定对象(this),返回值(return),作用域,以及原型链等相关知识!
函数声明方式
命名函数
function funName(){
}
let funName = function () {
}
匿名函数
匿名函数,就是没有命名的函数,常见的应用场景有,立即执行函数,回调函数,闭包,事件绑定函数!
立即执行函数:(function(){ console.log("函数体~") })()回调函数:[1,4,undefind,5,6,null].filter(function(item){ return !!item; })闭包:function closure(){ let name = "张三"; return function(){ console.log("name", name) return name; } }事件绑定:el.onclick = function(){ console.log("我被点击了~") }
立即执行函数
立即执行函数,就是创建一个独立作用域的可立即执行的函数体!
(function(a,b){
console.log(a + b)
})(1,2);注意: 立即执行函数,代码结束位置需要加入";"号,确保上一个代码段执行完毕!
参数传递
参数分为:形参和实惨!
形参: 是在声明函数的时候,定义的参数叫形参!
实参: 在函数调用时,传递的参数可称为实参数,实际传递的参数!
let funName = function (num1, num2) {
console.log("funName", num1, num2)
}
funName(12, 15);
在函数内部,有一个arguments参数对象,改对象包含一组参数列表!
arguments有自己的length,但是不是真正的数组,无法使用数组的方法来处理参数列表对象!
let funName = function (num1, num2) {
console.log("funName arguments", arguments, arguments.length)
// log funName arguments {"0":12,"1":15} 2
}
funName(12, 15);返回值
返回值,
就是函数在执行完毕时,向外部返回的一个结果!使用
return关键字可以返回一个结果!
let funName = function (num1, num2) {
console.log("funName arguments", arguments, arguments.length)
return num1 + num2;
}
let sumResult = funName(12, 15);
console.log("sumResult", sumResult)作用域
作用域就是一个变量可访问范围,通常在创建一个函数时,内部会有自己的作用域,除了自身作用域以外,还会包含父级作用域!
局部作用域:- 在
函数内部,或者块级儿内部定义的变量,且该变量仅能在局部作用域内生效!
- 在
全局作用域:- 在
全局代码中定义的变量,可供全局任何地方访问的变量就是属于全局作用域!
- 在
let anya = "全局作用域定义的变量";
function funName(){
// 局部作用域 父级
let name = "张三";
let age = 18;
console.log(`funName ${name} ${age}`)
return function (){
// 局部作用域 子级 解析函数时会创建父级作用域 并指向父级作用域
// 如果内部作用域没有定义该变量,且被引用时,则会查找父级作用域
console.log(`return fun ${name} ${age}`)
}
}作用域链
js引擎在解析函数时,会创建内部作用域,也会有一个父级作用域parentScope!
当在内部作用域内访问一个变量时,且该变量未在当前作用域中定义,则会向父级作用域中查找,直到全局作用域获取到为止
若都没有,则报错is not defind!
this动态绑定
this是函数体内特有的动态绑定对象,根据函数调用情况,返回不同this对象!
this有四种绑定方式分别为:默认绑定隐式绑定显示绑定new绑定!
默认绑定:- 在
全局中定义函数时,并在全局中调用该函数时,this会指向 window 全局对象!
- 在
隐式绑定:- 当
函数作为某个对象中的方法时,通过对象的方式来调用该函数,这时,this会指向该对象!
- 当
显示绑定:- 在
js中有三种方法可以修改函数的this指向,分别是apply call bind,该方法是函数中特有的,用来修改函数中的this指向!
- 在
new绑定:new是创建构造函数的关键字,创建构造函数时会创建一个空对象,并将函数的this指向这个空对象!
字符串
字符串就是被双引号引住的值,例如
"张三", "描述"!
let str = "Hello, World!";常用的方法
字符串的长度:length: "hello".length
查找字符串:charAt(index): 指定索引位置,返回索引位置所对应的字符!indexOf(substr, start): 检索字符串,根据指定字符,返回该字符的索引位置!console.log(str.indexOf("World")); // 输出: 7lastIndexOf(substr, start): 返回子字符串最后一次出现的位置。console.log(str.lastIndexOf("o")); // 输出: 8includes(searchString, position):判断字符串是否包含指定的子字符串,返回布尔值。console.log(str.includes("World")); // 输出: truestartsWith(searchString, position):判断字符串是否以指定的子字符串开始。console.log(str.startsWith("Hello")); // 输出: trueendsWith(searchString, length):判断字符串是否以指定的子字符串结束。console.log(str.endsWith("!")); // 输出: true
字符串提取:slice(start, end): 根据开始索引和结束索引,对字符串进行截取,不包含最后索引值!。"hello,world".slice(2,4); // llsubstring(start, end): 与slice相似,不支持负数!substr(start, length): 从索引开始位置截取,到指定长度!// 从开始索引第7个位置,截取5个字符串长度! let str = "Hello, World!"; console.log(str.substr(7, 5)); // 输出: "World"
字符串替换:replace(searchValue, replaceValue): 替换字符串中匹配的值(只替换第一个匹配项)。let str = "Hello, World!"; console.log(str.replace("World", "JavaScript")); // 输出: "Hello, JavaScript!"replaceAll(searchValue, replaceValue): 替换字符串中所有匹配的值。let str = "Hello, World! World!"; console.log(str.replaceAll("World", "JavaScript")); // 输出: "Hello, JavaScript! JavaScript!"
大小写转换:toUpperCase(): 将字符串转换为大写。toLowerCase(): 将字符串转换为小写。
去空白字符:trim(): 去除字符串两端的空白字符。trimStart(): 去除字符串开头的空白字符。trimEnd(): 去除字符串结尾的空白字符。
分割字符串split: 根据指定字符,将字符串进行分割,返回一个分割后的数组列表!let str = "Hello, World!"; console.log(str.split(",")); // 输出: ["Hello", " World!"]
连接字符串:concat(str1, str2, ...): 连接两个或多个字符串。
重复字符串repeat(count): 重复字符串指定的次数。
数组
数组是js中数据结构存储之一,它可以存储任意类型的值,包括基本类型,引用类型,Set,Map,等数据结构!
let testSet = new Set([1, '2', '5', 7])
let testFun = function () { }
let testArr = [testSet, testFun, 12, "张三", true, { name: "张三"} ]
console.log("testArr", testArr)操作数组方法
unshift: 在数组的第一项添加元素!shift:删除数组的第一项,并返回删除的元素!push: 在数组的最后一项添加元素!pop:删除数组最后一项,并返回删除的元素!indexOf:检索数组中的某一项,若找到则返回该元素在数组中的索引位置,否则返回-1!slice:截取根据起始索引和结束索引位置,对数组进行截取,不包含结束索引位置!splice:添加、删除或替换数组中的元素,会改变原始数组!语法:array.splice(start, deleteCount, item1, item2, ..., itemX)start: 必需。指定开始修改数组的索引位置。如果为负数,则从数组末尾开始计算。deleteCount: 可选。指定要删除的元素数量。如果省略或大于等于从start到数组末尾的元素数量,则删除从 start 到数组末尾的所有元素。item1, item2, ..., itemX:可选。要添加到数组中的新元素,从start位置开始插入。
includes: 判断数组中是否包含该元素,返回Boolean!concat: 将两个数组合并,返回一个新的数组长度!join: 将数组通过某个字符分割成字符串!
数组遍历方法
let arr = [1,43,45,56,66,3]
let obj = { name: "张三", age: 18 }for循环:for(let i = 0; i < arr.length; i++){ console.log("遍历的每一项 item", arr[i]) }forEach:forEach无法通过break或return提前终止循环。arr.forEach(function(item){ console.log("遍历的每一项 item", item) })for...in:主要用于
迭代对象的可枚举属性!for(let key in obj) { console.log("遍历的每一项 对象的属性", key) }for...of:循环用于遍历
可迭代对象(如数组、字符串、Map、Set等)的元素。for(let item of arr){ console.log("遍历的每一项 item", item) }
ES6新增的迭代方法
map:对数组元素进行
逻辑处理后,返回一个新的数组,不会影响原来的数组结构!let newArr = arr.map(function(item, index, sourceArr){ console.log(item, index, sourceArr) return item * 2; }) console.log("newArr", newArr)filter:对数组元素进行过滤, 返回一个
过滤后新的数组结构! 会过滤掉undefind和null的数据!// 返回一个 boolean,过滤数组中大于 10 的元素! let filterResult = arr.filter((item, index, sourceArr) => { return item > 10; }) console.log("filterResult", filterResult)some:判断该数组中,是否有
某些元素满足条件,满足则返回true, 否则返回false;let result = arr.some((item, index, sourceArr) => { return item === 3; }) console.log("result", result) // trueevery:判断数组中
所有元素满足该条件时,返回true, 否则返回false;let arr = [2,2,5,2,3,5]; let arr2 = [3,3,3,3,3]; arr.every(item => item === 2) // false arr2.every(item => item === 3); // truefind:返回满足条件的那一条数据!
let result = arr.find((item, index, sourceArr) => { return item === 3; }) console.log("result", result) // 3findIndex:返回满足条件的那一条数据的
index索引值!let result = arr.find((item, index, sourceArr) => { return item === 3; }) console.log("result", result) // index 5
对象
在
js中对象也是一种数据存储结构,它是以键值对形式存储数据,并通过键来获取值!
let obj = { name: "张三", age: 19 }对象的操作
根据
key来获取value:console.log("name", obj["name"], obj.name);设置对象属性值:
obj["name"] = "李四"; obj.name = "李四"
遍历对象属性
for(let key in obj){
console.log("obj[key]", obj[key])
}内置对象
内置对象就是js中预制的对象,像Date日期Math数学RegExp正则对象等 !
全局对象
Object: 是所有对象的基类,包含对象的一些操作方法,例如对象属性是否可枚举,可写,以及一些属性判断等方法!Function: 是所有函数的基类,提供了一些方法,如call(), apply(), bind()等。Array: 用于创建数组对象,包含一些数组的方法push(), pop(), slice(), splice()!String: 用于创建字符串对象,包含一些字符串相关的方法,如slice(), replace(), toUpperCase()等!Number: 用于创建数字对象,包含一些数字处理相关的方法,如toFixed() toPrecision()!Boolean: 用于创建布尔对象,提供布尔值相关的方法。Date: 用于处理日期和时间,提供日期和时间相关的方法,如getFullYear(), getMonth(), getDate()等!RegExp: 用于创建正则表达式对象,提供正则表达式相关的方法,如test(), exec()等!
错误对象
Error: 所有错误对象的基类。try { throw new Error("An error occurred"); } catch (e) { console.log(e.message); // 输出: "An error occurred" }TypeError: 表示类型错误。try { null.f(); } catch (e) { console.log(e instanceof TypeError); // 输出: true }ReferenceError: 表示引用错误。try { console.log(x); } catch (e) { console.log(e instanceof ReferenceError); // 输出: true }
数学对象
Math: 提供数学常数和函数,如Math.PI,Math.sin(),Math.cos(),Math.random()等。
console.log(Math.PI); // 输出: 3.141592653589793
console.log(Math.random()); // 输出: 0 到 1 之间的随机数Math.abs(): 绝对值,所有负数转换为正数!Math.max() Math.min(): 返回参数中最大值(max)或最小值(min)!Math.max(1,5,2) // 5 Math.min(1,5,2) // 1 // 如果没有参数 则是 +infinity 和 -infinityMath.floor() Math.ceil(): 向下取整(floor) 和 向上取整(ceil)!// 向下取整 Math.floor(3.2) // 3 Math.floor(-3.2) // -4 // 向上取整 Math.ceil(3.2) // 4 Math.ceil(-3.2) // -3Math.random(): 随机数 默认 >= 0 小于1// 10 ~ 20 随机数 function random( min, max ){ /* 先算乘除 在算加减 Math.random() 默认为 0 ~ 1 max - min = 10 Math.random() * 10 + min 10 */ return Math.floor(Math.random() * ( max - min ) + min); }
JSON对象
JSON: 提供将对象转换为 JSON 字符串和将 JSON 字符串解析为对象的方法,如JSON.stringify(),JSON.parse()!
let obj = { name: "Alice", age: 30 };
let json = JSON.stringify(obj);
console.log(json); // 输出: '{"name":"Alice","age":30}'
let parsed = JSON.parse(json);
console.log(parsed); // 输出: { name: "Alice", age: 30 }DOM
DOM(文档对象模型)document主要用来操作 html dom元素!
例如:对 元素的创建删除以及 元素属性的添加删除等一系列有关操作!
DOM 不属于javascript中的范畴,是独立的,是w3c标准提供的对html元素一系列操作的接口(api)!
文档中对应的属性
document: 获取整个html文档!- 获取文档中的父节点或子节点
parentNode: 获取元素的父节点!childNodes: 获取子节点!sibling: 获取同级节点!
获取元素节点属性
通过
nodeType属性可以获取元素节点所对应的属性常量值:
属性 |
数值 |
描述 |
|---|---|---|
文档节点(document) |
9 |
Node.DOCUMENT_NODE |
元素节点(element) |
1 |
Node.ELEMENT_NODE |
属性节点(attribute) |
2 |
Node.ATTRIBUTE_NODE |
文本节点(text) |
3 |
Node.TEXT_NODE |
文档片段(DocumentFragment) |
11 |
Node.DOCUMENT_FRAGMENT_NODE |
document.nodeType === Node.DOCUMENT_NODE // 9 true获取元素的方法

<div class = "box"></div>
<div class = "container"></div>
<div id = "app"></div>根据元素标签获取
指定
元素标签返回一组符合元素标签的元素节点集合[HTMLCollection[div]]!可以
实时获取元素的变化,若没有符合的元素,则返回一个空的集合!
document.getElementsByTagName("div") // HTMLCollection[div]获取元素集合中某个元素
document.getElementsByTagName("div")[0] // 获取集合中第一个元素节点根据className获取
document.getElementsByClassName("div.box") // HTMLCollection[div.box]根据 id 获取
document.getElementById("#app") // 返回一个唯一符合的元素节点使用query选择器
接受一个
css选择器,返回第一个符合的元素节点!
document.querySelector(".box") // className
document.querySelector("#box") // id
document.querySelector("div") // tagName使用queryAll选择器
与
querySelector类似,返回的是一个NodeList元素节点集合!
document.querySelectorAll(".box")创建元素与属性
创建和删除元素
使用
createElement方法来创建一个元素标签!
let divEl = document.createElement('div');
document.removeChild(divEl); // 删除指定元素创建元素属性
使用
createdAttribute方法来创建一个元素属性,并返回一个元素节点!使用
setAttributeNode给元素设置属性!
let idAttr = document.createAttribute('id');
divEl.setAttributeNode(idAttr);使用
setAttribute和getAttribute来设置元素的属性和获取元素的属性!
el.setAttribute('style', 'display: flex; flex-wrap: wrap; gap: 10px;');
console.log(el.getAttribute('style')); // display: flex; flex-wrap: wrap; gap: 10px;使用
removeAttribute可以删除指定的属性!
el.removeAttribute('style');追加子元素
使用
appendChild在父元素节点内部元素之后添加子元素节点!
let pEl = document.createElement("p");
pEl.innerText = "hello world~";
divEl.appendChild(pEl);使用
insertBefore在父元素节点内部元素之前添加子元素节点!
Element元素属性
元素属性就是,可通过Element对象直接获取或设置对应的属性内容!
| 属性 | 描述 | 获取方式 |
|---|---|---|
id |
获取元素属性id |
el.id |
className |
获取元素属性的class |
el.className |
classList |
获取元素属性的class集合 |
el.classList |
innerText |
设置或获取元素节点的内容content |
el.innerText获取 / el.innerText = '新的内容' |
innerHtml |
设置或获取元素节点中的html元素内容 |
el.innerHtml获取 / el.innerHtml = '<p>新的内容</p>' |
console.log("获取id", div.id); // div-id
console.log("获取class", div.className); // div-class
console.log("获取classList", div.classList); // DOMTokenList(1) ["div-class", value: "div-class"]添加或删除class属性
add属性可以添加一个class属性,remove可以删除一个class属性!
el.classList.add("new_class_name") el.classList.remove("new_class_name")
contains属性可以判断该元素中的class属性列表中是否包含,指定class选择器!
el.classList.contains('new_class_name');
toggle如果class列表中不存在,则添加,否则删除!
el.classList.toggle('new_class_name');innerHTML属性
innerHTML可以在页面中添加元素标签以及内容!
el.innerHTML = `<div style="width: 50px; height: 50px; background-color: red;"></div>`当
循环追加多个标签时,存在性能问题,导致页面渲染缓慢!拼接字符串会引起渲染性能问题!
let startTime = Date.now();
let div = document.querySelector('.test');
for(let i = 0; i < 1000; i++){
div.innerHTML += `<div style="width: 50px; height: 50px; background-color: red; margin-bottom: 10px;"></div>`
}
let endTime = Date.now();
console.log(`生成1000个div耗时${endTime - startTime}ms`); // 生成1000个div耗时372ms左右处理
性能问题,可以将添加的元素放在数组当中,通过join的方法,将数组转换为字符串,最后赋值与innerHTML元素!
let startTime = Date.now();
let arr = [];
let div = document.querySelector('.test');
for(let i = 0; i < 1000; i++){
arr.push(`<div style="width: 50px; height: 50px; background-color: red; margin-bottom: 10px;"></div>`);
}
div.innerHTML = arr.join('');
let endTime = Date.now();
console.log(`生成1000个div耗时${endTime - startTime}ms`); // 生成1000个div耗时1ms相对于
createElement方法创建元素,innerHTML采用数组方式来生成元素时,其效率更高!
获取元素的位置
包含
元素的宽高,网页可见宽高以及body的宽高,用来配合元素在页面中的位置计算!

元素偏移量(offset)
offset系列
offset(偏移量):
获取
元素的自身的宽高还有获取当前
元素的距离定位的父元素距离位置!
常用的属性
| 属性 | 描述 |
|---|---|
el.offsetParent |
获取带有定位(绝对定位 和 相对定位)的父元素,如果没有定位,则获取body! |
el.offsetLeft |
获取元素距离带有定位的父元素的左侧距离 |
el.offsetTop |
获取元素距离带有定位的父元素的顶部距离 |
el.offsetHeight |
获取元素自身的高度,内边距 边框 以及内容区的高度! |
el.offsetWidth |
获取元素自身的宽度,内边距 边框 以及内容区的宽度! |
offsetParent: 带有定位的父元素,没有则获取 body!
parentNode: 不管父元素有没有定位,都是最近一层上级元素!
offset 和 style 的区别
offset:是只读属性,无法进行赋值,只能用来获取元素的相关属性!
style:是行内样式,只能获取和修改元素的行内样式!
获取在盒子内部的x和y坐标
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>获取鼠标在盒子内部的坐标</title>
<style>
.box{
width: 200px;
height: 200px;
background-color: #ccc;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box');
box.addEventListener('click', function(event){
/* const x = event.clientX - box.offsetLeft;
const y = event.clientY - box.offsetTop; */
const x = event.pageX - box.offsetLeft;
const y = event.pageY - box.offsetTop;
console.log(`鼠标在盒子内部的坐标为:(${x}, ${y})`);
})
</script>
</body>
</html>
拖动元素案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>拖拽盒子</title>
<style>
:root, body {
width: 100%;
height: 100%;
}
:root {
margin: 0;
padding: 0;
}
.box {
width: 500px;
height: 300px;
background-color: #fcf;
border-radius: 15px;
box-shadow: 0 0 10px #999;
position: fixed;
top: 50%;
left: 50%;
/* margin: auto; */
transform: translate(-50%, -50%);
cursor: move;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
const box = document.querySelector('.box');
// 当鼠标按下时
box.addEventListener('mousedown', function(event) {
const innerX = event.pageX - box.offsetLeft;
const innerY = event.pageY - box.offsetTop;
// 当鼠标在 文档页面 上移动时
document.addEventListener('mousemove', move);
// 当鼠标在 文档页面 上抬起时
document.addEventListener('mouseup', up);
function move(event) {
console.log(box.offsetLeft)
box.style.left = event.pageX - innerX + 'px';
box.style.top = event.pageY - innerY + 'px';
}
function up() {
document.removeEventListener('mousemove', move);
document.removeEventListener('mouseup', up);
}
});
</script>
</body>
</html>
innerX和innerY是鼠标在box元素内部触发事件时到左侧的一个距离!
move触发移动事件时,需要重新计算出,box元素的距离body top和left值!
计算规则:(pageX, pageY or clientX ,clientY )获取鼠标距离左侧和顶部的坐标值(x,y)
减去,鼠标距离box元素的内部坐标值(x,y)!
内部鼠标距离元素 left 和 top 的距离,通过 pageX - offsetLeft 和 pageY - offsetTop!
client系列
获取元素的
边框大小,以及元素的大小!
| 属性 | 描述 |
|---|---|
el.clientLeft |
返回左边框的大小! |
el.clientTop |
返回上边框的大小! |
el.clientWidth |
返回元素的宽度,包含 padding 和 内容的宽度,不包含border! |
el.clientHeight |
返回元素的高度,包含 padding 和 内容的高度,不包含border! |
scroll系列
可以获取元素滚动时的距离!
| 属性 | 描述 |
|---|---|
e.scrollTop |
返回上层被滚动隐藏元素的距离! |
e.scrollLeft |
返回左侧被滚动隐藏元素的距离! |
e.scrollWidth |
返回自身实际的宽度,不包含border! |
e.scrollHeight |
返回自身实际的高度,不包含border! |

在窗口下滚动被卷去的元素距离
window.pageXOffset:获取在窗口内滚动被卷去的左侧距离!
window.pageYOffset:获取在窗口内滚动被卷去的顶部距离!
兼容问题 : >= ie9否则使用document.body.scrollTop如果是在
元素内部滚动,请使用el.scrollTop和el.scrollLeft!
滚动案例
<!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;
box-sizing: border-box;
}
div:not(.box, .back-top, .top) {
width: 85%;
border-radius: 10px;
margin: 15px auto;
text-align: center;
font-weight: bold;
font-size: 24px;
color: white;
}
div.box {
position: relative;
}
div.header {
height: 100px;
line-height: 100px;
background-color: cadetblue;
}
div.banner {
height: 400px;
line-height: 300px;
background-color: darkcyan;
}
div.main {
height: 1200px;
line-height: 800px;
background-color: darkslategray;
}
.back-top {
width: 50px;
height: 100px;
border: 1px solid red;
position: absolute;
top: 300px;
right: 4.6%;
background-color: tomato;
border-radius: 5px;
font-size: 14px;
font-weight: bold;
color: #fff;
line-height: 100px;
text-align: center;
}
.back-top .top {
cursor: pointer;
opacity: 0;
transition: all 0.3s ease;
}
</style>
</head>
<body>
<div class="box">
<div class="header">header</div>
<div class="banner">banner</div>
<div class="main">main</div>
<div class="back-top">
<div class="top">Top</div>
</div>
</div>
<script>
/*
1. 判断 header 是否在可视范围内
2. 设置 backTop 为 fixed 重新计算 top 值
*/
const header = document.querySelector(".header");
const banner = document.querySelector(".banner");
const main = document.querySelector(".main");
const backTop = document.querySelector(".back-top");
const headerTop = header.offsetTop;
const bannerTop = banner.offsetTop;
const mainTop = main.offsetTop;
const backTopOffset = backTop.offsetTop - bannerTop;
document.addEventListener("scroll", function (e) {
if (window.pageYOffset >= bannerTop) {
console.log("header 隐藏");
backTop.style.position = "fixed";
backTop.style.top = backTopOffset + "px";
} else {
console.log("header 显示");
backTop.style.position = "absolute";
backTop.style.top = 300 + "px";
}
// 滚动到主内容区域
if (window.pageYOffset >= mainTop) {
console.log("main 显示");
backTop.children[0].style.opacity = 1;
} else {
console.log("main 隐藏");
backTop.children[0].style.opacity = 0;
}
});
backTop.addEventListener("click", function (e) {
window.scrollTo({
top: 0,
left: 0,
behavior: "smooth",
});
})
</script>
</body>
</html>总结
offset和client以及scroll都可以获取元素本身的宽高,除了offset获取宽高包含boder以外,其它两个都不包含border!
设置css样式
使用
setAttribute来设置样式:el.setAttribute("style", "width: 120px; height:120px; background: red;")使用
style属性来设置:el.style.width = "120px"; el.style.color = "red";使用
cssText属性来设置:el.style.cssText = "width: 120px;", + "height: 120px;", + "background: red;",
事件操作
事件就是一种在网页元素中的操作行为,例如鼠标事件,滚动事件, 键盘事件等!
鼠标事件:常见的有点击事件,滚轮事件,以及鼠标移入移出的事件!
键盘事件:就是键盘的按键触发事件的一种行为操作!
let btn = document.querySelector(".btn");
btn.onclick = function( e ){
console.log("触发点击事件!", e)
}以上就是一个
按钮点击事件的案例!
注册事件
注册事件,就是给元素添加事件的方式,一种是传统方式注册,一种是对事件的一个监听!
传统方式注册
在元素上
通过事件绑定属性来注册一个事件:<button onclick = "alert("hello")"></button>在j
s代码中通过元素对象,获取事件属性并赋值与函数来注册事件:el.onclick = function(){ }
传统事件注册,只能给元素绑定一个事件,若出现多次绑定的情况,则后面的绑定事件会覆盖之前的绑定!
btn.onclick = function( e ){
console.log("触发点击事件!", e)
}
btn.onclick = function( e ){
console.log("我会覆盖之前的事件绑定", e)
}事件监听器
事件监听器就是通过addEventListener该方法来注册一个事件!
addEventListener:该方法存在兼容性问题,IE9之前不支持,添加事件需使用attachEvent(非标准,生产环境不推荐使用);
参数:
事件监听的类型(
type):click mouseover mouseout等...,这里不需要写on!事件监听的回调函数(
callback): 当触发事件时,该回调函数被执行!
el.addEventListener('click', function(e){
console.log(e.target);
})
el.addEventListener('click', function(e){
console.log(e.target);
})给某个元素
添加事件监听!这里同一个元素
可以添加多个事件监听,且依次执行!
attachEvent事件注册
事件类型,需要补充on语法!
el.attachEvent('onclick', function(e){
console.log(e.target);
})删除事件
删除事件 使用该方法 removeEventListener,可以对事件进行解绑和删除!
传统
事件绑定的删除方式:el.onclick = null;使用
监听器绑定事件后进行解绑:// 绑定监听的函数 let bindFunction = functon(){ } el.addEventListener("click", bindFunction); // 解除绑定函数 el.removeEventListener("click", bindFunction);使用
attchEvent方式绑定的事件进行解绑:let bindFunction = functon(){ } el.attachEvent("onclick", bindFunction); // 解除绑定函数 el.detach("onclick", bindFunction);
DOM事件流
事件流就是一个传播过程,当给元素绑定事件时会有以下流程:
捕获阶段: 由根元素到子元素的一个过程,直到发现被绑定事件的子元素!
冒泡阶段: 由子元素到根元素的一个过程,直到根元素为止!


事件捕获
addEventListerer第三个参数为Boolean,为true时,则为捕获阶段,为false时或默认时,则为冒泡阶段!
捕获阶段:事件的执行顺序,会从根元素开始, 从外而内,进行事件触发执行!
<div class="parent">
<div class="sub">sub</div>
</div>let parent = document.querySelector('.parent');
let sub = document.querySelector('.sub');
parent.addEventListener('click', function(e){
console.log("parent click");
}, true);
sub.addEventListener('click', function(e){
console.log("sub click");
},true);
// log parent click
// log sub click冒泡阶段
冒泡阶段: 事件的执行顺序,会从子元素开始,从内而外,进行事件触发执行!
设置冒泡行为,第三个参数为false时,或者默认不传时,则为冒泡!
let parent = document.querySelector('.parent');
let sub = document.querySelector('.sub');
parent.addEventListener('click', function(e){
console.log("parent click");
}, false);
sub.addEventListener('click', function(e){
console.log("sub click");
},false);
// log sub click
// log parent click事件对象
事件对象(event),就是每一个事件类型所触发后产生的一个对象!
鼠标事件触发后,事件对象会包含该鼠标对象的信息!
键盘事件触发后,事件对象会包含改键盘对象的信息!
el.onclick = function ( event ) {
console.log("包含了click点击事件的信息", event);
}
event是一个对象,包含了,当前触发事件的一系列信息!
注意: event在 ie678里存在兼容问题!
可以通过window.event来获取!
el.onclick = function ( event ) {
console.log("包含了click点击事件的信息", event || window.event);
}this 绑定对象 与 el.target对象的区别
this是绑定对象,是当前绑定事件的元素对象!
el.target是获取返回触发事件的元素对象信息!
<ul>
<li>sub</li>
<li>sub</li>
<li>sub</li>
<li>sub</li>
<li>sub</li>
</ul>
<script>
let ul = document.querySelector('ul');
// this = ul 当前绑定元素
// el.target = 触发事件的元素 比如我点击了 li 则 li为触发元素的对象!
ul.addEventListener('click', function(e){
console.log("ul click", e.target, this);
})
</script>
el.target是有兼容问题,在ie678下可以通过el.srcElement来获取
阻止默认事件
阻止默认事件(preventDefault方法),默认事件就是某个元素在触发事件时,一些默认行为操作!
表单提交 button type="submit",提交后,会默认提交以及刷新浏览器的行为!
<form action="http://www.baidu.com">
<button type="submit">提交</button>
</form>
<script>
let btn = document.querySelector('button');
btn.addEventListener('click', function(e){
e.preventDefault(); // 阻止 默认提交行为操作 以及浏览器刷新操作!
console.log('提交');
})
</script>
preventDefault 兼容问题:
ie678请使用:e.returnValue!这是一个属性不是一个方法!
btn.onclick = function(e){
// e.preventDefault(); // 兼容问题
// e.returnValue;
return false;
}
// 三种方式都可以阻止默认事件阻止冒泡事件
冒泡事件,从子元素开始,向上层逐个事件触发,为了保证事件触发的单一行,需要进行冒泡行为阻止!
stopPropagation该方法,可以帮我们阻止事件传播过程!
el.onclick = function(e){
e.stopPropagation(); // 兼容问题
e.cancelBubble = true; // 兼容 ie678
}事件委托
事件委托,就是不在子元素上进行一个一个事件绑定,通过事件传播的行为,将事件绑定到父元素上,来操作子元素!
<ul>
<li>1. 事件委托</li>
<li>2. 事件委托</li>
<li>3. 事件委托</li>
<li>4. 事件委托</li>
<li>5. 事件委托</li>
</ul>
<script>
let ul = document.querySelector('ul');
ul.addEventListener('click', function(e){
console.log(e.target.innerText);
})
</script>事件对象中常见的属性和方法

鼠标事件
事件类型有很多种,鼠标移入元素 移出元素 点击元素 以及 触发焦点 和 失去焦点事件等类型!
| 事件类型 | 事件描述 |
|---|---|
onclick |
鼠标点击左键事件 |
onmouseenter |
鼠标移入自身元素时触发事件,如果自身元素下有子元素,则移入子元素时,不触发,因为没有冒泡! |
onmouseleave |
鼠标移出事件,与enter相似 |
onmouseover |
鼠标经过该元素时频繁触发事件,如果自身元素下有子元素,则鼠标移入时依旧触发事件! |
onmouseout |
鼠标移出事件,与over相似 |
onfocus |
鼠标触发焦点事件 |
onblur |
鼠标失去焦点事件 |
onmousemove |
鼠标移动事件 |
onmouseup |
鼠标按键抬起触发事件 |
onmousedown |
鼠标按键按下触发事件 |
contentmenu |
鼠标右键按下触发事件 |
selectstart |
鼠标开始选择时触发事件 |
ondbclick |
鼠标双击时触发事件操作 |
禁止鼠标右键菜单
document.addEventListener("contextmenu", function(e){
e.preventDefault();
console.log("contextmenu", e.target);
})禁止文字选择
document.addEventListener("selectstart", function(e){
e.preventDefault();
console.log("contextmenu", e.target);
})鼠标事件对象
鼠标事件对象
event, 当鼠标事件触发时,产生的MouseEvent事件对象,包含关于鼠标相关属性信息!比如,鼠标的
坐标位置等相关信息!
| 属性 | 描述 |
|---|---|
e.clientX |
当前鼠标指针相对于 body 可视窗口 x 坐标! |
e.clientY |
当前鼠标指针相对于 body 可视窗口 y 坐标! |
e.pageX |
当前鼠标指针相对于 document(文档 包含滚动区域的 x 坐标! |
e.pageY |
当前鼠标指针相对于 document(文档) 包含滚动区域的 y 坐标! |
e.screenX |
当前元素相对于 电脑屏幕 x 坐标! |
e.screenY |
当前元素相对于 电脑屏幕 y 坐标! |
e.offsetX |
当前鼠标指针相对于当前元素的left距离! |
e.offsetY |
当前鼠标指针相对于当前元素的top距离 ! |


鼠标事件跟随案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>鼠标跟随案例</title>
<style>
body{
height: 3000px;
}
.cursor-box{
width: 30px;
height: 30px;
background-color: #f00;
position: relative;
cursor: pointer;
box-shadow: 0 0 10px #000;
border-radius: 20px;
}
</style>
</head>
<body>
<div class="cursor-box"></div>
<script>
const cursorBox = document.querySelector('.cursor-box');
document.addEventListener('mousemove', (event) => {
cursorBox.style.left = event.pageX + 'px';
cursorBox.style.top = event.pageY + 'px';
});
</script>
</body>
</html>案例

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
/* 设置边框盒 外边距, 内容等的宽高自动计算,加上内边距和边框*/
box-sizing: border-box;
}
.container{
width: 100%;
height: 100vh;
border: 1px solid #000;
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: center;
align-items: center;
}
.container div{
width: 100px;
height: 100px;
background-color: sandybrown;
text-align: center;
line-height: 100px;
font-size: 14px;
font-weight: bold;
border-radius: 25px;
transition: all .5s linear;
}
.container div:hover{
transform: scale(1.1);
cursor: pointer;
}
.container div:nth-child(2n){
background-color: skyblue;
}
</style>
</head>
<body>
<div class="container">
<div>click</div>
<div>mouseover</div>
<div>mouseout</div>
<div>mousedown</div>
<div>mouseup</div>
<div>mousemove</div>
</div>
<div class="test"></div>
<script>
let events = ['click', 'mouseover', 'mouseout', 'mousedown', 'mouseup', 'mousemove'];
let container = document.querySelector('.container');
let els = document.querySelectorAll('.container div');
for(let i = 0; i < events.length; i++){
let event = `on${events[i]}`;
els[i][event] = function(){
console.log(event);
}
}
</script>
</body>
</html>键盘事件
| 事件 | 描述 |
|---|---|
onkeyup |
按键抬起时触发事件 |
onkeydown |
按键按下时触发事件 不区分大小写! |
onkeypress |
按键按下时触发事件 不识别 ctrl shift 箭头,区分大小写! |
键盘事件对象
event键盘事件对象,就是当触发键盘行为操作时,会生成一个键盘对象(keybordEvent)
根据keyCode来判断对应的按键值
keyCode返回一个ASCLL码值,每一个按键,且对应一个相应的值!
表单事件
| 事件 | 描述 |
|---|---|
submit |
当表单元素提交时,触发该事件! |
reset |
当表单元素被重置时,触发该事件! |
change |
当表单元素发生改变的时候触发该事件! |
input |
当表单元素输入内容时触发该事件! |
窗口事件
| 事件 | 描述 |
|---|---|
load |
当页面以及所有资源加载完毕时触发该事件! |
unload |
当用户离开页面时触发该事件! |
scroll |
当页面滚动时触发该事件! |
resize |
当窗口或者元素大小发生改变时触发该事件! |
触摸事件
| 事件 | 描述 |
|---|---|
touchstart |
当用户开始触摸屏幕时触发。 |
touchmove |
当用户触摸屏幕并移动时触发。 |
touchend |
当用户停止触摸屏幕时触发 |
touchcancel |
当触摸被中断时触发 |
拖拽事件
拖拽元素时,需要
给拖拽元素增加拖拽属性,才可以对元素进行拖拽行为!
draggable="true"
<div id="draggableid" class="drag-box" draggable="true">拖拽元素</div>
<!-- 放置目标区域 -->
<div class="placement-box">请将红色的框拖拽到此处</p>| 事件 | 描述 |
|---|---|
dragstart |
当用户开始拖动元素时触发。此事件通常用于初始化拖拽数据,如设置 dataTransfer 对象的数据类型和数据值 |
drag |
当元素被拖动时持续触发。此事件可以用于实时更新拖拽过程中的状态,例如显示拖拽进度。 |
dragenter |
当被拖动的元素进入目标元素时触发。此事件用于确定目标元素是否可以接受拖拽的数据 |
dragover |
当被拖动的元素在目标元素上移动时持续触发。此事件用于更新拖拽过程中的视觉效果,例如改变目标元素的样式 |
dragleave |
当被拖动的元素离开目标元素时触发。此事件用于重置目标元素的样式 |
drop |
当用户释放鼠标按钮并完成拖放操作时触发。此事件用于处理拖放的数据,例如将拖动的元素插入到目标元素中 |
dragend |
当拖拽操作结束时触发,无论是否成功放下。此事件用于清理拖拽过程中的状态,例如重置拖拽元素的样式 |
拖拽案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>拖拽事件</title>
<style>
div{
padding: 15px;
}
.drag-box {
width: 100px;
height: 100px;
background-color: #f00;
color: #fff;
cursor: move;
border-radius: 10px;
}
.placement-box {
margin-top: 15px;
height: 300px;
border-radius: 10px;
background-color: #4fc3f7;
}
</style>
</head>
<body>
<div id="draggableid" class="drag-box" draggable="true">拖拽元素</div>
<!-- 放置目标区域 -->
<div class="placement-box">请将红色的框拖拽到此处</p>
<script>
const draggable = document.querySelector(".drag-box");
const placement = document.querySelector(".placement-box");
// 开始拖拽
draggable.addEventListener("dragstart", function (event) {
console.log("开始拖拽",event);
event.dataTransfer.setData("text/plain", event.target.id);
event.dataTransfer.effectAllowed = "move";
});
// 拖拽过程中持续触发
draggable.addEventListener("drag", function (event) {
// console.log("正在拖动...");
});
// 进入目标元素时触发
placement.addEventListener("dragenter", function (event) {
event.preventDefault();
console.log("进入目标元素",event);
event.target.classList.add("dragover");
});
// 在目标元素上移动时持续触发
placement.addEventListener("dragover", function (event) {
event.preventDefault();
// console.log("在目标元素上移动",event);
});
// 离开目标元素时触发
draggable.addEventListener("dragleave", function (event) {
event.target.classList.remove("dragover");
// console.log("离开目标元素");
});
// 放下元素时触发
placement.addEventListener("drop", function (event) {
event.preventDefault();
console.log("放下元素",this, event.target);
const id = event.dataTransfer.getData("text/plain");
const draggableElement = document.getElementById(id);
event.target.appendChild(draggableElement);
event.target.classList.remove("dragover");
});
// 拖拽结束时触发
draggable.addEventListener("dragend", function (event) {
console.log("拖拽结束");
});
</script>
</body>
</html>事件顺序: 拖拽事件有特定的触发顺序,通常是dragstart -> drag -> dragenter -> dragover -> drop -> dragend。阻止默认行为: 在dragover和drop事件中,需要调用event.preventDefault()来阻止默认的拖拽行为(如打开文件)。数据传递: 在dragstart事件中,可以使用dataTransfer.setData方法传递数据,在drop事件中可以使用dataTransfer.getData方法获取数据浏览器兼容性: 虽然大多数现代浏览器
BOM
BOM(浏览器对象模型) 主要是浏览器内一些相关的api操作!
例如: 对 浏览器窗口对一些操作,如果页面跳转历史记录(history), location, navgitor,本地存储(sessionStorage localStorage cookie)等!

BOM缺乏标准规范,JS的标准规范是由ECMA实现的,DOM 的标准规范是由W3C实现的,而BOM最早是由Netscape浏览器标准的一部分!
BOM是浏览器厂商自己定义的标准,兼容性比较差!
window全局对象
在
浏览器中,window是一个顶层对象也是全局对象,可以通过该对象来访问一些基本的webapi!所有定义在
全局的变量和函数,都会被绑定在顶层对象window中!
window.alert(123) // alert(123) window可以省略!注意:
window对象中有一个特殊的属性,window.name,该name属性,是在一开始初始化时,就已经存在的属性,且默认值为" "!
window常见的事件
页面加载事件
onload: 当页面所有资源以及dom元素加载完毕时调用该回调函数!window.onload = function(){ console.log("页面所有资源以及dom元素以加载完毕!") } window.addListenerEvent("load", function(){ console.log("页面所有资源以及dom元素以加载完毕!") })DOMContentLoaded: 当所有dom元素加载完毕时调用该回调函数,不包含图片 flash 以及css样式表资源!ie9+ 支持!- 好处是,
不用等待其他外部引用资源加载完毕时,处理逻辑操作,当外部资源体积大且加载缓慢,则只需要处理dom时可以使用该事件!
document.addListenerEvent("DOMContentLoaded", function(){ console.log("所有的 dom 元素加载完毕时 调用回调函数, 不包含外部资源!") })pageshow: 在页面显示时加载事件,无论页面是否缓存!a 连接跳转返回当前页时触发事件刷新页面或者强制刷新触发事件pageshow会在load 事件后触发e.persisted可以判断该是否在缓存中的页面中触发!火狐浏览器,在跳转页面并通过浏览记录返回时,会对原有的页面进行缓存,缓存后的页面不会触发onload事件!
window.addListenerEvent("pageshow", function(e){ console.log("在 onload 事件后触发,无论页面是否有缓存!") })
窗口以及元素大小监听事件
resize事件,当窗口或者元素大小发生变化时,触发该事件!
window.onresize = function(e){
console.log("窗口大小发生改变!")
}定时器
定时器就是根据指定时间去执行一段逻辑!
setTimeOut
根据
指定时间,在时间结束后,执行回调函数!单位为
毫秒!第一个参数,
回调函数,第二个参数,指定的时间单位(毫秒)!
setTimeout(function(){
console.log("3秒钟会执行此回调函数!")
},3000)setInterval
根据
指定时间,循环间隔执行回调函数!单位为
毫秒!第一个参数,
回调函数,第二个参数,指定的时间单位(毫秒)!
setInterval(function(){
console.log("每此间隔3秒钟执行回调函数!")
},3000)清除定时器
清除定时器,在一定时机内,将定时器进行清除,结束回调函数的执行行为!
clearInterval是清除定时器(Interval)的一个函数,且参数为定时器所返回的id值!
clearTimeout是清除定时器(Timeout)的一个函数,且参数为定时器所返回的id值!
let startTime = Date.now();
setTimeout(()=>{
let endTime = Date.now();
console.log(`执行时间:${endTime - startTime}ms`);
// 5s中清除定时器setInterval
clearInterval(intervalId);
},5000)
let intervalId = setInterval(() => {
console.log("每次间隔2s");
}, 2000);倒计时案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>定时器</title>
<style>
.timer-box {
height: 90vh;
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
}
.timer-box div {
width: 50px;
height: 50px;
background-color: rgba(0, 0, 0, 0.6);
text-align: center;
line-height: 50px;
font-weight: bold;
color: #fff;
}
</style>
</head>
<body>
<center><h2>倒计时</h2></center>
<div class="timer-box">
<div class="hour">1</div>
<div class="minute">2</div>
<div class="second">3</div>
</div>
<script>
const hour = document.querySelector(".hour");
const minute = document.querySelector(".minute");
const second = document.querySelector(".second");
const futureTime = new Date("2024-11-27 15:00:00").getTime();
// 防止一开始页面加载时,时间显示为空白
countdown();
let timerId = setInterval(countdown, 1000); // 每秒执行一次倒计时
// 时间单位换算
// 1秒 = 1000毫秒
// 1分钟 = 60秒 * 1000毫秒
// 1小时 = 60分钟 * 60秒 * 1000毫秒
// 1天 = 24小时 * 60分钟 * 60秒 * 1000毫秒
// 1周 = 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
// 1月 = 30天 * 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
// 1年 = 365天 * 30天 * 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
function countdown() {
const nowTime = new Date().getTime();
const gapTime = (futureTime - nowTime) / 1000; // 未来时间 - 现在时间 = 剩余时间
// 3600 = 1000 * 60秒 * 60分 1小时
const hourGap = Math.floor(gapTime / 3600); // 剩余小时
const minuteGap = Math.floor((gapTime - hourGap * 3600) / 60); // 剩余分钟
const secondGap = Math.floor(gapTime - hourGap * 3600 - minuteGap * 60); // 剩余秒
hour.textContent = hourGap < 10 ? "0" + hourGap : hourGap;
minute.textContent = minuteGap < 10 ? "0" + minuteGap : minuteGap;
second.textContent = secondGap < 10 ? "0" + secondGap : secondGap;
if (gapTime <= 0) {
clearInterval(timerId);
hour.textContent = "00";
minute.textContent = "00";
second.textContent = "00";
}
}
</script>
</body>
</html>时间单位换算
1秒 = 1000毫秒
1分钟 = 60秒 * 1000毫秒
1小时 = 60分钟 * 60秒 * 1000毫秒
1天 = 24小时 * 60分钟 * 60秒 * 1000毫秒
1周 = 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
1月 = 30天 * 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
1年 = 365天 * 30天 * 7天 * 24小时 * 60分钟 * 60秒 * 1000毫秒
function countdown() {
const nowTime = new Date().getTime();
const gapTime = futureTime - nowTime; // 未来时间 - 现在时间 = 剩余时间
// 3600 = 1000 * 60秒 * 60分 1小时
const yearGap = Math.floor(gapTime / (1000 * 60 * 60 * 24 * 365));
const monthGap = Math.floor(gapTime / (1000 * 60 * 60 * 24 * 30));
const weekGap = Math.floor(gapTime / (1000 * 60 * 60 * 24 * 7));
const dayGap = Math.floor(gapTime / (1000 * 60 * 60 * 24));
const hourGap = Math.floor((gapTime / (1000 * 60 * 60)) % 24); // 剩余小时
const minuteGap = Math.floor((gapTime / 1000 / 60) % 60); // 剩余分钟
const secondGap = Math.floor((gapTime / 1000) % 60); // 剩余秒
day.textContent = dayGap;
hour.textContent = hourGap < 10 ? "0" + hourGap : hourGap;
minute.textContent = minuteGap < 10 ? "0" + minuteGap : minuteGap;
second.textContent = secondGap < 10 ? "0" + secondGap : secondGap;
if (gapTime <= 0) {
clearInterval(timerId);
day.textContent = "00";
hour.textContent = "00";
minute.textContent = "00";
second.textContent = "00";
}
}
小时: parseInt(时间戳 / 60 / 60 % 24)
分钟: parseInt(时间戳 / 60 % 60)
秒: parseInt(时间戳 % 60)
js执行机制
js 语言是单线程语言,在代码执行时只能同时处理一件事情!在
js 代码中,如果遇到代码运行比较耗时的逻辑,按照单线程的管理,只有等待耗时任务完成时,才能执行下一段逻辑!因此,为此解决问题,则执
行代码逻辑分为,同步代码执行,和异步代码执行!
同步任务(代码)
同步任务:代码依次执行,只有等待上一步代码执行完毕后才会执行下一步代码,且不能同时执行其他任务代码!
异步任务(代码)
异步任务:代码依次执行,但是执行代码时,遇到异步任务代码,会将异步任务回调函数存放到任务队列当中,不影响其它代码执行,当需要异步任务代码执行时,会从队列中按次序获取相应的回调函数并执行!
定时器(setTimeout setInterval),事件(click mousemove...) 以及网络请求(ajax)等都属于异步任务!
执行栈: 此处,会执行同步任务代码!
console.log(1);
setTimeout(fun, 100);
console.log(2);任务队列: 此处,会存放异步任务回调函数!
fun回调函数 |console.log(3)

执行顺序,
首先执行执行栈中的同步任务,当遇到异步任务时,会将回调函数放入任务队列当中,然后继续执行同步任务,至到同步任务执行完毕后,才会从任务队列中执行异步任务回调函数!
事件循环
在
执行代码时,遇到异步代码,会将异步回调函数存放到任务队列当中,但是在存放过程中,有一个异步任务队列处理程序,主要来判断,该异步任务回调函数是否需要存放到任务队列当中!
执行栈->异步任务处理->任务队列(执行回调函数后调用)->执行栈如上图,
点击事件,经过异步任务队列处理程序,不会立即存放到任务队列当中,只有点击的时候,会将异步回调函数添加到任务队列中并执行异步回调函数,执行完毕后,并清空任务队列中的回调函数,待下次新的异步回调函数进入!当
执行栈中的同步代码执行完毕时,执行栈会反复查看异步任务队列中,是否有可执行的异步回调函数来执行!
location
location主要用来处理和解析网页域名路径(URL)!
域名(URL)组成
http://127.0.0.1:5500/dom.html?id=1234591283
协议://ip 地址:port(端口)?query(查询参数)
常见的属性
| 属性 | 描述 |
|---|---|
location.href |
获取和设置整个URL路径 |
location.host |
返回主机的域名 |
location.part |
返回端口号,未写返回空的字符串 |
location.pathname |
返回路径 |
location.search |
返回参数 |
location.hash |
返回 hash 路径 # 号后面的锚点 |
常见的方法
| 方法 | 描述 |
|---|---|
location.assign(url) |
与 href 一样,可以跳转页面,会有浏览历史记录! |
location.replace(url) |
替换当前页面,不会被浏览历史记录! |
location.reload(true) |
重新加载页面,相当于 f5 刷新,如果参数为true, 则为强制刷新 ctrl+f5 |
navigator
navigator包含了浏览器的一些基本信息,常用的属性有userAgent,主要用来获取当前平台的信息,可以判断是PC还是移动端H5!
history
history 对象,主要用来和浏览器历史记录进行交互,可以实现浏览记录前进后退跳转的基本功能 !
back():后退功能!forword():前进功能!go(-1):跳转功能,参数如果是1这是前进功能,如果是-1这是后退功能!
本地存储
本地存储是一种存储数据的一种方式,平时我们的数据在刷新浏览器或者关闭浏览器以及标签页时,数据都会消失,通过
本地存储的方式,将数据存储到浏览器本地内存中,这样就不会因刷新或者关闭的情况下丢失数据了!
本地存储,有三种方式,sessionStorage(会话存储)localStorage(本地存储)cookie!
| 特性 | sessionStorage |
localStorage |
cooKie |
|---|---|---|---|
存储容量 |
5M |
5M |
4kb |
声明周期 |
会话窗口关闭(浏览器或标签页) |
持久存储,至到手动清除 |
设置过期时间(持久存储),会话结束(cookie) |
与服务器交互 |
不会自动发送到服务器 | 不会自动发送到服务器 | 每次http请求都会自动发送到服务器 |
用途 |
主要用于在单个会话中存储临时数据 |
主要用于在客户端存储大量数据,如用户设置、缓存数据等 |
主要用于存储用户状态信息,如登录状态、用户偏好设置等 |
安全性 |
不支持 HttpOnly,安全性较低 |
不支持 HttpOnly,安全性较低 |
可以设置 HttpOnly 和 Secure 属性,增加安全性 |
API |
提供简单的 setItem 和 getItem 方法 |
提供简单的 setItem 和 getItem 方法 | 需要使用 document.cookie 进行操作 |
sessonStorage
会话存储,存储大小5M,不支持httpOnly,浏览器窗口关闭或标签页关闭时会话结束!
| api | 参数 | 描述 |
|---|---|---|
sessionStorage.setItem() |
setItem(key,value) |
设置存储数据,key为键,value为值! |
sessionStorage.getItem() |
getItem(key) |
根据key获取存储数据,key为键! |
sessionStorage.removeItem() |
removeItem(key) |
根据key删除存储数据,key为键! |
sessionStorage.clear() |
clear() |
清空存储数据! |
localStorage
本地存储,存储大小5M(因每个浏览器不一致,大小或更多,且通常最大为5M,最小为4M),不支持httpOnly,手动清除!
| api | 参数 | 描述 |
|---|---|---|
localStorage.setItem() |
setItem(key,value) |
设置存储数据,key为键,value为值! |
localStorage.getItem() |
getItem(key) |
根据key获取存储数据,key为键! |
localStorage.removeItem() |
removeItem(key) |
根据key删除存储数据,key为键! |
localStorage.clear() |
clear() |
清空存储数据! |
cookie
Cookie是一种小型文本文件,由服务器发送到用户的浏览器,并在用户下次访问同一网站时由浏览器自动发送回服务器。Cookie主要用于存储用户状态信息,如登录状态、用户偏好设置等。
存储方式
每个
Cookie都有名称、值、路径、域、过期时间等属性。
cookie封装
设置 Cookiefunction setCookie(name, value, days) { let expires = ""; if (days) { const date = new Date(); date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000); expires = "; expires=" + date.toUTCString(); } document.cookie = name + "=" + (value || "") + expires + "; path=/"; } setCookie('username', 'JohnDoe', 7); // 设置一个名为 'username' 的 Cookie,过期时间为 7 天
获取cookiefunction getCookie(name) { const nameEQ = name + "="; const ca = document.cookie.split(';'); for(let i=0;i < ca.length;i++) { let c = ca[i]; while (c.charAt(0)==' ') c = c.substring(1,c.length); if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); } return null; } const username = getCookie('username'); console.log(username); // 输出: JohnDoe
删除cookiefunction deleteCookie(name) { document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT;'; } deleteCookie('username'); // 删除名为 'username' 的 Cookie



