本文件已定稿,最后修改时间 20240511 03:20


  • 浏览器渲染引擎(解析HTML和CSS,俗称内核)和js引擎(读取网页中的js代码并运行)两部分组成。
  • JavaScript由三部分组成:
    • JavaScript语法
    • DOM:页面文档对象模型,是W3C推荐的处理可扩展标记语言的标准编程接口,通过DOM可以对页面上的各种元素进行操作。
    • BOM:浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构,通过BOM可以操作浏览器窗口

image-20221021210556246

一、语法

1、书写位置

  • JavaScript有3种书写位置,分别是行内、内部、外部(js不建议写分号,但立即执行函数和数组解构交换值时必须写,否则报错)。

  • 行内:

    <body>
    <input type="button" value="点我试试" onclick="alert('hello world')">
    </body>
  • 内部:

    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script>
    alert('hello world');
    </script>
    </head>
  • 外部:

    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src=""></script>
    </head>

2、注释

<head>
<script src="">
//单行注释
/*多行注释*/
</script>
</head>

3、变量

3.1、命名规范

  • 由字母、数字、下划线、$组成。
  • 区分大小写。
  • 不能以数字开头。
  • 不能是关键字、保留字。
  • 遵循小驼峰命名法

3.2、定义方式

  • var 定义的是全局变量(可重复定义同名变量,后定义的覆盖先定义的)。
  • let 定义的是局部变量(不可重复定义同名变量)。
  • const 定义常量。
//1、只声明不赋值,直接使用变量,结果是undefined
var a;
console.log(a); //undefined
//2、在定义变量时就赋值
var b = 10;
console.log(b); //10
//3、不定义直接赋值
c = 20;
console.log(c); //20
//4、可以同时声明、初始化、输出多个变量
var d = 1, e = 2;
console.log(d, e); //1 2

3.3、简单数据类型

  • 简单数据类型包括:

    • Number——默认值0,包含整型和浮点型,有3个特殊值
      • Infinity——正无穷大。
      • -Infinity——负无穷大。
      • NaN——代表一个非数值。
    • Boolean——默认值false,包含true和false(等价于1和0)。
    • String——默认值 “”。
    • Undefined——默认值undefined。
    • Null——var a = null;
    var a = 10;
    var b = true;
    //1、字符串需要用单引号或双引号定义,但在html中双引号表示属性,故推荐单引号定义字符串
    var str1 = 'wo';
    var str2 = "wo";
    //2、字符串的长度
    console.log(str1.length); //2
    //3、判断变量的数据类型
    console.log(typeof a); //number
    //4、判断变量是不是数值
    console.log(isNaN(b)); //false

3.4、数组

  • 定义方式:

    • 利用字面量创建数组。
    • 利用new创建数组。
  • 增加元素:

    • 不能直接给数组名赋值,否则会覆盖掉以前的数据。
    • 可以通过数组索引的方式给数组追加元素(推荐)
    • 使用数组名.length可以访问数组长度。
    • length属性是可读写的,可通过修改length长度实现数组扩容的目的。
  • 注意:

    • 数组里可存放任意类型的数据。
    <body>
    <script>
    //1、利用字面量创建数组
    //(1)空数组
    var arr1 = [];
    //(2)带初值的数组
    var arr2 = [1, 2, 3];
    //给arr2增加元素
    arr2[3] = 4;

    //2、利用new创建数组
    var arr3 = new Array();
    //3、给arr1增加元素
    //(1)
    arr1 = [1, 2];
    //(2)push方法将一个或多个元素添加到数组末尾,并返回该数组的新长度
    arr1.push(3);
    //(3)unshift方法将一个或多个元素添加到数组开头,并返回该数组的新长度
    arr1.unshift(0);
    console.log(arr1); //[0,1,2,3]

    //4、删除arr2的元素
    //(1)pop方法删除数组中最后一个元素,并返回该元素的值
    arr2.pop();
    //(2)shift方法删除数组中第一个元素,并返回该元素的值
    arr2.shift();
    //(3)splice(start,deleteCount)方法,删除指定元素
    arr2.splice(0, 2);
    console.log(arr2); //[]
    </script>
    </body>

image-20240506024856476

  • 展开运算符:…

    //... 展开运算符的作用就是将数组展开
    let arr = [1, 2, 3];
    console.log(...arr); //1 2 3
  • forEach遍历数组

    const color = ['red', 'black', 'white']
    //index可以不写
    color.forEach((item, index) => console.log(item, index))
  • 数组解构

    image-20240504012606912

    //1)变量多,单元值少,undefined
    const [a, b, c] = [1, 2]
    console.log(a)
    console.log(b)
    console.log(c)

    //2)变量少,单元值多
    const [d] = [3, 4]
    console.log(d)

    //3)剩余参数接多余的单元值
    const [e, ...f] = [5, 6, 7]
    console.log(e)
    console.log(f)

    //4)设置默认值 防止undefined传递
    const [g = 0] = []
    console.log(g)

    //5)按需导入值
    const [h, i, , j] = [8, 9, 10, 11]
    console.log(h)
    console.log(i)
    console.log(j)

    //6)支持多维数组的解构
    const [k, [l, m]] = [12, [13, 14]]
    console.log(k)
    console.log(l)
    console.log(m)

3.5、数据类型转换

  • 转换为数字型:

    var a = '10';
    var b = '10.2';
    var c = '20';
    var d = '20.2';
    //1、将String类型转换为整型
    a = parseInt(a);
    console.log(typeof a); //number
    //2、将String类型转换为浮点型
    b = parseFloat(b);
    console.log(typeof b); //number
    //3、强制转换,将String类型转换为数值型
    c = Number(c);
    console.log(typeof c); //number
    //4、js隐式转换(- * /)
    d = d - 0;
    console.log(typeof d); //number
  • 转换为布尔型:代表空和否定的值(false,0,null,undefined,NaN)都会被转换成false,其余值都转换成true。

    var a = false;
    a = Boolean(a);
    console.log(a); //false
  • 转换为字符串:

    var a = 1;
    var b = 2;
    var c = 3;
    //1、toString转成字符串
    a = a.toString();
    console.log(typeof a); //string
    //2、String强制转成字符串
    b = String(b);
    console.log(typeof b); //string
    //3、任何类型 +字符串 == 字符串
    c = c + '';
    console.log(typeof c); //string
  • 数组转换为字符串:

    var arr = [1, 2, 3];
    console.log(arr.toString()); //1,2,3
    console.log(arr.join('')); //123

3.6、Object

  • Object是由属性和方法组成的,现阶段创建对象的3种方式:
    • 利用字面量创建对象。
    • 利用new Object创建对象。
    • 利用构造函数创建对象(是一种用来初始化对象的特殊函数,总与new一起使用,约定函数名第一个字母大写)。
  • 对象属性或方法的调用:
    • 属性使用 对象名.属性名 或 对象名[‘属性名’] 调用。
    • 方法使用 对象名.方法名() 调用。
  • :和改属性值是一样的,直接对象名.属性名=xx;
  • :delete 对象名.属性名
  • 遍历对象:for (变量名 in 对象名) {}
    • 变量名——得到的是属性名。
    • 对象名[属性名]——得到的是属性值。

image-20240506024417891

image-20240506024511021

image-20240506024555164

//1、利用字面量创建对象
var star = {
name: 'pink',
sayHello: function () {
alert('hello');
}
};

//2、利用new Object创建对象
var obj1 = new Object(); //空对象
obj1.name = 'blue';
obj1.sayHi = function () {
console.log('hi');
};

//3、利用构造函数创建对象
//(1)先定义构造函数
function GouZao() {
this.name = 'GouZao';
this.say = function () {
console.log('wa');
}
};
//(2)使用new
var obj2 = new GouZao();
console.log(obj2.name); //GouZao
console.log(obj2['name']); //GouZao

//4、遍历
//pink
//ƒ() {alert('hello');}
for (s in star) {
console.log(star[s]);
}

image-20240506025944056

image-20240506030532587

image-20240506030642321

image-20240511022041197

3.7、内置对象

  • JavaScript中的对象分为3种,内置对象、浏览器对象、自定义对象

  • Math对象:

    var a = 3.1;
    //1、圆周率
    console.log(Math.PI); //3.1415926
    //2、向下取整
    console.log(Math.floor(a)); //3
    //3、向上取整
    console.log(Math.ceil(a)); //4
    //4、四舍五入,就近取整
    console.log(Math.round(-3.5)); //注意 -3
    console.log(Math.round(3.2)); //3
    //5、绝对值
    console.log(Math.abs(-3)); //3
    //6、求最大值和最小值
    console.log(Math.max(1, 2)); //2
    console.log(Math.min(1, 2)); //1
  • Date对象:

    //1、获取系统当前时间(必须实例化)
    var now = new Date();
    console.log(now);
    //2、获取日期对象的指定部分
    console.log(now.getFullYear()); //获取年
    console.log(now.getMonth()); //获取月(0-11)
    console.log(now.getDate()); //获取月中的第几天
    console.log(now.getDay()); //获取周中的第几天(0-6)
    console.log(now.getHours()); //时
    console.log(now.getMinutes()); //分
    console.log(now.getSeconds()); //秒
    //3、构造函数构造指定日期的Date对象
    var a = new Date('2011-1-1');
    console.log(a.getFullYear()); //2011
    //4、获取系统当前时间毫秒值
    console.log(Date.now());
  • 字符串对象:JavaScript中的字符串同Java一样,具有不可变的特点。

    //1、根据字符查找,返回第一个匹配字符的索引(找不到返回-1)
    var str1 = 'hello';
    //(1)0代表从索引0开始查找
    console.log(str1.indexOf('l', 0)); //2
    //(2)倒着查找
    console.log((str1.lastIndexOf('o'))); //4

    //2、根据索引返回字符
    console.log(str1.charAt(0)); //h
    console.log(str1.charCodeAt(0)); //104(ASCII)

    //3、字符串操作方法
    //(1)拼接字符串 == + (+更常用)
    console.log(str1.concat(' world')); //hello world
    //(2)截取字符串 start end 包前不包后
    console.log(str1.slice(0, 1)); //h
    console.log(str1.substring(0, 1)); //h
  • 数组对象:

    //1、检测是否为数组
    var arr1 = [1, 2, 3];
    console.log(arr1 instanceof Array); //true
    console.log(Array.isArray(arr1)); //true

    //2、增删数组元素
    //(1)末尾添加一个或多个元素,返回新的长度
    arr1.push(3, 5);
    //(2)删除数组最后一个元素,返回删除的值
    arr1.pop();
    //(3)向数组的开头添加一个或多个元素,返回新的长度
    arr1.unshift(-1, 0); //注意,-1会后添加到数组中
    //(4)删除数组的第一个元素
    arr1.shift();
    console.log(arr1); //[0, 1, 2, 3, 3]

    //3、数组索引方法(不存在返回-1)
    //(1)查找给定元素在数组中的第一个索引
    console.log(arr1.indexOf(3)); //3
    //(2)查找给定元素在数组中的最后一个索引
    console.log(arr1.lastIndexOf(3)); //4

    //4、连接多个数组,不影响原数组,返回新数组
    console.log(arr1.concat([4])); //[0, 1, 2, 3, 3, 4]
    //5、截取数组,不影响原数组,返回新数组,start end 包前不包后
    console.log(arr1.slice(0, 2)); //[0, 1]
    //6、删除数组元素,影响原数组,start deleteCount
    arr1.splice(3, 2);
    console.log(arr1); //[0, 1, 2]

    //7、数组排序
    //(1)反转数组
    arr1.reverse();
    //(2)冒泡排序
    arr1.sort(function (a, b) {
    return a - b; //升序
    // return b - a; //降序
    });
    console.log(arr1); //[0, 1, 2]

3.8、自定义对象

var myObject = {
name: 'myObject',
eat: function () {
console.log('吃饭');
}
};

3.9、对象解构

image-20240504022006261

image-20240504022635242

image-20240504023023601

//4、多级对象解构
const animal = {
isLive: 'yes',
pig: {
name: 'pig',
age: 10
}
}
const { isLive, pig: { name, age } } = animal
console.log(isLive) //yes
console.log(name) //pig
console.log(age) //10

4、输入输出

  • JavaScript常用输入输出语句如下:

    //1、浏览器弹出警示框
    alert('hello');
    //2、浏览器控制台打印输出信息
    console.log('hello');
    //3、浏览器弹出输入框,用户可以输入
    prompt('请输入');
    //4、直接将内容写入页面的内容流,但是文档流执行完毕,它会导致页面全部重绘。
    document.write('hello');
  • 转义字符:

    //  \n
    // \\
    // \'
    // \"
    // \t
    // \b

5、运算符

5.1、算术运算符

  • 浮点数值的最高精度是17位小数,不要直接判断两个浮点数是否相等
  • 比如 0.1 + 0.2 不等于 0.3,而是0.30000000000000004

image-20221022223037968

5.2、比较运算符

image-20221022223732726

5.3、赋值运算符

  • 赋值运算符包括:

    • =

    • +=

    • -=

    • *=

    • /=

    • %=

5.4、自增自减运算符

  • ++ –:

  • ++ – 在前:先自增自减,再参与运算。

  • ++ – 在后:先参与运算,再自增自减。

5.5、逻辑运算符

  • 逻辑运算符包括:

    • &&——与
    • ||——或
    • ! ——非
  • 与、或的短路现象:

    console.log(1 && 2);    //2
    console.log(0 || 2); //2
    console.log(1 > 0 && 2 < 3); //true
    var a = 2;
    console.log(1 || (a = a - 1));
    console.log(a); //2,或短路

5.6、优先级

image-20221022225722589

6、流程控制

6.1、if分支

var a = 3;
if (a === 1) {
console.log(1);
} else if (a === 2) {
console.log(2);
} else {
console.log('烫');
}

6.2、switch分支

var a = 3;
switch (a) {
case 1:
console.log(1);
break;
case 2:
console.log(2);
break;
default:
console.log('烫');
}

6.3、三元表达式

var a = 3;
a > 1 ? console.log(true) : console.log(false); //true

6.4、for循环

for (var i = 0; i < 3; i++) {
console.log(i);
}

6.5、while循环

var i = 0;
while (i < 3) {
console.log(i);
i++;
}

6.6、do-while循环

var i = 0;
do {
console.log(i);
i++;
} while (i < 3);

6.7、跳转

  • continue —— 跳出本次循环,开始下次循环。
  • break —— 跳出循环。

7、函数

7.1、定义方式

  • 实参个数应与形参个数保持一致。
    • 实参个数多于形参个数,只接收形参的个数。
    • 实参个数小于形参个数,多的形参定义为undefined,结果为NaN。
  • return只能返回一个值。
    • 如果有多个被逗号隔开的值,只返回最后一个值。
    • 函数没有写return则返回undefined。
//可以为参数设置默认值
function sayHello(name = 'tiger') {
console.log(name + ' say hello');
//1、不需要声明返回值类型
return 1;
}

var result = sayHello('ergou');
console.log(result); //1
console.log(sayHello()); //tiger say hello

7.2、匿名函数

//1、定义匿名函数
var func = function (name) {
console.log(name);
}
//2、调用匿名函数
func('zhangSan'); //zhangSan

7.3、立即执行函数

  • 匿名函数和有名字的函数都可以。
  • 内部定义的var变量是局部变量。
<script>
//1、方式一
(function () {console.log(1);})();
//2、方式二
(function () {console.log(2);}());
</script>

7.4、不定参数

//1、定义函数
function print() {
//(1)arguments是一个伪数组,具有length属性,可以以数组形式取索引值和遍历
console.log(arguments); //[1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
console.log(arguments[0]); //1
}

//2、调用函数
print(1, 2, 3);

7.5、剩余参数

//...表示剩余参数,是真数组
function func(a, b, ...arr) {
console.log(a, b, arr);
}
func(1, 2, 3, 4); //1 2 [3, 4]

7.6、箭头函数

  • 目的:为了更简短的函数写法,并且不绑定this,适用于需要匿名函数的地方。

  • 区别:箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this

    // const fn = function () {
    // console.log(100);
    // }

    //1)箭头函数基本语法
    const fn = () => {
    console.log(100);
    }
    fn();

    // 2)只有一个形参可以省略小括号,只有一行代码体可以省略大括号
    const fn2 = x => console.log(x);
    fn2(101);

    //3)如果只有一行返回值,可以省略大括号和return
    const fn3 = x => x + x;
    console.log(fn3(100));

    //4)箭头函数可以直接返回一个对象
    const fn4 = uname => ({ uname: uname });
    console.log(fn4("hello"));

image-20240504010803404

image-20240504011957241

7.7、作用域

  • 作用域分为局部作用域和全局作用域,作用域链本质上就是变量的查找机制(就近原则)。

  • 闭包:函数中嵌套函数,且嵌套函数用到了外层函数的变量。

    <body>
    <script>
    //闭包的作用,封闭数据,提供操作,外部也可以访问函数内部的变量
    function func1() {
    let a = 1;
    function func2() {
    console.log(a);
    }
    return func2;
    }
    let f = func1();
    f();
    </script>
    </body>
  • 变量提升

    image-20240315023911550

8、正则表达式

8.1、语法

<body>
<script>
//正则表达式的作用,检测是否含有指定字符串
//1、定义规则
let str = 'hello';
const reg = /l/;
//2.1、调用规则的test方法,返回true或false
console.log(reg.test(str)); //true
//2.2、调用规则的exec方法,返回数组或null
console.log(reg.exec(str));
</script>
</body>

8.2、元字符

  • 元字符可以使正则表达式更加灵活和简洁,而普通字符只能表示它本身。

    • ① 边界符:^ 表示以谁开始;$ 表示以谁结束;^ 和 $ 一起写表示是精确匹配

    • ② 量词:* 重复零次或多次;+ 重复1次或多次;? 重复零次或1次;{n} 重复n次;{n,} 重复n次或多次;{n,m} 重复n到m次

    • ③ 字符类:[] 匹配字符集合,包含[]中其中一个就是true;[a-zA-Z0-9]表示这个范围都行;[^a -z] ^表示取反,除了小写字母都行

    • ④ 预定义:

      image-20240315015058842

    • ⑤ 修饰符和替换:

      <body>
      <script>
      //1、定义规则
      let str = 'helLo';
      const reg = /l/ig;
      //2、修饰符 i 表示忽略大小写;g 表示全局搜索(否则只会匹配一个)
      console.log(str.replace(reg, 'a')); //heaao
      </script>
      </body>

9、异常处理

image-20240506033419513

image-20240506033959916

10、节流防抖

10.1、节流

image-20240506034957741

10.2、防抖

image-20240506034512245

二、DOM

  • DOM树(DOM把以下内容都看作对象):
    • 文档,一个页面就是一个文档(文档从上往下加载),DOM中使用document表示。
    • 元素,页面中的所有标签都是元素,DOM中使用element表示。
    • 节点,网页中所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示。

image-20221023213151519

1、获取元素

1.1、根据标签获取

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>2019-9-9</div>
<div>2022-10-24</div>
<script>
//1、根据标签获取元素对象,会以伪数组的形式返回元素对象的集合,没有就返回空数组
var divs = document.getElementsByTagName('div');
console.log(divs); //[div, div]
console.log(divs[0]); //<div>2019-9-9</div>
</script>
</body>
</html>

1.2、根据类名获取

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="time">2019-9-9</div>
<div class="time">2022-10-24</div>
<script>
//1、根据类名获取元素对象集合(伪数组形式)
var timers = document.getElementsByClassName('time');
console.log(timers); //[div.time, div.time]
console.log(typeof timers); //object
</script>
</body>
</html>

1.3、根据ID获取

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="time">2019-9-9</div>
<script>
//1、根据id获取元素对象
var timer = document.getElementById('time');
console.log(timer); //<div id="time">2019-9-9</div>
console.log(typeof timer); //object
//2、打印返回的元素对象,方便我们更好地查看其属性和方法
console.dir(timer);
</script>
</body>
</html>

1.4、特殊元素获取

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>2019-9-9</div>
<script>
//1、获取html元素对象
var html = document.documentElement;
console.log(html);
//2、获取body元素对象
var body = document.body;
console.log(body);
</script>
</body>
</html>

1.5、其它

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="timer1">2019-9-9</div>
<div id="timer2">2022-10-24</div>
<script>
//1、querySelector返回指定选择器的第一个元素对象
var timer1 = document.querySelector('div');
var timer2 = document.querySelector('#timer1');
console.log(timer1); //<div id="timer1">2019-9-9</div>
console.log(timer2); //<div id="timer1">2019-9-9</div>
//2、querySelectorAll返回指定选择器的所有元素对象集合
var timers = document.querySelectorAll('div');
console.log(timers); //[div#timer1, div#timer2]
</script>
</body>
</html>

2、事件

2.1、事件三要素

  • 事件由三要素组成:事件源、事件类型、事件处理程序

    • 事件源:事件被触发的对象,按钮?
    • 事件类型:什么事件,如何触发,鼠标经过?键盘按下?
    • 事件处理程序:通过一个函数赋值的方式完成。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form>
<input type="button" id="btn" value="点我试试">
</form>
<script>
//1、点击一个按钮,弹出对话框
var btn = document.getElementById('btn');
//传统的注册事件方式
btn.onclick = function () {
alert('hello world');
};
</script>
</body>
</html>

2.2、注册事件

  • 给元素添加事件称为注册事件或者绑定事件,注册事件分为传统方式方法监听注册(推荐)两种。

    • 传统方式
      • 比如 btn.onclick = function () {alert(‘hello world’);};
      • 注册事件的唯一性——同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数会覆盖前面注册的。
    • 方法监听注册(推荐)
      • 同一个元素同一个事件可以注册多个监听器。
      • addEventListener有3个参数:
        • type —— 事件类型字符串,比如click、mouseover,注意不要带on。
        • listener —— 事件处理函数。
        • useCapture —— 可选参数,布尔类型,默认值为false。
    <body>
    <form>
    <input type="button" value="点我试试1">
    <input type="button" value="点我试试2">
    </form>
    <script>
    //1、传统方式
    var btns = document.querySelectorAll('input');
    btns[0].onclick = function () {
    alert('hello world');
    };
    //2、方法监听注册
    btns[1].addEventListener('click', function () {
    alert(22);
    });
    btns[1].addEventListener('click', function () {
    alert(33);
    });
    </script>
    </body>

2.3、删除事件

  • 删除事件(解绑事件)传统方式removeEventListener两种方式。

    <body>
    <form>
    <input type="button" value="点我试试1">
    <input type="button" value="点我试试2">
    </form>
    <script>
    //1、传统方式
    var btns = document.querySelectorAll('input');
    btns[0].onclick = function () {
    alert('hello world');
    };
    //删除事件
    btns[0].onclick = null;

    //2、removeEventListener方式
    function fn() {
    alert(22);
    }
    btns[1].addEventListener('click', fn);
    //删除事件(匿名函数无法解绑)
    btns[1].removeEventListener('click', fn);
    </script>
    </body>

2.4、事件对象

  • event对象代表事件的状态,触发事件后,会得到相关的属性,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。

    • 事件对象只有有了事件才会存在(系统自动创建),event写到事件处理函数的()里,可自定义命名(e、evt)。
    • 事件对象的属性方法:
      • event.target —— 返回触发事件的对象(标准)(this代表的是绑定事件的对象)。
      • event.type —— 返回事件的类型。
      • event.preventDefault() —— 该方法阻止默认事件(标准),比如不让链接跳转。
      • event.stopPropagation() —— 阻止冒泡(标准)。
    <body>
    <form>
    <input type="button" value="点我试试">
    </form>
    <script>
    //以注册事件的传统方式举例
    var btn = document.querySelector('input');
    btn.onclick = function (event) {
    alert('hello world');
    console.log(event.target);
    };
    </script>
    </body>

2.5、鼠标事件

  • 常用的鼠标事件有:
    • onclick —— 鼠标点击左键触发。

    • onmouseover —— 鼠标经过触发。

    • onmouseout —— 鼠标离开触发。

    • onfocus —— 获得鼠标焦点触发。

    • onblur —— 失去鼠标焦点触发。

    • onmousemove —— 鼠标移动触发。

    • onmouseup —— 鼠标弹起触发。

    • onmousedown —— 鼠标按下触发。

    • 禁止鼠标右键和选中文字,代码见下:

      <body>
      <p>我是一段文字</p>
      <script>
      document.addEventListener('contextmenu', function (e) {
      //1、禁止右键菜单
      e.preventDefault();
      });
      document.addEventListener('selectstart', function (e) {
      //2、禁止选中文字
      e.preventDefault();
      });
      </script>
      </body>
  • 常用的鼠标事件对象属性:
    • event.clientX —— 相对于浏览器可视区的X坐标。
    • event.clientY —— 相对于浏览器可视区的Y坐标。
    • event.pageX —— 相对于文档页面的X坐标。
    • event.pageY —— 相对于文档页面的Y坐标。
    • event.screenX —— 相对于电脑屏幕的X坐标。
    • event.screenY —— 相对于电脑屏幕的Y坐标。

2.6、键盘事件

  • 常用的键盘事件有:
    • onkeyup —— 某个键盘按键被松开时触发(不区分大小写)。
    • onkeydown —— 某个键盘按键被按下时触发(不区分大小写)。
  • 常用的键盘事件对象属性:
    • event.key —— 键的字母值。

2.7、事件流

  • 事件流描述的是从页面中接收事件的顺序,事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。

  • DOM事件流分为3个阶段:

    • 捕获阶段(DOM最顶层节点➡具体元素)、当前目标阶段(具体元素)、冒泡阶段(具体元素➡DOM最顶层节点)。
  • 注意:

    • js代码中只能执行捕获或者冒泡其中的一个阶段。
    • onclick 和 attachevent只能得到冒泡阶段。
    • addEventListener第三个参数是true表示在事件捕获阶段调用事件处理程序,默认是false,表示在冒泡阶段调用事件处理程序。
    • 有些事件是没有冒泡的,比如onfocus、onblur。
    • 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。

    image-20221026110810639

    <!--事件委托:利用冒泡原理在父节点上设置事件处理程序,可以影响每个子节点,只操作一次DOM,提高性能-->
    <body>
    <ul>
    <li>第1个li标签</li>
    <li>第2个li标签</li>
    <li>第3个li标签</li>
    </ul>
    <script>
    var uls = document.querySelectorAll('ul');
    uls[0].onclick = function () {
    alert('ul标签');
    };
    </script>
    </body>

3、操作元素

3.1、修改元素内容

  • 修改元素内容有两种方式:

    • innerText —— 非标准,不识别html标签,可读写,读取其内容时会去掉空格和换行。
    • innerHTML —— w3c标准,识别html标签,可读写,读取其内容时会保留空格和换行。
<body>
<form>
<input type="button" value="点我试试">
</form>
<div>点击按钮,显示当前系统时间</div>
<p>
盒子2
<span>hello</span>
</p>
<script>
//当我们点击按钮,div里面的文字会发生变化
var btn = document.querySelector('input');
var div = document.querySelector('div');
var p = document.querySelector('p');
btn.onclick = function () {
// div.innerText = '<strong>2022-10-24</strong>';
div.innerHTML = '<strong>2022-10-24</strong>';
console.log(div.innerText); //<strong>2022-10-24</strong>
console.log(div.innerHTML); //2022-10-24
console.log(p.innerText); //盒子2 hello
//盒子2
//<span>hello</span>
console.log(p.innerHTML);
}
</script>
</body>

3.2、修改元素属性

<body>
<form>
<input type="button" value="点我试试">
</form>
<div style="width: 100px;height: 100px;background-color: springgreen"></div>
<script>
//当我们点击按钮,div盒子大小会变化
var btn = document.querySelector('input');
var div = document.querySelector('div');
btn.onclick = function () {
div.style.width = '200px';
div.style.height = '200px';
}
</script>
</body>

3.3、修改表单属性

  • 表单里面的值是通过value属性来控制的。

  • 想要表单被禁用,可以将disabled属性设置为true。

<body>
<form>
<input type="button" value="点我试试">
</form>
<script>
var btn = document.querySelector('input');
btn.onclick = function () {
btn.value = '点击了,不能再点了';
btn.disabled = true;
}
</script>
</body>

3.4、修改样式属性

  • 通过js修改样式属性有两种方式

    • element.style —— 行内样式操作。
    • element.className —— 类名样式操作。
  • 注意:

    • js里面的样式采用小驼峰命名法,比如fontSize。
    • element.style产生的是行内样式,CSS权重高。
    • className会直接更改元素的类名,从而覆盖原类名。
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    .change {
    width: 200px;
    height: 200px;
    background-color: springgreen;
    }
    </style>
    </head>
    <body>
    <form>
    <input type="button" value="点我试试">
    </form>
    <div></div>
    <script>
    //当我们点击按钮,div盒子大小会变化
    //element.style在修改元素属性时已演示,此处只演示element.className的方式
    var btn = document.querySelector('input');
    var div = document.querySelector('div');
    btn.onclick = function () {
    div.className = 'change';
    }
    </script>
    </body>

3.5、自定义属性

  • 自定义属性目的:是为了保存并使用数据,有些数据可以保存在页面中而不用保存到数据库中。

  • 获取属性值:

    • element.属性 —— 获取属性值(内置属性值)。
    • element.getAttribute(‘属性’) —— 获取属性值(主要获得自定义的属性)。
  • 设置属性值:

    • element.属性 = ‘值’ —— 设置属性值(内置属性)。
    • element.setAttribute(‘属性’, ‘值’) —— 设置属性值(自定义属性)。
  • 移除属性:

    • element.removeAttribute(‘属性’)
  • H5设置和获取自定义属性值:

    • element.setAttribute(‘属性’, ‘值’) —— 设置属性值(必须以 data- 开头)。
    • element.getAttribute(‘属性’) —— 兼容性获取。
    • element.dataset.index 或 element.dataset[‘index’] —— 新增获取方式(只能获取 data- 开头的属性值)。
    <body>
    <form>
    <input type="button" value="点我试试">
    </form>
    <script>
    var btn = document.querySelector('input');
    btn.onclick = function () {
    //1、H5设置自定义属性
    btn.setAttribute('data-index', '1');
    //2、H5获取自定义属性
    console.log(btn.getAttribute('data-index'));
    console.log(btn.dataset.index);
    console.log(btn.dataset['index']);
    //3、移除属性
    btn.removeAttribute('data-index');
    btn.removeAttribute('type');
    }
    </script>
    </body>

4、节点

4.1、概述

  • 获取元素的两种方式比较:
    • 利用DOM提供的方法获取元素——逻辑性不强,比较繁琐。
    • 利用节点层级关系获取元素——逻辑性强,操作更简单,但对老版本浏览器兼容性较差。
  • 节点至少拥有nodeType、nodeName、nodeValue这三个基本属性。
    • 元素节点,nodeType为1。
    • 属性节点,nodeType为2。
    • 文本节点,nodeType为3(包括文字、空格、换行等)。
    • 在实际开发中,主要操作的是元素节点。

4.2、父节点

  • node.parentNode —— 获取node节点的父节点(是获取最近的一个父节点,没有返回null)。

    <body>
    <form>
    <input type="button" value="点我试试">
    </form>
    <script>
    var btn = document.querySelector('input');
    //1、获取btn的父节点
    console.log(btn.parentNode);
    </script>
    </body>

4.3、子节点

  • parentNode.childNodes(标准) —— 返回指定节点的子节点集合,该集合为即时更新的集合。返回值包含了所有的子节点(元素节点、文本节点等),只要元素节点则须专门处理,所以我们不提倡这种方式

  • parentNode.children(非标准) —— 只读,返回所有的子元素节点,重点掌握

  • parentNode.firstElementChild —— 返回第一个子元素节点,找不到则返回null。

  • parentNode.lastElementChild —— 返回最后一个子元素节点,找不到则返回null。

    <body>
    <form>
    <input type="button" value="点我试试">
    </form>
    <script>
    var form = document.querySelector('form');
    console.log(form.childNodes); //[text, input, text]
    console.log(form.children); //[input]
    console.log(form.firstElementChild); //<input type="button" value="点我试试">
    console.log(form.lastElementChild); //<input type="button" value="点我试试">
    </script>
    </body>

4.4、兄弟节点

  • nextSibling —— 下一个兄弟节点(包括元素节点或者文本节点等)。

  • nextElementSibling —— 下一个兄弟元素节点。

    <body>
    <form>
    <input type="button" value="按钮">
    <input type="text" value="文本框">
    </form>
    <script>
    var btn = document.querySelector('input');
    console.log(btn.nextSibling);
    console.log(btn.nextElementSibling);
    </script>
    </body>

4.5、创建和添加节点

<body>
<ul>
<li>li</li>
</ul>
<script>
//1、创建节点(li)
var li1 = document.createElement('li');

//2、添加节点
//(1)作为子节点,追加到父级节点里的末尾
var ul = document.querySelector('ul');
ul.appendChild(li1);
//(2)作为子节点,插入到父节点下指定子节点的前面
var li2 = document.createElement('li');
ul.insertBefore(li2, ul.children[0]);
</script>
</body>

4.6、删除节点

<body>
<ul>
<li>li1</li>
<li>li2</li>
</ul>
<script>
//1、删除父节点中的一个子节点,返回被删除的节点
var ul = document.querySelector('ul');
ul.removeChild(ul.children[1]);
</script>
</body>

4.7、复制节点

  • 复制节点分为浅拷贝和深拷贝两种:
    • 浅拷贝——参数为空或false,只复制节点本身,不复制里面的子节点。
    • 深拷贝——参数为true,会复制节点本身及里面所有的子节点。
<body>
<ul>
<li>li</li>
</ul>
<script>
var li = document.querySelector('li').cloneNode();
var ul = document.querySelector('ul');
ul.appendChild(li); //没有 'li'
</script>
</body>

4.8、动态创建元素

  • 动态创建元素有3种方式:

    • document.write() —— 直接将内容写入页面的内容流,但是文档流执行完毕,它会导致页面全部重绘
    • element.innerHTML —— 将内容写入某个节点,不会导致页面全部重绘,创建多个元素效率更高(不拼接字符串,拼接数组),但结构稍微复杂。
    • createElement() —— 创建多个元素,效率稍微低一点,但结构更清晰
    <body>
    <ul></ul>
    <script>
    //element.innerHTML 创建 1000个li的效率(采用数组拼接的形式)
    var d1 = Date.now();
    var ul = document.querySelector('ul');
    var arr = [];
    for (var i = 0; i < 1000; i++) {
    arr[i] = '<li></li>';
    }
    ul.innerHTML = arr.join('');
    var d2 = Date.now();
    console.log(d2 - d1); //1ms
    </script>
    </body>

三、BOM

  • window对象是浏览器的顶级对象,它具有双重角色
    • 它是js访问浏览器窗口的一个接口。
    • 它是一个全局对象,定义在全局作用域中的变量、函数都会变成window对象的属性和方法。
    • window有一个特殊属性window.name

image-20221027101600799

1、JS执行队列

  • JavaScript是单线程,因为它是为操作DOM和处理页面交互而诞生的,比如对某个DOM元素进行添加和删除,必须先添加才能删除,不能同时进行。但单线程可能会导致js执行时间过长➡页面渲染不连贯,为了解决这个问题,HTML5提出允许JavaScript创建多个线程,于是js中出现了同步和异步:

    • 同步——前一个任务结束后再执行后一个任务 ,程序的执行顺序与任务的排列顺序是一致的
    • 异步——在处理一个任务时,可以同时处理其它任务。一般来说,异步任务有以下三种类型:
      • 普通事件,如click、resize等。
      • 资源加载,如load、error等。
      • 定时器,setTimeout、setInterval等。
  • 同步任务和异步任务的执行过程

    • 先执行执行栈中的同步任务。
    • 异步任务(回调函数)放入任务队列中。
    • 一旦执行栈中的同步任务执行完毕,系统会按次序读取任务队列中的异步任务,并进入执行栈执行。
    • 由于主线程不断地获取任务、执行任务,这种机制被称为事件循环

    image-20240314003234310

    <body>
    <script>
    //演示 同步 问题 (单线程顺序执行)
    //1 3 2
    console.log('1');
    window.setTimeout(function () {
    console.log('2');
    }, 10000);
    console.log('3');
    </script>
    </body>
    <body>
    <script>
    //演示 同步任务 和 异步任务 执行过程
    //仍然是 1 3 2
    console.log('1');
    window.setTimeout(function () {
    console.log('2');
    }, 0);
    console.log('3');
    </script>
    </body>

2、window对象

2.1、页面加载事件

  • 页面加载事件就是给window或document绑定事件,分为两种:
    • onload(load) —— 当文档内容全部加载完毕(图像、脚本、css等),才调用处理函数。
    • DOMContentLoaded —— 当DOM加载完成(不包括图片、css、flash等)就调用处理函数。
    • 注意:
    • 有了onload就可以把js代码写到页面元素的上方。
    • onload的传统注册方式只能写一次,如果有多个,以最后一个为准。
    • 页面图片较多时,从用户访问到onload触发可能需要较长时间,交互效果就不能实现,此时用DOMContentLoaded比较合适。
<body>
<script>
//1、load(这样写就可以将js放到页面元素的前面)
window.addEventListener('load', function () {
//注意,js代码可以在元素p的前面了
var p = document.querySelector('p');
p.innerHTML = '文字消失了';
});
//2、DOMContentLoaded
document.addEventListener('DOMContentLoaded', function () {
console.log('DOM加载完成');
});
</script>
<p>我是一段文字</p>
</body>

2.2、调整窗口大小事件

  • onresize(resize) —— 当窗口大小发生像素变化,就会触发事件处理函数。

    • 我们经常利用此完成响应式布局window.innerWidth当前屏幕的宽度,window.innerHeight当前屏幕的高度。
    <body>
    <p>我是一段文字</p>
    <script>
    window.addEventListener('resize', function () {
    console.log('窗口大小变化了');
    });
    </script>
    </body>

3、navigator对象

  • navigator对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回userAgent值。

  • 下面前端代码可以判断用户的终端是什么类型,并跳转不同的页面。

    待续

4、location对象

  • window对象给我们提供了一个location属性(对象)用于获取或者设置窗体的url,并且可以用于解析url

    • 一般语法:protocol://host[:port]/path/[?query]#fragment
      • query —— 键值对形式的参数,通过&分隔开。
      • fragment —— 片段,#后面内容常见于链接锚点。
  • location对象属性:

    • window.location.href —— 获取或者设置整个url。
    • window.location.host —— 返回主机(域名)。
    • window.location.port —— 返回端口号。
    • window.location.pathname —— 返回路径。
    • window.location.search —— 返回参数。
    • window.location.hash —— 返回片段。
  • location对象方法:

    • window.location.assign( url ) —— 跳转页面(同设置href),也称为重定向记录历史,可后退
    • window.location.replace( url ) —— 替换当前页面,不记录历史,不能后退
    • window.location.reload( ) —— 刷新页面,参数为true表示强制刷新。
    <body>
    <div></div>
    <script>
    //1、实现5s后自动跳转
    var count = 5;
    var div = document.querySelector('div');
    window.setInterval(function () {
    div.innerHTML = '您将在' + count + 's之后跳转到首页';
    count--;
    if (count == -1) {
    // window.location.href = 'http://www.baidu.com';
    // window.location.assign('http://www.baidu.com');
    window.location.replace('http://www.baidu.com');
    window.location.reload(true);
    }
    }, 1000);
    </script>
    </body>

5、history对象

  • window对象给我们提供了history对象,可以与浏览器历史记录进行交互。
    • window.history.back() —— 后退。
    • window.history.forward() —— 前进。
    • window.history.go( 参数 ) —— 正整数前进几,负整数后退几。

6、定时器

6.1、setTimeout定时器

  • window.setTimeout(调用函数, 延迟的毫秒数) —— 设置一个定时器,定时器到期后执行调用函数。
    • 调用函数可以直接写函数、函数名、’函数名()’(不推荐)。
    • 延迟的毫秒数默认值是0,单位是ms。
    • 通常要给定时器赋值一个标识符。
  • window.clearTimeout(定时器标识符) —— 取消setTimeout定时器。
<body>
<form>
<input type="button" value="点我停止">
</form>
<script>
//1、设置setTimeout定时器
var timer1 = window.setTimeout(function () {
document.write(new Date());
}, 3000);
//2、点击按钮取消定时器
var btn = document.querySelector('input');
btn.addEventListener('click', function () {
clearTimeout(timer1);
});
</script>
</body>

6.2、setInterval定时器

  • window.setInterval(回调函数, 间隔的毫秒数) —— 每隔一段时间,就调用一次回调函数。
    • 调用函数可以直接写函数、函数名、’函数名()’(不推荐)。
    • 延迟的毫秒数默认值是0,单位是ms。
    • 通常要给定时器赋值一个标识符。
  • **window.clearInterval(定时器标识符)**—— 取消setInterval定时器。
<body>
<form>
<input type="button" value="点我停止">
</form>
<script>
//1、设置setInterval定时器
var timer1 = window.setInterval(function () {
console.log(new Date());
}, 2000);
//2、点击按钮取消定时器
var btn = document.querySelector('input');
btn.addEventListener('click', function () {
clearInterval(timer1);
});
</script>
</body>

7、网页特效

7.1、元素偏移量offset系列

  • 我们使用offset系列相关属性可以动态地得到该元素的位置、大小等。
    • 获得元素距离带有定位父元素的位置。
    • 获得元素自身的大小(宽度高度)。
    • 返回的数值都不带单位。
  • offset系列常用属性:
    • element.offsetParent —— 返回该元素带有定位的父元素,如果父级都没有定位则返回body。
    • element.offsetTop —— 返回元素相对带有定位父元素上方的偏移。
    • element.offsetLeft —— 返回元素相对带有定位父元素左边的偏移。
    • element.offsetWidth —— 返回自身宽度(padding+border+width)。
    • element.offsetHeight —— 返回自身高度(padding+border+height)。
  • offset 和 style 对比:
    • offset —— 可以得到任意样式表中的样式值。获取数值没有单位。获取元素大小位置用offset合适
    • style —— 只能得到行内样式表中的样式值。获取数值有单位。可读写,给元素更改值用style

7.2、元素可视区client系列

  • 元素可视区client系列常用属性:
    • element.clientTop —— 返回元素上边框的大小。
    • element.clientLeft —— 返回元素左边框的大小。
    • element.clientWidth —— 返回 padding + width,不带单位。
    • element.clientHeight —— 返回 padding + height,不带单位。

7.3、元素滚动scroll系列

  • 元素滚动scroll系列常用属性:
    • element.scrollTop —— 返回被卷去的上侧距离,不带单位。
    • element.scrollLeft —— 返回被卷去的左侧距离,不带单位。
    • element.scrollWidth —— 返回自身实际的宽度,不含边框,不带单位。
    • element.scrollHeight —— 返回自身实际的高度,不含边框,不带单位。

7.4、触屏touch事件

  • 常见的触屏touch事件:
    • touchstart —— 手指触摸到一个DOM元素时触发。
    • touchend —— 手指从一个DOM元素上移开时触发。
    • touchmove —— 手指在一个DOM元素上滑动时触发。
    • 触摸列表:
      • touches —— 正在触摸屏幕的所有手指的一个列表。
      • targettouches —— 正在触摸当前DOM元素的手指列表。
      • changedtouches —— 手指状态发生了改变的列表。

7.5、click延时解决方案

  • 移动端click事件会有300ms的延迟,原因是移动端屏幕双击会缩放页面,解决方案:

    • 禁用缩放。浏览器禁用默认的双击缩放行为并且去掉300ms的点击延迟。

      <meta name="viewport" content="user-scalable=no">
    • 利用touch事件解决:

      • 当我们手指触摸屏幕时,记录当前触摸时间。
      • 当我们手指离开屏幕时,用离开的时间减去触摸的时间。
      • 如果时间小于150ms,并且没有滑动屏幕,那么我们就定义为点击。

8、本地存储

  • 本地存储特性:
    • 数据存储在用户浏览器中。
    • 容量较大,sessionStorage 约 5M,localStorage 约 20M。
    • 只能存储字符串,可以将对象 JSON.stringify()编码后存储。
  • window.sessionStorage:
    • 特点:
      • 生命周期为关闭浏览器窗口。
      • 在同一个页面下数据可以共享。
      • 以键值对的形式存储使用。
    • 存储数据:
      • sessionStorage.setItem(key,value)
    • 获取数据:
      • sessionStorage.getItem(key)
    • 删除数据:
      • sessionStorage.removeItem(key)
    • 删除所有数据:
      • sessionStorage.clear()
  • Window.localStorage:
    • 特点:
      • 生命周期永久生效,除非手动删除,否则关闭页面也会存在。
      • 可以多页面共享(同一浏览器)。
      • 以键值对的形式存储使用。
    • 存储数据:
      • localStorage.setItem(key,value)
    • 获取数据:
      • localStorage.getItem(key)
    • 删除数据:
      • localStorage.removeItem(key)
    • 删除所有数据:
      • localStorage.clear()