计算机入门

1.计算机编程基础

1.1 编程

编程: 就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程

计算机程序:就是计算机所执行的一系列的指令集合,而程序全部都是用我们所掌握的语言来编写的,所以人们要控制计算机一定要通过计算机语言向计算机发出命令。

注意: 上面所定义的计算机指的是任何能够执行代码的设备,可能是智能手机、ATM 机、黑莓 P1、服务器等等。

1.2 计算机语言

计算机语言指用于人与计算机之间通讯的语言,它是人与计算机之间传递信息的媒介

计算机语言的种类非常的多,总的来说可以分成机器语言汇编语言高级语言三大类。实际上计算机最终所执行的都是机器语言,它是由”0”和”1”组成的二进制数,二进制是计算机语介言的基础。

0=00000000 	1=00000001	2=00000010
3=00000011	4=00000100	5=00000101	6=00000110
7=00000111	8=00001000	9=00001001	10=00001010

1.3 编程语言

可以通过类似于人类语言的”语言”来控制计算机,让计算机为我们做事情,这样的语言就叫做 **编程语言(ProarammingLanguage)**。

编程语言是用来控制计算机的一系列指令,它有固定的格式和词汇(不同编程语言的格式和词汇不一样),必须遵守。

如今通用的编程语言有两种形式:汇编语言和高级语言。

  • 汇编语言和机器语言实质是相同的,都是直接对硬件操作,只不过指令采用了英文缩写的标识符,容易识别和记忆.
  • 高级语言主要是相对于低级语言而言,它并不是特指某一种具体的语言,而是包括了很多编程语言,常用的有 C 语言、C++、Java、C#、Python、PHP、JavaScript、Go 语言、ObjectiveC、Swift 等。

1.4 翻译器

高级语言所编制的程序不能直接被计算机识别,必须经过转换才能被执行,为此,我们需要一个翻译器。

翻译器可以将我们所编写的源代码转换为机器语言,这也被称为二进制化。记住 1 和 0。
image-20240828215818211

1.5 编程语言和标记语言区别

编程语言有很强的逻辑和行为能力。在编程语言里,你会看到很多ifelseforwhile等具有逻辑性和行为能力的指令,这是主动的。

标记语言(html)不用于向计算机发出指令,常用于格式化和链接。标记语言的存在是用来被读取的,他是被动的。

1.6 总结

  1. 计算机可以帮助人类解决某些问题
  2. 程序员利用编程语言编写程序发出指令控制计算机来实现这些任务
  3. 编程语言有机器语言、汇编语言、高级语言
  4. 高级语言需要一个翻译器转换为计算机识别的机器语言
  5. 编程语言是主动的有很强的逻辑性

1.7 编译型语言和解释型语言

概述

计算机不能直接理解任何除机器语言以外的语言,所以必须要把程序员所写的程序语言翻译成机器语言才能执行程序。程序语言翻译成机器语言的工具,被称为翻译器

  • 翻译器翻译的方式有两种: 一个是编译,另外一个是解释。两种方式之间的区别在于翻译的时间点不同
  • 编译器是在代码执行之前进行编译,生成中间代码文件
  • 解释器是在运行时进行及时解释,并立即执行(当编译器以解释方式运行的时候,也称之为解释器)
执行过程

image-20240830183214962

1.8 标识符、关键字、保留字

标识符

标识(zhi)符: 就是指开发人员为变量、属性、函数、参数取的名字。

标识符不能是关键字或保留字

关键字

关键字: 是指 JS 本身已经使用了的字,不能再用它们充当变量名、方法名。

包括: break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with 等。

保留字

保留字: 实际上就是预留的”关键字”意思是现在虽然还不是关键字,但是未来可能会成为关键字,同样不能使用它们当变量名或方法名。

2.计算机基础

2.1 计算机组成

image-20240828220424331

2.2 数据存储

  1. 计算机内部使用二进制 0 和 1 来表示数据
  2. 所有数据,包括文件、图片等最终都是以二进制数据(0 和 1)的形式存放在硬盘中的。
  3. 所有程序,包括操作系统,本质都是各种数据,也以二进制数据的形式存放在硬盘中。平时我们所说的安装软件,其实就是把程序文件复制到硬盘
  4. 硬盘、内存都是保存的二进制数据。

2.3 数据存储单位

  • bit < byte < kb < GB < TB<……
    • 位(bit): 1bit 可以保存一个 0 或者 1(最小的存储单位)
    • 字节(Byte):1B=8b
    • 千字节(KB):1KB=1024B
    • 兆字节(MB):1MB=1024KB
    • 吉字节(GB):1GB=1024MB
    • 太字节(TB):1TB=1024GB
    • ……

2.4 程序运行

image-20240828220826659

  1. 打开某个程序时,先从硬盘中把程序的代码加载到内存中
  2. CPU 执行内存中的代码

**注意:**之所以要内存的一个重要原因,是因为 cpu 运行太快了,如果只从硬盘中读数据,会浪费 cpu 性能,

所以,才使用存取速度更快的内存来保存运行时的数据。(内存是电,硬盘是机械)

JavaScript 基础

JavaScript 初始

1.初识 JavaScript

1.1 JavaScript 历史
  • 布兰登:艾奇(BrendanEich,1961 年~)
  • 神奇的大哥在 1995 年利用 10 天完成 JavaScript 设计。
  • 网景公司最初命名为LiveScript,后来在与 Sun 合作之后将其改名为 JavaScript
1.2 JavaScript 是什么
  • JavaScript 是世界上最流行的语言之一,是一种运行在客户端的脚本语言(Script 是脚本的意思)

  • 脚本语言:不需要编译,运行过程中由js解释器(js引擎)逐行来进行解释并执行

  • 现在也可以基于Node.js技术进行服务器端编程

    image-20240828221512945

1.3 JavaScript 的作用

表单动态校验(密码强度检测)(JS 产生最初的目的)

网页特效

服务端开发(Node.js)

桌面程序(Electron)

App(Cordova)

控制硬件-物联网(Ruff)

游戏开发(cocos2d-js)

1.4 HTML/CSS/JS 的关系
  • HTML/CSS 标记语言–描述类语言

    HTML 决定网页结构和内容(决定看到什么),相当于人的身体

    CSS 决定网页呈现给用户的模样(决定好不好看)相当于给人穿衣服、化妆

  • JS 脚本语言–编程类语言

    实现业务逻辑和页面控制(决定功能),相当于人的各种动作

1.5 浏览器执行 JS 简介

浏览器分成两部分渲染引擎JS引擎

  • 渲染引擎:用来解析 HTML 与 CSS,俗称内核,比如 chrome 浏览器的blink,老版本的webkit
  • JS 引擎:也称JS解释器。用来读取网页中的 JavaScript 代码,对其处理后运行,比如 chrome 浏览器的 V8

浏览器本身并不会执行 JS 代码,而是通过内置 JavaScript 引擎(解释器)来执行 JS 代码。JS 引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行,所以 JavaScript 语言归为脚本语言,会逐行解释执行。

image-20240828222353856

1.6 JS 的组成
image-20240828222503677
  1. ECMAScript

ECMAScript是由 ECMA 国际(原欧洲计算机制造商协会)进行标准化的一门编程语言,这种语言在万维网上应用广泛,它往往被称为 JavaScript(网景公司)或 JScript(微软公司),但实际上后两者是 ECMAScript 语言的实现和扩展。

ECMAScript:ECMAScript 规定了 JS 的编程语法和基础核心知识,是所有浏览器厂商共同遵守的一套 JS 语法工业标准。

更多参看 MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/JavaScript_technologies_overview

  1. DOM–文档对象模型
  2. BOM–浏览器对象模型

BOM(Browser ObjectModel,简称BOM)是指浏览器对象模型,它提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。通过 BOM 可以操作浏览器窗口,比如弹出框、控制浏览器跳转、获取分辨率等

1.7JS 的初体验
  1. 行内式的 js,直接写到元素的内部
<!-- 1.行内式的js 直接写到元素的内部 -->
<input type="button" value="李白" onclick="alert('Hello, World!');" />
  • 可以将单行或少量 JS 代码写在 HTML 标签的事件属性中(以 on 开头的属性),如:onclick
  • 注意单双引号的使用:在 HTML 中我们推荐使用双引号,JS 中我们推荐使用单引号
  • 可读性差,在 html 中编写 JS 大量代码时,不方便阅读;
  • 引号易错,引号多层嵌套匹配时,非常容易弄混;
  • 特殊情况下使用
  1. 内嵌式 js
<!-- 2.内嵌式js -->
<script>
  alert("你好,世界!");
</script>
  • 可以将多行 JS 代码写到<script>标签中
  • 内嵌 JS 是学习时常用的方式
  1. 外部文件式
<!-- 3.外链式js -->
<script src="my.js"></script>
// my.js
alert("Hello, World!");
  • 利于 HTML 页面代码结构化,把大段 JS 代码独立到 HTML 页面之外,既美观,也方便文件级别的复用
  • 引用外部 JS 文件script 标签中间不可以写代码
  • 适合于 JS 代码量比较大的情况

2.JavaScript 注释

  • 单行注释 使用//
  • 多行注释 使用/**/

3.JavaScript 输入输出语句

为了方便信息的输入输出,JS 中提供了一些输入输出语句,其常用的语句如下

方法 说明 归属
alert(msg) 浏览器弹出警示框 浏览器
console.log(msg) 浏览器控制台打印输出信息 浏览器
prompt(info) 浏览器弹出输入框,用户可以输入 浏览器

变量

1.变量概述

1.1 什么是变量

变量是用于存放数据的容器。我们通过变量名 获取数据,甚至数据可以修改。

1.2 变量在内存中的存储

本质:变量是程序在内存中申请的一块用来存放数据的空间。

2.变量的使用

变量在使用时分为两步: 1.声明变量 2.赋值

声明变量
// 声明变量
var age; // 声明一个名称为age的变量
  • var 是一个 JS 关键字,用来声明变量(variable 变量的意思)。使用该关键字声明变量后,计算机会自动为变量分配内存空间,不需要程序员管
  • age 是程序员定义的变量名,我们要通过变量名来访问内存中分配的空间
赋值
age = 10;
//给age 这个变量赋值为10
  • =用来把右边的值赋给左边的变量空间中 此处代表赋值的意思
  • 变量值是程序员保存到变量空间里的值
变量的初始化

var age = 18;//声明变量同时赋值为18

3.变量语法扩展

  1. 更新变量

一个变量被重新复赋值后,它原有的值就会被覆盖,变量值将以最后一次赋的值为准。

  1. 同时声明多个变量

同时声明多个变量时,只需要写一个var,多个变量名之间使用英文逗号隔开。

var age = 10,
  name = "s",
  sex = 2;
// **英文逗号**隔开
  1. 声明变量特殊情况
情况 说明 结果
var age; console.log(age); 只声明 不赋值 undefined
console.log(age) 不声明 不赋值 直接使用 报错
age = 10; console.log(age); 不声明 只赋值 10

变量命名规范

  • 由字母(A-Za-z)、数字(0-9)、下划线(_)、美元符号($)组成,如: usrAge, num01, nameR
  • 严格区分大小写。var app;和 var App;是两个变量
  • 不能 以数字开头。 18age 是错误的
  • 不能 是关键字、保留字。例如:var、for、while
  • 变量名必须有意义。MMD BBD nianling → age
  • 遵守驼峰命名法。首字母小写,后面单词的首字母需要大写。myFirstName
  • 推荐翻译网站:有道 爱词霸
  • name一般不要使用作为变量名,可能在某些浏览器会有特殊含义

交换变量案例

// 只对数字类型有效
var a = 10;
var b = 20;
console.log("Before swapping: a = " + a + ", b = " + b);
a = a + b;
b = a - b;
a = a - b;
console.log("After swapping: a = " + a + ", b = " + b);

// 字符串类型
var str1 = "hello";
var str2 = "world";
console.log("Before swapping: str1 = " + str1 + ", str2 = " + str2);
str1 = str1 + str2;
str2 = str1.substring(0, str1.length - 5);
str1 = str1.substring(str1.length - 5);
console.log("After swapping: str1 = " + str1 + ", str2 = " + str2);

数据类型

1.数据类型简介

1.1 为什么需要数据类型

在计算机中,不同的数据所需占用的存储空间是不同的,为了便于把数据分成所需内存大小不同的数据,充分利用存储空间,于是定义了不同的数据类型。

1.2 变量的数据类型

变量是用来存储值的所在处,它们有名字和数据类型。变量的数据类型决定了如何将代表这些值的位存储到计算机的内存中。JavaScript 是一种弱类型或者说动态语言。这意味着不用提前声明变量的类型,在程序运行过程中,类型会被自动确定。

var age = 10; // 这是一个数字型
var areYouok = "是的"; //这是一个字符串

在代码运行时,变量的数据类型是由 JS 引擎根据**=右边变量值的数据类型来判断**的,运行完毕之后,变量就确定了数据类型
JavaScript 拥有动态类型,同时也意味着相同的变量可用作不同的类型

var x = 6; //x为数字
var x = "Bill"; //x为字符串
1.3 数据类型的分类

JS 把数据类型分为两类:

  • 简单数据类型(Number,String,Boolean,Undefined,Null)
  • 复杂数据类型(object)

2.简单数据类型

2.1 简单数据类型(基本数据类型)

JavaScript 中的简单数据类型及其说明如下

简单数据类型 说明 默认值
Number 数字型,包含 整型值和浮点型值,如 21、0.21 0
Boolean 布尔值类型,如 true、false,等价于 1 和 0 false
String 字符串类型,如 “张三” 注意:在 JS 里面,字符串都带引号 “”
Undefined var a; 声明了变量 a 但是没有给值,此时 a = undefined undefined
Null var a = null; 声明了变量 a 为空值 null
2.2 数字型 Number

JavaScript 数字类型既可以用来保存整数值,也可以保存小数(浮点数)。

var age = 21; // 整数
var age = 21.3747; // 小数

1.数字型进制

最常见的进制有二进制、八进制、十进制、十六进制。

//1.八进制数字序列范围:0~7
var numl = 07; // 对应十进制的7
var num2 = 019; //对应十进制的19
var num3 = 08; //对应十进制的8

//2.十六进制数字序列范围:0~9以及A~F
var num = 0xa;

3.数字型三个特殊值

alert(Infinity); //Infinity
alert(-Infinity); //-Infinity
alert(NaN); // NaN

Infinity 代表无穷大,大于任何数值

-Infinity 代表无穷小,小于任何数值

NaN,Not a number 代表一个非数值

  1. 非数值型 NaN

使用isNaN()来判断是否是非数字

2.3 String 字符串型
  1. 使用引号包裹起来的称为字符串类型

字符串型可以是引号中的任意文本,其语法为双引号””和 单引号’

var strMsg="我爱北京天安门~";// 使用双引号表示字符串v
var strMsg2='我爱吃猪蹄~';	//使用单引号表示字符串
// 常见错误
var strMsg3=我爱大肘子;	//报错,没使用引号,会被认为是js代码,但js没有这些语法

因为 HTML 标签里面的属性使用的是双引号,JS 这里我们更推荐使用单引号

// 引号的嵌套
var str = 'Hello, "World"!';
console.log(str);

// 字符串的拼接
var str1 = "Hello";
var str2 = "World";
console.log(str1 + "" + str2);
  1. 字符串转义符

类似 HTML 里面的特殊字符,字符串中也有特殊字符,我们称之为转义符转义符都是\开头的,常用的转义符及其说明如下

转义符 解释说明
\n 换行符,n 是 newline 的意思
\\ 斜杠 \
\' ‘ 单引号
\" “ 双引号
\t tab 缩进
\b 空格,b 是 blank 的意思
  1. 字符串长度

字符串是由若干字符组成的,这些字符的数量就是字符串的长度。通过字符串的length 属性可以获取整个字符串的长度。

  1. 字符串拼接

多个字符串之间可以使用+进行拼接,其拼接方式为字符串 + 任何类型 = 拼接之后的新字符串

// 字符串的拼接
var str1 = "Hello";
var num = 100;
console.log(str1 + num);
//输出Hello100
2.4 布尔类型 Boolean

布尔类型有两个值:truefalse,其中 true 表示真(对),而 false 表示假(错)。

布尔型和数字型相加的时候,true 的值为 1,false 的值为 0

console.log(true + 1); //2
console.log(false + 1); //1
2.5 Undefined 和 Null

-个声明后没有被赋值的变量会有一个默认值undefined(如果进行相连或者相加时,注意结果)

var variable;
console.log(variable); //undefined
console.log("你好:" + variable); //你好:undefined
undefinedconsole.log(11 + variable); // NaN
console.log(true + variable); //NaN

一个声明变量给 null 值,里面存的值为空(学习对象时,我们继续研究 null)

var vari = null;
console.log("你好" + vari); //你好nu11
console.log(11 + vari); //11
console.log(true + vari); //1

3.获取检测变量的数据类型

3.1typeof可用来获取检测变量的数据类型
var a = 10;
console.log(typeof a); // output: number

var b = "hello";
console.log(typeof b); // output: string

var c = true;
console.log(typeof c); // output: boolean

var d = null;
console.log(typeof d); // output: object

var e = undefined;
console.log(typeof e); // output: undefined

var f = function () {};
console.log(typeof f); // output: function

var g = {};
console.log(typeof g); // output: object

var h = [];
console.log(typeof h); // output: object
  • prompt()获取的是String 类型
3.2 字面量

字面量是在源代码中一个固定值的表示法,通俗来说,就是字面量表示如何表达这个值

数字字面量: 8,9,10

字符串字面量: ‘黑马程序员’,”大前端”

布尔字面量: true,false

4.数据类型转换

4.1 什么是数据类型转换

使用表单、prompt 获取过来的数据默认是字符串类型的,此时就不能直接简单的进行加法运算,而需要转换变量的数据类型。通俗来说,就是把一种数据类型的变量转换成另外一种数据类型

4.2 转换成字符串类型
方式 说明 案例
toString() 转成字符串 var num = 1; alert(num.toString());
String() 强制转换 转成字符串 var num = 1; alert(String(num));
加号拼接字符串 和字符串拼接结果都是字符串 var num = 1; alert(num + "我是字符串");
  • toString()String() 使用方式不一样。
  • 三种转换方式,我们更喜欢用第三种加号拼接字符串转换方式,这一种方式也称之为隐式转换
4.3 转换成数字型(重点)
  • parseInt(),取整函数,截断小数部分,返回整数部分
// 1.parseInt()
var str1 = "100.5"; // 100
var num1 = parseInt(str1);
console.log(num1);

console.log(parseInt("120px")); // 120,会从字符串中取出数字,但必须是以数字开头
  • parseFloat(),转变成浮点数
// 2.parseFloat()
var str2 = "10.5";
var num2 = parseFloat(str2);
console.log(num2);
console.log(parseFloat("120.45px")); // 120.45,会从字符串中取出数字,但必须是以数字开头
console.log(parseFloat("rem120.45px")); // NaN
  • Number()函数
// 3.Number()
var str3 = "10";
var num3 = Number(str3);
console.log(num3);
  • 算数运算符隐式转换
//利用算数 - / *运算符实现转换效果
var str4 = "10";
var num4 = str4 - 0;
console.log(num4);

var str5 = "10.5";
var num5 = str5 * 1;
console.log(num5);
方式 说明 案例
parseInt(string) 函数 将 string 类型转成整数数值类型 parseInt('78')
parseFloat(string) 函数 将 string 类型转成浮点数数值类型 parseFloat('78.21')
Number() 强制转换函数 将 string 类型转成数值类型 Number('12')
js 隐式转换 (- * /) 利用算术运算隐式转换为数值类型 '12' - 0或者'12' - '0'
Number.isInteger() 检查是否为整数 console.log(Number.isInteger('4'));false
4.4 转化成布尔类型
  • 代表空、否定的值会被转换为false,如‘’0NaNnullundefined
  • 其余值都会被转换为true
console.log(Boolean("")); // false
console.log(Boolean(0)); // false
console.log(Boolean(NaN)); // false
console.log(Boolean(null)); // false
console.log(Boolean(undefined)); // false
console.log(Boolean("小徐")); // true
console.log(Boolean(12)); // true
方式 说明 案例
Boolean() 函数 其他类型转成布尔值 Boolean('true')

JavaScript 运算符

1.运算符

运算符(operator)也被称为操作符,是用于实现赋值、比较和执行算数运算等功能的符号

2.算数运算符

2.1 算术运算符概述

概念: 算术运算使用的符号,用于执行两个变量或值的算术运算。

运算符 描述 实例
+ 10 + 20 = 30
- 10 - 20 = -10
* 10 * 20 = 200
/ 10 / 20 = 0.5
% 取余数 (取模) 返回除法的余数 9 % 2 = 1(常用于检测是否能整除)
2.2 浮点数的精度问题

浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数

var result = 0.1 + 0.2; //结果不是 0.3,而是:0.30000000000000004
console.log(0.07 * 100); //结果不是7, 而是:7.000000000000001

var num = 0.1 + 0.2;
console.log(num == 0.3); // false

所以:不要直接判断两个浮点数是否相等!

2.3 表达式和返回值

表达式: 是由数字、运算符、变量等以能求得数值的有意义排列方法所得的组合简单理解:是由数字、运算符、变量等组成的式子

var result =  1 + 1; //2
`1+1`是表达式,把值返回给result变量

3.递增和递减运算符

概述

如果需要反复给数字变量添加或减去 1,可以使用递增(++)和递减(–)运算符来完成.

在 JavaScript 中,递增(++)和递减(–)既可以放在变量前面,也可以放在变量后面。放在变量前面时我们可以称为前置递增(递减)运算符,放在变量后面时,我们可以称为后置递增(递减)运算符

递增运算符
  • 前置递增运算符**(先加后用)**
// 前置运算符 先+1在使用
var num = 11;
console.log(++num); // 12
  • 后置递增运算符**(先用后加)**
// 后置运算符 先使用在+1
var num = 10;
console.log(num++); // 10
console.log(num); // 11
递减运算符
  • 前置递减运算符**(先加后用)**
// 前置运算符 先-1在使用
var num = 11;
console.log(++num); // 10
  • 后置递减运算符**(先用后加)**
// 后置运算符 先使用在-1
var num = 10;
console.log(num--); // 10
console.log(num); // 9
前置递增和后置递增小结
  • 前置递增和后置递增运算符可以简化代码的编写,让变量的值+1 比以前写法更简单
  • 单独使用时,运行结果相同
  • 与其他代码联用时,执行结果会不同
  • 后置:先原值运算,后自加
  • 前置:先自加,后运算

4.比较运算符

概念:比较运算符(关系运算符)是两个数据进行比较时所使用的运算符比较运算后,会**返回一个布尔值(true/false)**作为比较运算的结果。

运算符名称 说明 案例 结果
< 小于号 1 < 2 true
> 大于号 1 > 2 false
>= 大于等于号 (大于或者等于) 2 >= 2 true
<= 小于等于号 (小于或者等于) 3 <= 2 false
== 判等号 (会自动转换类型) ‘37’ == 37 true
!= 不等号 37 != 37 false
=== !== 全等 要求值和数据类型都一致 37 === ‘37’ false

=小结

符号 作用 用法
= 赋值 把右边给左边
== 判断 判断两边值是否相等(注意有隐式转换)
=== 全等 判断两边的值和数据类型是否完全相同

5.逻辑运算符

5.1 逻辑运算符概述

概念: 逻辑运算符是用来进行布尔值运算的运算符,其返回值也是布尔值,后面开发中经常用于多个条件的判断

5.2 逻辑运算
  • 布尔值参与逻辑运算

| 逻辑运算符 | 说明 | 案例 |
| ———- | ———————— | ———————– | — | ————- |
| && | “逻辑与” ,简称 “与” and | true && false = false |
| || | “逻辑或” ,简称 “或” or | true | | false = true |
| ! | “逻辑非” ,简称 “非” not | !true = false |

  • 或者表达式参与逻辑运算
5.3 短路运算(逻辑中断)

短路运算的原理: 当有多个表达式(值)时左边的表达式值已经可以确定结果时,就不再继续运算右边的表达式的值;

  • 逻辑与

语法: 表达式 1 && 表达式 2
如果第一个表达式的值为真,则返回表达式 2
如果第一个表达式的值为假,则返回表达式 1

  • 逻辑或

语法: 表达式 1 || 表达式 2
如果第一个表达式的值为真,则返回表达式 1
如果第一个表达式的值为假,则返回表达式 2

// 逻辑与的短路运算:
console.log(123 && 456); // 输出 456
console.log(0 && 456); // 输出 0
console.log(0 && 456 && 789 * 2); // 输出 0
console.log(123 && 456 && 789 * 2); // 输出 789*2 == console.log(123 && (456 && (789 * 2)));
// 逻辑或的短路运算:
console.log(123 || 456); // 输出 123
console.log(0 || 456); // 输出 456
console.log(0 || 456 || 789 * 2); // 输出 456
console.log(0 || "" || 789 * 2); // 输出 789*2 == console.log((0 || "") || (789 * 2));
// 逻辑非的短路运算:如果操作数为假,则返回真,否则返回假
console.log(!123); // 输出 false
console.log(!0); // 输出 true
console.log(!""); // 输出 true
console.log(!"0"); // 输出 false

注意点

var num=;
console.log(123 || num++);
console.log(num);
//结果为123,根本没有进行到num++

6.赋值运算符

概念:用来把数据赋值给变量的运算符。

赋值运算符 说明 案例
= 直接赋值 var usrName = '我是值';
+=, -= 加、减一个数后再赋值 var age = 10; age += 5; // 15
*=, /=, %= 乘、除、取模后再赋值 var age = 2; age *= 5; // 10

7.运算符优先级

| 优先级 | 运算符 | 顺序 |
| —— | ———- | ——————- | — | — |
| 1 | 小括号 | () |
| 2 | 一元运算符 | ++ -- ! |
| 3 | 算数运算符 | 先 * / %+ - |
| 4 | 关系运算符 | > >= < <= |
| 5 | 相等运算符 | == != === !== |
| 6 | 逻辑运算符 | 先 && | | |
| 7 | 赋值运算符 | = |
| 8 | 逗号运算符 | , |

流程控制

在一个程序执行的过程中,各条代码的执行顺序对程序的结果是有直接影响的。很多时候我们要通过控制代码的执行顺序来实现我们要完成的功能。

简单理解:流程控制就是来控制我们的代码按照什么结构顺序来执行

流程控制主要有三种结构,分别是顺序结构分支结构循环结构,这三种结构代表三种代码执行的顺序。

image-20240831110247247

1.顺序控制

顺序结构是程序中最简单、最基本的流程控制,它没有特定的语法结构,程序会按照代码的先后顺序,依次执行程序中大多数的代码都是这样执行的。

2.分支结构

由上到下执行代码的过程中,根据不同的条件,执行不同的路径代码(执行代码多选一的过程),从而得到不同的结果

if 语句

if 语句是一种控制流语句,用于根据指定条件的真伪来执行不同的代码块。它通常用于简单条件判断,适合处理逻辑表达式的评估,并根据条件的结果执行不同的操作。

语法:

if语法结构

if (条件表达式1) {
    // 条件表达式1为true时执行的代码
} else if(条件表达式2) {
    // 条件表达式2满足时执行的代码
}else {
	// 条件表达式为false时执行的代码
}
条件表达式可以是任意表达式,包括变量、运算符、函数调用等
switch 语句

switch 语句也是多分支语句,它用于基于不同的条件来执行不同的代码。当要针对变量设置一系列的特定值
的选项时,就可以使用 switch。

语法:

switch语法结构

switch (表达式) {
    case1:
        // 值1时执行的代码
        break;
    case2:
        // 值2时执行的代码
        break;
    default:
        // 值都不匹配时执行的代码
}
表达式可以是变量、运算符、函数调用等,值可以是任意值


var num = 2;
switch (num) {
    case 1:
        alert(num + "=1");
        break;
    case 2:	//注意case后面的值要和num全(类型和值)等才行
        alert(num + "=2");
        break;
}
switch语句和if-else-if语句的区别
  1. 一般情况下,它们两个语句可以相互替换
  2. switch..case 语句通常处理 case 为比较确定值的情况,而 if..else..语句更加灵活,常用于范围判断(大于
    等于某个范围)
  3. switch 语句进行条件判断后直接执行到程序的条件语句,效率更高。而 if..else 语句有几种条件,就得判断多少次。
  4. 当分支比较少时,if…else 语句的执行效率比 switch 语句高
  5. 当分支比较多时,switch 语句的执行效率比较高,而且结构更清晰,

3.三元运算符和三元表达式

三元运算符(Ternary Operator)是一种在编程语言中用于简化条件语句的表达方式。它通常用于根据某个条件返回两个值之一。

三元运算符的语法如下:

条件 ? 表达式1 : 表达式2;

let a = 5;
let b = 10;

// 使用三元运算符
let max = a > b ? a : b; // max将会是10
  • 如果条件为真(true),则返回 表达式1 的值。
  • 如果条件为假(false),则返回 表达式2 的值。

4.循环结构

4.1 循环

在实际问题中,有许多具有规律性的重复操作,因此在程序中要完成这类操作就需要重复执行某些语句

4.2 for 循环

在程序中,一组被重复执行的语句被称之为循环体,能否继续重复执行,取决于循环的终止条件。由循环体及循环的终止条件组成的语句,被称之为循环语句

语法结构

for (初始化变量; 条件表达式; 操作表达式) {
  //循环体
}
  1. 初始化变量 就是用var 声明的一个普通变量,通常用于作为计数器使用
  2. 条件表达式 就是用来决定每一次循环是否继续执行,就是终止的条件
  3. 操作表达式 是每次循环最后执行的代码,经常用于我们计数器变量进行更新(递增或者递减)
4.3 while 循环
while (条件表达式) {
  //循环体
}

当条件表达式为真时,执行循环体

4.4 do-while 循环
do {
  //循环体
} while (条件表达式);

先执行一次循环体,在判断条件表达式,如果为真,再次执行循环体

do…while 循环语句至少会执行一次循环体代码

break 和 continue

continue 关键字

continue关键字用于立即跳出本次循环继续下一次循环(本次循环体中 continue 之后的代码就会少执行一次)。

例如,吃 5 个包子,第 3 个有虫子,就扔掉第 3 个,继续吃第 4 个第 5 个包子,其代码实现如下

for (var i = 1; i <= 5; i++) {
  if (i == 3) {
    continue;
  } else {
    console.log("我吃了第" + i + "个包子");
  }
}
break 关键字

break 关键字用于立即跳出整个循环(循环结束)
例如,吃 5 个包子,吃到第 3 个发现里面有半个虫子,其余的不吃了

数组

1.数组的概念

数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一
种将一组数据存储在单个变量名下的优雅方式。

2. 创建数组

  1. 使用 new 关键字创建数组
var 数组名 = new Arr();
var arr = new Array(); //创建一个新的空数组
  1. 利用数组字面量创建数组
//1.使用数组字面量方式创建空的数组
var 数组名 = [];

//2.使用数组字面量方式创建带初始值的数组
var 数组名 =["小白"'小黑''大黄'"瑞奇"];
  • 数组的字面量是方括号[]
  • 声明数组并赋值称为数组的初始化

3.获取数组里的元素

3.1 数组的索引

索引(下标):用来访问数组元素的序号(数组下标从 0 开始)。

3.2 遍历数组

使用循环,不断更改索引值,遍历数组

for (var i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

4.数组中新增元素

4.1 通过修改 length 长度新增数组元素
  • 可以通过修改 length 长度来实现数组扩容的目的
  • length 属性是可读写的
var arr = [1, 2, 3, 4, 5];
console.log(arr.length); // 5
arr.length = 8;
console.log(arr); // [1, 2, 3, 4, 5, undefined, undefined, undefined]
arr.length = 3;
console.log(arr); // [1, 2, 3]

声明变量未给值,默认值就是 undefined

4.2 通过数组索引号添加元素
// 数组的索引添加元素
arr[3] = 6;
console.log(arr); // [1, 2, 3, 6]
  • 可以通过修改数组索引的方式追加数组元素
  • 不能直接给数组名赋值,否则会覆盖掉以前的数据

5.数组案例

反转数组
var arr1 = [1, 2, 3, 4];
var arr2 = [];
for (var i = arr1.length - 1; i >= 0; i--) {
  arr2[arr2.length] = arr1[i];
}
数组排序(冒泡排序)
var arr = [5, 3, 8, 6, 2, 7, 1, 4];
function bubbleSort(arr) {
  var len = arr.length;
  for (var i = 0; i < len - 1; i++) {
    for (var j = 0; j < len - i - 1; j++) {
      if (arr[j] > arr[j + 1]) {
        var temp = arr[j];
        arr[j] = arr[j + 1];
        arr[j + 1] = temp;
      }
    }
  }
  return arr;
}
console.log(bubbleSort(arr));

JavaScript 函数

1.函数的概念

在 JS 里面,可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用,虽然 for 循环语句也能实现一些简单的重复操作,但是比较具有局限性,此时我们就可以使用 JavaScript 中的函数

函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。

2.函数的使用

声明函数

语法规范

function 函数名(参数...) {
    函数体代码
}
function getSum(a, b) {
    max = a > b ? a : b;
    min = a < b ? a : b;
    var sum = 0;
    for (var i = min; i <= max; i++) {
        sum += i;
    }
    return sum;
}
console.log(getSum(100, 10));
调用函数

函数不调用,自己不调用

调用方法: 函数名();

3.函数的参数

利用函数的参数,实现不同的执行结果

**参数的作用:**在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去

3.1 形参和实参

定义时写形参,调用时传实参(形参是接收实参的)

// a和b是形参
function getSum(a, b) {
  max = a > b ? a : b;
  min = a < b ? a : b;
  var sum = 0;
  for (var i = min; i <= max; i++) {
    sum += i;
  }
  return sum;
}
// 100,10是实参
console.log(getSum(100, 10));
3.2 形参和实参不匹配的问题
function add(a, b) {
  return a + b;
}
// 1.形参和实参个数匹配,正常输出
console.log(add(1, 2)); // 3

// 2.形参个数小于实参
console.log(add(1, 2, 3)); // 会被截断参数,只取到1和2,3被忽略

//3.如果实参的个数小于形参的个数
//形参可以看做是不用声明的变量,num2 是一个变量但是没有接受值 结果就是undefined
console.log(add(1)); // 1 + undefined = NaN

注意:在 JavaScript 中,形参的默认值是 undefined.

4.函数的返回值

4.1return 返回结果

只要函数遇到 return,就把结果返回给函数的调用者,后面的代码不执行,函数名() = return 后面的结果

4.2return 终止函数
function Sum(a, b) {
  return a + b;
  console.log("这句话是不会被输出的,因为遇到return就终止函数");
}
Sum();
4.3 只能返回一个值
function Sum(a, b) {
  return a, b;
}
console.log(Sum(1, 2)); // 输出2

return 语句只返回一个值(若有多个,则返回最后一个)

4.4 函数没有 return 语句 返回 undefined
function func() {
  console.log("hh");
}
console.log(func()); // undefined

5.arguments 的使用

当我们不确定有多少个参数传递的时候,可以用arguments来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参

// arguments是一个类数组对象,包含了传递给函数的所有参数
function fn() {
  console.log(arguments);
}

fn(1, 2, 3);
类数组对象

arguments 是一个类数组对象,里面有数组的一些属性,但并不是真正的数组

  1. length属性
  2. 按照索引方式存储
  3. 没有真正数组的一些方法,例如pop(),push()

6.函数案例

求任意个数的最大值

function getMax() {
  var max = arguments[0];
  for (var i = 0; i < arguments.length; i++) {
    max = max > arguments[i] ? max : arguments[i];
  }
  return max;
}

7.函数的两种声明方式

7.1 命名函数(function)

使用function定义函数

7.2 函数表达式(匿名函数)

语法: var 变量名 = function(){};

8. 函数的内置方法

Function 实例的 apply() 方法会以给定的 this 值和作为数组(或类数组对象)提供的 arguments 调用该函数。

var arr = [1, 2, 3, 4, 5];
Math.max.apply();

JavaScript 作用域

1.作用域

1.1 作用域的概述

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突

2.全局作用域和局部作用域

  • 全局作用域: 整个<script>标签,或者是一个单独的js文件

  • 局部作用域: 在函数内部就是局部作用域,这个代码的名字只在函数内部起效果和作用

3.变量的作用域

3.1 变量作用域的分类

在 JavaScript 中,根据作用域的不同,变量可以分为两种:

  • 局部变量
// 2.局部变量在局部作用域下的变量 后者在函数内部的变量就是 局部变量
// 函数的形参也可以当作局部变量
function fun(argu) {
  var num1 = 10; // num1就是局部变量 只能在函数内部使用
  var num2 = 20;
  fun();
}
  • 全局变量
// 1.全局变量: 在全局作用域下的变量 在全局下都可以使用
// 注意 如果在函数内部 没有声明直接赋值的变量也属于全局变量

var num = 10; //num就是一个全局变量
console.log(num);
function fn() {
  console.log(num);
}
fn();
3.2 从执行效率来看全局变量和局部变量
  1. 全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
  2. 局部变量,当程序执行完毕就会销毁
4. 作用域链
  • 只要是代码,就至少有一个作用域
  • 写在函数内部的局部作用域
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链

链式查找: 内部函数先访问内部变量,如果没有该同名变量,则使用外部函数的变量,再没有则去找全局变量

var num = 0;
function fun1() {
    // 外部函数
    var num = 10;
    function fun2() {
        // 内部函数
        var num = 20;
        console.log(num);
    }
    fun2();
    console.log(num);
}
fun1();
console.log(num);

输出结果: 20 10 0

JavaScript 预解析

预解析

JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析代码执行

预解析:js 引擎会把 js 里面所有的var还有function提升到当前作用域的最前面

代码执行:按照代码书写的顺序从上往下执行

变量预解析和函数预解析

变量提升(预解析)

**变量提升:**就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作

console.log(num); // undefined
var num = 10;

首先进行变量提升,相当于把所有变量(num)定义,执行var num步骤

然后才开始按顺序执行代码,所以输出 undefined

var fun = function () {
  console.log("fun是一个函数变量");
};
fun(); // 报错: fun不是函数

相当于以下代码;
var fun;
var fun = function () {
  console.log("fun是一个函数变量");
};
fun(); // "fun是一个函数变量"
函数预解析

函数提升:就是把所有的函数声明提升到当前作用域的最前面,不调用函数

fun(); // 可以输出
function fun() {
  console.log("hello world");
}

预解析案例

//案例3
var a = 18;
f1();
function f1() {
  var b = 9;
  console.log(a);
  console.log(b);
  var a = "123";
}

相当于以下代码

var a;
function() {
    var b;
    var a
    b = 9;
    console.log(a); // undefined
    console.log(b);	// 9
    a = '123';
}
a = 18;
f1();

var a = b = c = 9; 相当于var a = 9; b = 9; c = 9;

b 和 c 直接赋值,没有 var 声明,当全局变量看

JavaScript 对象

1. 什么是对象?

面向对象(Object Oriented Programming),简称oop

对象是由属性和方法组成的。

  • 属性:事物的特征,在对象中用属性来表示(常用名词)
  • 方法:事物的行为,在对象中用方法来表示(常用动词 )

2. 为什么需要对象

保存一个值时,可以使用变量,保存多个值(一组值)时,可以使用数组。如果要保存一个人的完整信息呢?

这个时候,就需要使用到对象

3. 创建对象的三种方式

3.1 利用字面量创建对象

**对象字面量:**就是花括号{}里面包含了表达这个具体事物(对象)的属性和方法

// 创建空对象
var obj = {};

// 创建对象
var obj = {
  uname: "0zxm",
  age: 18,
  sayHi: function () {
    console.log("hello");
  },
};
  • 里面的属性或者方法我们采取键值对的形式 键 属性名: 值 属性值
  • 多个属性或者方法中间用逗号隔开的
  • 方法冒号后面跟的是一个匿名函数
使用对象
  1. 调用对象的属性,我们采取对象名.属性名或者对象名[‘属性名’]
  2. 调用对象的方法,我们使用对象名.方法名()
3.2 利用 new Object 关键字创建

语法: var obj = new Object(); 创建对象,然后使用对象名.属性名 或者 对象名.方法名()来添加属性和方法

// 创建空对象
var obj = new Object();
obj.uname = "0zxm";
obj.age = 18;
obj.sayHi = function () {
  console.log("hello");
};
3.3 构造函数

语法:function 构造函数名(形参列表){this.属性 = 值;this.方法= function(){}}

使用 new 构造函数名(实参列表);来创建对象

  • 构造函数首字母要大写(规范)
  • 构造函数不需要 return 值

利用构造函数创建对象的过程我们也称为对象的实例化

new 关键字

new 在执行时会做四件事情:

  1. 在内存中创建一个新的空对象。
  2. 让 this 指向这个新的对象。
  3. 执行构造函数里面的代码,给这个新对象添加属性和方法。
  4. 返回这个新对象(所以构造函数里面不需要 return)

4. 遍历对象属性

4.1 新的遍历方式for..in..

for...in语句用于对数组或者对象的属性进行循环操作。

// 定义一个对象
var person = {
  name: "John",
  age: 30,
  city: "New York",
};

// 使用for-in语句遍历对象
for (var key in person) {
  console.log(key + " : " + person[key]);
}

5. 对象点语法和方括号语法

在JavaScript中,对象的属性可以通过两种语法来访问:点语法(.)和方括号语法([])。这两种语法各有特点,适用于不同的场景。

1. 点语法(.

点语法是最常见的属性访问方式,它用于访问对象的属性。语法格式为:object.propertyName

使用场景

  • 已知属性名:当属性名是一个有效的标识符(即符合变量命名规则,如字母、数字、下划线等,且不能以数字开头)时,可以使用点语法。
  • 代码简洁:点语法更简洁,可读性更高。

示例

const person = {
  name: "Alice",
  age: 25,
  address: {
    city: "Beijing",
    country: "China"
  }
};

console.log(person.name); // 输出:Alice
console.log(person.address.city); // 输出:Beijing

注意事项

  • 如果属性名包含特殊字符(如空格、破折号、点号等)或以数字开头,则不能使用点语法。例如:

    const obj = {
      "first-name": "John",
      "2ndProperty": "value"
    };
    // 错误:obj.first-name 和 obj.2ndProperty
2. 方括号语法([]

方括号语法用于通过字符串或变量动态访问对象的属性。语法格式为:object['propertyName']object[variableName]

使用场景

  • 动态属性名:当属性名是动态生成的,或者属性名是一个变量时,必须使用方括号语法。
  • 特殊字符属性名:当属性名包含特殊字符(如空格、破折号等)或以数字开头时,只能使用方括号语法。
  • 访问嵌套属性:通过嵌套使用方括号语法,可以访问嵌套对象的属性。

示例

const person = {
  name: "Alice",
  age: 25,
  address: {
    city: "Beijing",
    country: "China"
  }
};

// 使用字符串访问属性
console.log(person['name']); // 输出:Alice

// 使用变量访问属性
const key = 'age';
console.log(person[key]); // 输出:25

// 访问包含特殊字符的属性
const obj = {
  "first-name": "John",
  "2ndProperty": "value"
};
console.log(obj['first-name']); // 输出:John
console.log(obj['2ndProperty']); // 输出:value

// 访问嵌套属性
console.log(person['address']['city']); // 输出:Beijing
3. 点语法与方括号语法的对比
特点 点语法(. 方括号语法([]
可读性 更简洁,可读性高 稍显复杂,但更灵活
适用场景 属性名是已知的、有效的标识符 属性名是动态的、包含特殊字符或以数字开头
性能 略微优于方括号语法 略微低于点语法,但差异通常可以忽略不计
动态访问 不支持 支持,可以通过变量动态访问属性

JavaScript 内置对象

1. 内置对象

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

  • 前面两种对象是 JS 基础内容,属于ECMAScript;第三个浏览器对象属于我们 JS 独有的API

2. 查文档

2.1 MDN

学习一个内置对象的使用,只要学会其常用成员的使用即可,我们可以通过查文档学习,可以通过MDN/W3C来查询。

Mozilla 开发者网络(MDN)提供了有关开放网络技术(Open Web)的信息,包括 HTML、CSS 和万维网及 HTML5 应用的 API

MDN: https://developer.mozilla.org/zh-CN/

2.2 如何学习对象中的方法
  1. 查阅该方法的功能
  2. 查看里面参数的意义和类型
  3. 查看返回值的意义和类型

3. Math 对象

常用方法和成员
  • Math.PI - Π 常量

  • Math.max() - 传入任意个数值,如果给定的参数中至少有一个参数无法被转换成数字,则返回NaN,否则返回最大值,如果参数为空,返回-Infinity

  • Math.floor() - 向下取整

  • Math.ceil() - 向上取整

  • Math .round() - 四舍五入版,就近取整 注意 -3.5 结果是 -3,其他数字都是四舍五入,但是 .5 特殊,它往大了取

  • Math.abs() - 绝对值(会把字符串变量隐式转换成数字)

random()函数

返回值: [0, 1)的一个浮点数

参数: 不需要带参数

我们想要得到两个数之间的随机整数,包含这两个数,可以使用getRandomIntInclusive方法

function getRandomIntInclusive(min, max) {
  const minCeiled = Math.ceil(min);
  const maxFloored = Math.floor(max);
  return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // 包含最小值和最大值
}

4.Date 对象

Date 对象必须使用new Date();构造函数来创建日期对象

4.1 构造函数
  1. 空参构造: 返回系统当前时间
  2. 带参(数字)构造: var date = new Date(2019,10,1);输出的却是 Nov,因为是从 0 开始
  3. 带参(字符串)构造: var date = new Date("2018-10-14");
4.2 日期格式化
方法名 说明 代码
getFullYear() 获取当年 dObj.getFullYear()
getMonth() 获取当月(0-11) dObj.getMonth()
getDate() 获取当天日期 dObj.getDate()
getDay() 获取星期几(周日 0 到周六 6) dObj.getDay()
getHours() 获取当前小时 dObj.getHours()
getMinutes() 获取当前分钟 dObj.getMinutes()
getSeconds() 获取当前秒钟 dObj.getSeconds()
4.3 获取日期的总的毫秒形式(时间戳)

Date 对象是基于 1970 年 1 月 1 日(世界标准时间)起的毫秒数

为什么计算机起始时间从 1970 年开始?

我们经常利用总的毫秒数来计算时间,因为它更精确

  • valueOf()函数
  • getTime()函数
  • var date = +new Date();
  • Date.now()
var date = new Date();
console.log(date.valueOf());
console.log(date.getTime());
console.log(+new Date());
console.log(Date.now());
4.4 案例
function countDown(time) {
  let nowTime = Date.now();
  let inputTime;
  try {
    inputTime = new Date(time).getTime(); // 用户输入的时间
  } catch (e) {
    console.error("Invalid date format");
    return "Invalid date format";
  }
  let times = inputTime - nowTime; // 剩余时间总的毫秒数
  if (times < 0) return "Countdown expired";

  let d = Math.floor(times / (1000 * 60 * 60 * 24)); // 天
  let h = Math.floor((times / (1000 * 60 * 60)) % 24); // 时
  let m = Math.floor((times / (1000 * 60)) % 60); // 分
  let s = Math.floor((times / 1000) % 60); // 秒

  return `${d}${h}${m}${s}`;
}

console.log(countDown("2024-12-31"));

5.Array 数组对象

5.1 创建数组
  • 利用数组字面量: var arr = [1, 2, 3];
  • 利用 new 关键字:
    • var arr = new Array(); 创建一个空数组
    • var arr = new Array(2); 创建一个长度为 2 的空数组,里面有两个空数组元素
    • var arr = new Array(2,3); 创建一个长度为 2 的数组,里面存放 2 和 3
5.2 检测是否为数组

instanceof / Array.isArray() 可以用来检测是否为数组

// 检测是否为数组
var arr = [];
var obj = {};

// 使用 instanceof 检测是否为数组
try {
  console.log(arr instanceof Array); // true
  console.log(obj instanceof Array); // false
} catch (e) {
  console.error("Error with instanceof check:", e);
}

// 使用 Array.isArray 检测是否为数组(H5新增的方法,ie9以上版本支持)
try {
  console.log(Array.isArray(arr)); // true
  console.log(Array.isArray(obj)); // false
} catch (e) {
  console.error("Error with Array.isArray check:", e);
}
5.3 数组添加和删除元素
方法名 说明 返回值
push(参数 1, …) 在数组末尾添加一个或多个元素,会修改原数组。 返回新数组的长度
pop() 删除数组最后一个元素,数组长度减 1,无需参数,会修改原数组。 返回被删除元素的值
unshift(参数 1, …) 在数组开头添加一个或多个元素,会修改原数组。 返回新数组的长度
shift() 删除数组的第一个元素,数组长度减 1,无需参数,会修改原数组。 返回删除的第一个元素的值
// pop() 方法用于删除并返回数组的最后一个元素,并将数组长度减一。
// push() 方法用于在数组的末尾添加一个或多个元素,并返回新的长度。
var arr = new Array(1, 2, 3);
arr.push(4, "pink"); // 添加元素到数组末尾
console.log(arr); // [1, 2, 3, 4]
arr.pop();
console.log(arr); // [1, 2, 3]

// shift() 方法用于删除并返回数组的第一个元素,并将数组长度减一。
// unshift() 方法用于在数组的开头添加一个或多个元素,并返回新的长度。
var arr = new Array(1, 2, 3);
arr.unshift(0, "red"); // 添加元素到数组开头
console.log(arr); // [0, "red", 1, 2, 3]
arr.shift();
console.log(arr); // ["red", 1, 2, 3]
5.4 数组排序
  • reserve(): 翻转函数
  • sort(): 排序函数,不加任何参数时,只能对个位数进行排序,否则会出错.可以自己定义排序规则
// 翻转数组
var arr = [3, 2, 1];
var arr2 = arr.reverse();
console.log(arr2); // [1, 2, 3]

// (数组排序)冒泡排序
var arr3 = [3, 4, 7, 1, 6, 2, 9];
sorted_arr = arr3.sort(function (a, b) {
  return a - b; // 升序
});
console.log(sorted_arr); // [1, 2, 3, 4, 6, 7, 9]

Array.prototype.sort() - JavaScript | MDN (mozilla.org)

5.5 数组索引方法
方法名 说明 返回值
indexOf() 数组中查找给定元素的第一个索引 如果存在返回索引号,如果不存在,则返回 -1。
lastIndexOf() 在数组中的最后一个的索引 如果存在返回索引号,如果不存在,则返回 -1。
5.6 数组转换成字符串
方法名 说明 返回值
toString() 把数组转换成字符串,逗号分隔每一项 返回一个字符串
join(‘分隔符’) 方法用于把数组中的所有元素转换为一个字符串 返回一个字符串
5.7 其他方法
方法名 说明 返回值
concat() 连接两个或多个数组,不影响原数组 返回一个新的数组
slice() 数组截取,slice(begin, end) 返回被截取项目的新数组
splice() 数组删除,splice(第几个开始, 要删除个数) 返回被删除项目的新数组(注意:会影响原数组)

6.字符串对象

6.1 基本包装类型

var itr = 'andy'; console.log(str.length);
对象才有属性和方法复杂数据类型才有属性和方法,简单数据类型为什么会有lenght 属性呢?

基本包装类型: 就是把简单数据类型包装成为了复杂数据类型

  1. 把简单数据类型包装为复杂数据类型var temp = new String('andy');
  2. 把临时变量的值给 strstr = temp;
  3. 销毁这个临时变量temp = null;

为了方便操作基本数据类型,JavaScript 还提供了三个特殊的引用类型:StringNumberBoolean基本包装类型就是把简单数据类型包装成为复杂数据类型,这样基本数据类型就有了属性和方法

6.2 字符串的不可变

指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存空间。

var str = "abc";
str = "hello";
//当重新给 str 赋值的时候,常量"abc'不会被修改,依然在内存中
//重新给字符串赋值,会重新在内存中开辟空间,这个特点就是字符串的不可变
//由于字符串的不可变,在大量拼接字符串的时候会有效率问题
var str = "";
for (var i = 0; i < 100000; i++) {
  str += i;
  console.log(str);
} //这个结果需要花费大量时间来显示,因为需要不断的开辟新的空间
6.3 根据字符返回位置

操作完成会返回一个新的字符串。字符串所有的方法,都不会修改字符串本身(字符串是不可变的)

方法名 说明 返回值
indexOf(要查找的字符,起始的位置) 字符串中查找给定元素的第一个索引 如果存在返回索引号,如果不存在,则返回 -1。
lastIndexOf() 在字符串中的最后一个的索引 如果存在返回索引号,如果不存在,则返回 -1。
6.4 根据位置返回字符(重点)
方法名 说明 使用
charAt(index) 返回指定位置的字符(index 字符串的索引号) str.charAt(0)
charCodeAt(index) 获取指定位置字符的 ASCII 码(index 索引号) str.charCodeAt(0)
str[index] 获取指定位置处字符 HTML5,IE8+ 支持,等效于 charAt()
6.5 字符串的其他方法
方法名 说明
concat(str1, str2, str3…) concat() 方法用于连接两个或多个字符串。拼接字符串,等效于 +,更常用
substr(start, length) 从 start 位置开始(索引号),length 取的个数(重点记住这个)
slice(start, end) 从 start 位置开始,截取到 end 位置,end 取不到(它们俩都是索引号)
substring(start, end) 从 start 位置开始,截取到 end 位置,end 取不到。基本和 slice 相同,但不接受负值
replace(‘被替换的字符’,”替换为的字符”) 默认只会把字符串中出现的第一个被替换字符替换
split(‘分隔符’) 把字符串根据给定的分割符划分成数组
  • toUpperCase() //转换大写
  • toLowerCase() //转换小写

JavaScript 简单数据类型和复杂数据类型

1.简单类型与复杂类型

简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型

  • 值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
    • string ,number ,boolean ,undefined ,null(特殊,空对象)
  • 引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
    • 通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date 等

2.堆和栈

堆栈空间分配区别:

  1. 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。其操作方式类似于数据结构中的栈,简单数据类型存放到栈里面
  2. 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放,若程序员不释放,由垃圾回收机制回收。复杂数据类型存放到堆里面
image-20240905110353348

注意: JavaScript 中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言

  • 简单数据类型是存放在栈里面 里面直接开辟一个空间存放的是值
  • 复杂数据类型 首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据(真正的对象实例)

3.简单类型传参

函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。

function fn(a) {
  a++;
  console.log(a);
}
var x = 10;
fn(x);
console.log(x);

4.复杂类型传参

函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同个堆地址,所以操作的是同一个对象

function Person(name) {
  this.name = name;
}

function f1(x) {
  // x=p
  console.log(x.name); // 2. 这个输出什么?    刘德华
  x.name = "张学友";
  console.log(x.name); // 3. 这个输出什么?    张学友
}

var p = new Person("刘德华");
console.log(p.name); // 1. 这个输出什么 ?  刘德华
f1(p);
console.log(p.name); // 4. 这个输出什么 ?   张学友

WebAPIs

1. WebAPIs 和 JS 基础关联性

1.1 JS 的组成

image-20240905111550131

1.2 JS 基础阶段以及 WebAPIs 阶段

  • JS 基础阶段

    • 我们学习的是 ECMAScript 标准规定的基本语法
    • 要求同学们掌握 Js 基础语法
    • 只学习基本语法,做不了常用的网页交互效果
    • 目的是为了 Js 后面的课程打基础、做铺垫
  • Web APIs 阶段

    • web APIs 是W3C组织的标准
    • web APIs 我们主要学习 DOM 和 BOM
    • web APIs 是我们 Js 所独有的部分
    • 我们主要学习页面交互功能
    • 需要使用 Js 基础的课程内容做基础

2.API 和 WebAPIs

2.1 API

API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

2.2 WebAPIs

Web API 是浏览器提供的一套操作浏览器功能页面元素的 API(BOMDOM)。

MDN 详细 API: https://developer.mozilla.org/zh-CN/docs/Web/API

DOM

1.DOM 简介

1.1 什么是 DOM

文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标记语言(HTML 或者 XML)的标准编程接口。

1.2 DOM 树

image-20240905112511895

  • 文档:一个页面就是一个文档,DOM 中使用 document 表示
  • 元素:页面中的所有标签都是元素,DOM 中使用 element 表示
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM 中使用 node 表示

DOM 把以上内容都看做是对象

2.获取元素

2.1 如何获取页面元素

DOM 在我们实际开发中主要用来操作元素。
我们如何来获取页面中的元素呢?

获取页面中的元素可以使用以下几种方式:

  • 根据 ID 获取
  • 根据标签名获取
  • 通过 HTML5 新增的方法获取
  • 特殊元素获取

2.2 根据 ID 获取

document.getElementById("ID属性");返回的是单个元素(查找到的第一个 id 匹配的标签)

<div id="time">2024-09-05</div>
<!-- 1.因为我们文档页面从上往下加载,所以先得有标签 所以我们script写到标签的下面
2.参数 id是大小写敏感的字符串 -->
<script>
  var timer = document.getElementById("time"); //返回的是DOM的Element对象
  console.log(timer);
  console.log(typeof timer);
  // 打印我们返回的元素对象 更好的查看里面的属性和方法
  console.dir(timer);
</script>

console.dir('timer');打印我们返回的元素对象 更好的查看里面的属性和方法

2.3 根据标签名获取

document.getElementsByTagName("标签名");,取出所有 div 标签,返回的是获取过来元素对象的集合,以伪数组 的形式存储的

<ul>
<li>知否知否,应是绿肥红瘦1</li>
<li>知否知否,应是绿肥红瘦2</li>
<li>知否知否,应是绿肥红瘦3</li>
<li>知否知否,应是绿肥红瘦4</li>
<li>知否知否,应是绿肥红瘦5</li>
</ul>

<script>
var lis = document.getElementsByTagName("li");
for (var i = 0; i < lis.length; i++) {
    console.log(lis[i]);
}
</script>

注意:

  1. 因为得到的是一个对象的集合,所以我们想要操作里面的元素就需要遍历
  2. 得到元素对象是动态的
  • 还可以获取某个元素(父元素)内部所有指定标签名的子元素

注意:父元素必须是单个对象(必须指明是哪一个元素对象,要从伪数组中获取元素),获取的时候不包括父元素自己。

element.getElementsByTagName('标签名');

2.4 通过 HTML5 新增的方法获取

  1. document.getElementsByClassName(‘类名’);//根据类名返回元素对象集
  2. document.querySelector(‘选择器’);//根据指定(CSS)选择器返回第一个元素对象
  3. querySelectorAll();//返回指定选择器的所有元素对象

2.5 获取特殊元素(body,html)

  • 获取 body 元素

doucumnet.body //返回 body 元素对象

  • 获取 html 元素

document.documentElement //返回 html 元素对象!

// 1.获取body 元素
var bodyEle = document.body;
console.log(bodyEle);
console.dir(bodyEle);
//2.获取htm1 元素
var htmlEle = document.documentElement;
console.log(htmlEle);

3.事件基础

3.1 事件概述

JavaScript 使我们有能力创建动态页面,而事件是可以被 JavaScript 侦测到的行为。

简单理解:触发—响应机制。

网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。

3.2 执行事件的步骤

  1. 获取事件源
  2. 注册事件(绑定事件)
  3. 添加事件处理程序(采取函数赋值形式)

3.3 常见的鼠标点击事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过时触发
onmouseout 鼠标离开时触发
onfocus 获取鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

4.操作元素

JavaScript 的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。注意以下都是属性

4.1 改变元素内容

  • element.innerText: 从起始位置到终止位置的内容,但它去除 html 标签,同时空格和换行也会去掉
  • element.innerHTML: 起始位置到终止位置的全部内容,包括 html 标签,同时保留空格和换行

4.2 常用元素的属性操作

使用元素.属性来修改属性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>修改元素属性</title>
  </head>
  <body>
    <input type="text" value="我是文本框" />
    <button>点击修改按钮</button>
    <script>
      var btn = document.querySelector("button");
      btn.onclick = function () {
        document.querySelector("input").value = "我被修改了";
      };
    </script>
  </body>
</html>

4.3 表单元素的属性操作

利用 DOM 可以操作如下表单元素的属性:type、value、checked、selected、disabled

var inputElement = document.getElementById("myInput");
inputElement.type = "password"; // 将输入框类型改为密码框

4.4 样式属性操作

我们可以通过 JS 修改元素的大小、颜色、位置等样式。

  1. element.style 行内样式操作
  2. element.className 对类名操作,如果想要保留原来的类名,使用.classList.add("change"),classList.remove,classList.toggle
--element.style--
<div></div>
<script>
  // 1.获取元素
  var div = document.querySelector("div");
  //2.注册事件 处理程序
  div.onclick = function () {
    // div.style里面的属性 采取驼峰命名法
    this.style.backgroundcolor = "purple"; //this指向函数的调用者
  };
</script>

--element.className--
<style>
  div {
    background-color: yellow;
    width: 200px;
    height: 100px;
  }
  .change {
    background-color: blue;
  }
</style>
<body>
  <div>文本</div>
  <script>
    var div = document.querySelector("div");
    div.onclick = function () {
      // div.classList.add("change");
      div.className = "change";
    };
  </script>
</body>

注意:

  • this 关键字指向函数的调用者
  • Js 里面的样式采取驼峰命名法 比如 fontSizebackgroundColor
  • Js 修改 style 样式操作,产生的是行内样式,CSS 权重比较高

4.5 排他效果

<body>
  <button>1</button><button>2</button><button>3</button><button>4</button
  ><button>5</button>
</body>
<script>
  // const buttons = document.querySelectorAll("button");
  var btns = document.getElementsByTagName("button");
  for (var i = 0; i < btns.length; i++) {
    btns[i].onclick = function () {
      //  先去掉其他的按钮的选中样式
      for (var j = 0; j < btns.length; j++) {
        btns[j].style.backgroundColor = "";
      }
      this.style.backgroundColor = "pink";
    };
  }
</script>

4.6 自定义属性效果

获得元素属性值
  • element.属性 获取属性值
  • element.getAttribute('属性');

区别:

  • element.属性 获取内置属性值(元素本身自带的属性)

  • element.getAttribute('属性'); 主要获得自定义的属性 (标准) 我们程序员自定义的属性

设置属性值
  • element.属性='值' 设置内置属性值
  • element.setAttribute('属性','值') 设置自定义属性值 (标准)
移除属性值
  • element.removeAttribute();

4.7 H5 自定义属性

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

自定义属性获取是通过getAttribute("属性")获取。

但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性,

H5 给我们新增了自定义属性

  1. 设置 H5 自定义属性

H5 规定自定义属性data-开头做为属性名并且赋值: 比如<div data-index="1"></div>

  1. 获取 H5 自定义属性
    1. 兼容性获取 element.getAttribute('data-index');
    2. 通过 H5 新增属性dataset获取所有以data-开头的属性,然后取出里面的值.index或者[index]
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>H5新增dataset属性</title>
  </head>
  <body>
    <div data-name="张三" data-age="18" data-class-name="student"></div>
  </body>
  <script>
    var div = document.querySelector("div");
    console.log(div.dataset.name); // 张三
    console.log(div.dataset.age); // 18
    // 注意:dataset属性的属性名是驼峰命名法,所以要用驼峰命名法来访问属性
    console.log(div.dataset.className); // student
  </script>
</html>

5.节点操作

5.1 为什么学节点操作

获取元素通常使用两种方式

  • 使用 DOM 提供的方法
    • document.getElementByld(),document.getElementsByTagName(),document.querySelector()
    • 逻辑性不强、繁琐
  • 利用节点层级关系获取元素
    • 利用父子兄弟节点关系获取元素
    • 逻辑性强,但是兼容性稍差

5.2 节点概述

网页中的所有内容都是节点(标签、属性、文本、注释等),在 DOM 中,节点使用 node 来表示 HTMLDOM 树中的所有节点均可通过 JavaScript 进行访问,所有 HTML 元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有nodeType(节点类型)nodeName(节点名称)nodeValue(节点值)这三个基本属性。

  • 元素节点 nodeType 为 1
  • 属性节点 nodeType 为 2
  • 文本节点 nodeType 为 3

(文本节点包含文字、空格、换行等我们在实际开发中,节点操作主要操作的是元素节点)

5.3 节点操作之父子节点

  • 父节点

    • 使用节点.parentNode属性获取父节点,得到的是离元素最近的父级节点,若找不到返回null
  • 子节点

    • 使用节点.childNodes属性获取全部子节点-集合形式(包含文本节点、元素节点等),我们可以通过遍历每一个元素的节点属性来对应操作

    • 使用节点.children属性获取所有子元素节点,是一个只读属性,返回所有的子元素节点。它只返回子元素节点,其余节点不返回

    • firstChild获取第一个子节点 不管是文本节点还是元素节点,lastChild同理

    • firstElementChild获取第一个子节点 不管是文本节点还是元素节点,lastElementChild同理,但可能有兼容性问题,一般使用节点.children[0]获取

<body>
    <ul>
      <li class="active">我是li</li>
      <li>我是li</li>
      <li>我是li</li>
      <li>我是li</li>
      <li>我是li</li>
    </ul>
    <script>
      var activeLi = document.querySelector(".active");
      activeLi.style.color = "red";

      var ul = activeLi.parentNode;
      console.log(ul);

      var childs = ul.childNodes;
      for (var i = 0; i < childs.length; i++) {
        if (childs[i].nodeType === 1) {
          console.log(childs[i]); // 只有当节点属性为1时才是元素节点,打印输出
        }
      }
      console.log(ul.children); // 等价于上面的代码
    </script>
  </body>

5.4 节点操作之兄弟节点

node.nextSibling: 返回元素下一个兄弟节点,包含文本节点等

node.nextElementSibling / node.previousElementSibling返回当前元素下一个/上一个兄弟元素节点,找不到则返回null.

  • 如何解决兼容性问题
    • 自己封装一个函数
function mygetNextElementSibling(node) {
  var el = node;
  while ((el = el.nextSibling)) {
    if (el.nodeType == 1) {
      return el;
    }
  }
  return null;
}

5.5 创建节点

document.createElement("tagName")

document.createElement()方法创建由 tagName 指定的 HTML 元素。因为这些元素原先不存在是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。

var div = document.createElement("div");
div.innerHTML = "Hello World!";
document.body.appendChild(div);

var p = document.createElement("p");
p.innerHTML = "This is a paragraph.";
document.body.appendChild(p);

5.6 插入节点

appendChild(node) 后面插入(尾插法)

insertBefore(child,指定元素)在指定元素前面插入新子元素 child(前插法)

<!-- 搭建评论框 -->
<div id="comment-box">
    <h2>发表评论</h2>
<form id="comment-form">
    <label for="name">昵称:</label>
<input type="text" id="name" name="name" required />
    <label for="email">邮箱:</label>
<input type="email" id="email" name="email" required />
    <label for="comment">评论:</label>
<textarea id="comment" name="comment" required></textarea>
<button type="submit">提交</button>
</form>
</div>

<!-- 评论列表 -->
<div id="comment-list">
    <h2>评论列表</h2>
<ul id="comment-list-ul"></ul>
</div>

<script>
    // 获取评论表单
    const commentForm = document.getElementById("comment-form");
// 获取评论列表
const commentList = document.getElementById("comment-list-ul");

// 监听提交事件
commentForm.addEventListener("submit", function (event) {
    // 阻止默认提交事件
    event.preventDefault();
    // 获取表单数据
    const name = document.getElementById("name").value;
    const email = document.getElementById("email").value;
    const comment = document.getElementById("comment").value;
    // 创建li节点
    const li = document.createElement("li");
    if (name === "" || email === "" || comment === "") {
        alert("请填写完整信息");
        return;
    }
    // 创建评论内容节点
    const content = document.createTextNode(
        `${name}(${email}): ${comment}`
    );
    // 将评论内容节点添加到li节点
    li.appendChild(content);
    // 将li节点添加到评论列表
    commentList.insertBefore(li, commentList.firstChild);
    // 清空表单
    commentForm.reset();
});
</script>

5.7 删除节点

node.removeChild(child) 删除node里面的子节点,node.removechild()方法从 DOM 中删除一个子节点,返回删除的节点

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>评论_创建元素节点</title>
  </head>
  <body>
    <!-- 搭建评论框 -->
    <div id="comment-box">
      <h2>发表评论</h2>
      <form id="comment-form">
        <label for="name">昵称:</label>
        <input type="text" id="name" name="name" required />
        <label for="email">邮箱:</label>
        <input type="email" id="email" name="email" required />
        <label for="comment">评论:</label>
        <textarea id="comment" name="comment" required></textarea>
        <button type="submit">提交</button>
      </form>
    </div>

    <!-- 评论列表 -->
    <div id="comment-list">
      <h2>评论列表</h2>
      <ul id="comment-list-ul"></ul>
    </div>

    <script>
      // 获取评论表单
      const commentForm = document.getElementById("comment-form");
      // 获取评论列表
      const commentList = document.getElementById("comment-list-ul");

      // 监听提交事件
      commentForm.addEventListener("submit", function (event) {
        // 阻止默认提交事件
        event.preventDefault();
        // 获取表单数据
        const name = document.getElementById("name").value;
        const email = document.getElementById("email").value;
        const comment = document.getElementById("comment").value;
        // 创建li节点
        const li = document.createElement("li");
        if (name === "" || email === "" || comment === "") {
          alert("请填写完整信息");
          return;
        }
        // 创建评论内容节点
        const content = document.createElement("span");
        content.textContent = `${name}(${email}): ${comment}`;
        const deletebtn = document.createElement("a");
        deletebtn.textContent = "删除";
        deletebtn.href = "javascript:void(0)";
        deletebtn.addEventListener("click", function () {
          li.remove();
        });
        // 将评论内容节点添加到li节点
        li.appendChild(content);
        // 将删除按钮添加到li节点
        li.appendChild(deletebtn);

        // 将li节点添加到评论列表
        commentList.insertBefore(li, commentList.firstChild);
        // 清空表单
        commentForm.reset();
      });
    </script>
  </body>
</html>
  • 当我们把文本域里面的值赋值给 li 的时候,多添加一个删除的链接
  • 需要把所有的链接获取过来,当我们点击当前的链接的时候,删除当前链接所在的 li
  • 阻止链接跳转需要添加javascript:void(0);或者 javascript:;

5.8 复制节点

node.cloneNode()方法返回调用该方法的节点的一个副本。也称为克隆节点/拷贝节点

  • 如果括号参数为 空 或者为 false,则是浅拷贝,即只克隆复制节点本身不克隆里面的子节点
  • 如果括号参数为 true,则是深度拷贝,会复制节点本身以及里面所有的子节点。

5.9 三种动态创建元素区别

  • document.write()
  • element.innerHTML
  • document.createElement()

区别

  1. document.write() 是直接将内容写入页面的内容流,但是文档流执行完毕,则调用它会导致页面全部重绘
  2. element.innerHTML 使用字符串拼接的方式创建元素,效率低,因为每次都要重新创建元素且开辟内存空间
  3. element.innerHTML 是将内容写入某个 DOM 节点,不会导致页面全部重绘,创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
  4. document.createElement() 通过**createElement()**方法创建元素,然后将创建的元素添加到文档中
  5. createglement() 创建多个元素效率稍低一点点,但是结构更清晰
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>创建元素方式区别</title>
  </head>
  <body>
    <ul>
      <li>创建元素方式1:write()</li>
      <li>创建元素方式2:createElement()</li>
      <li>创建元素方式3:innerHTML方式</li>
    </ul>
    <button>点击创建元素</button>
  </body>
  <script>
    // 1. write方式创建元素  直接将元素写入到文档中,可以直接使用document.write()方法,如果页面文档流加载完毕,再调用这句话会导致页面重绘
    var btn = document.querySelector("button");
    btn.onclick = function () {
      document.write("<div>write方式创建元素</div>");
    };

    // 2. createElement方式创建元素  通过createElement()方法创建元素,然后将创建的元素添加到文档中
    var btn2 = document.querySelector("button");
    btn2.onclick = function () {
      var div = document.createElement("div");
      div.innerHTML = "createElement方式创建元素";
      document.body.appendChild(div);
    };

    // 3. innerHTML方式创建元素  通过innerHTML方式创建元素,直接将元素添加到文档中,里面使用字符串拼接的方式创建元素,效率低,因为每次都要重新创建元素且开辟内存空间
    var btn3 = document.querySelector("button");
    btn3.onclick = function () {
      var div = document.createElement("div");
      div.innerHTML = "innerHTML方式创建元素";
      document.body.appendChild(div);
    };

	// 效率最高
    function fn() {
      var start = +new Date();
      var arr = [];
      for (var i = 0; i < 10000; i++) {
        arr.push("<div>innerHTML方式创建元素</div>");
      }
      document.body.innerHTML = arr.join("");
      var end = +new Date();
      console.log("innerHTML方式创建元素耗时:" + (end - start) + "ms");
    }
    fn();
  </script>
</html>

6. 案例

密码输入检验

<body>
  <div class="register">
    <input type="password" name="" id="" class="ipt" />
    <p class="message">请输入6-16位密码</p>
  </div>
</body>
<script>
  var ipt = document.querySelector(".ipt");
  var message = document.querySelector(".message");
  ipt.addEventListener("input", function () {
    var value = this.value;
    if (value.length < 6 || value.length > 16) {
      message.style.display = "block";
    } else {
      message.style.display = "none";
    }
  });
</script>

开关灯

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>开关灯</title>
    <style>
      .light {
        background-color: #fff;
      }
      .black {
        background-color: #000;
      }
    </style>
  </head>
  <body>
    <button>关灯</button>
  </body>
  <script>
    var flag = true;
    var btn = document.querySelector("button");
    btn.onclick = function () {
      if (flag) {
        document.body.className = "black";
        btn.innerHTML = "开灯";
        flag = false;
      } else {
        document.body.className = "light";
        btn.innerHTML = "关灯";
        flag = true;
      }
    };
  </script>
</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>
      body {
        background-color: #f5f5f5;
      }
      div.skin {
        width: 774px;
        margin: auto;
      }
      img {
        display: block;
        float: left;
        width: 380px;
        height: 200px;
        border: 1px solid #ccc;
      }
      .clearfix::after {
        content: "";
        display: table;
        clear: both;
      }
    </style>
  </head>
  <body>
    <div class="skin clearfix">
      <img src="../css下/background.png" alt="" />
      <img src="../html下/image.png" alt="" />
    </div>
  </body>
  <script>
    imgs = document.getElementsByTagName("img");
    for (var i = 0; i < imgs.length; i++) {
      imgs[i].onclick = function () {
        var body = document.querySelector("body");
        body.style.backgroundImage = "url(" + this.src + ")";
      };
    }
  </script>
</html>

新浪下划菜单

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Dropdown Menu</title>
    <style>
      body {
        margin: 0;
        padding: 0;
        font-family: Arial, sans-serif;
      }
      .nav {
        width: 100%;
        margin: 0 auto;
        padding: 0;
        list-style: none;
        background-color: #f8f8f8;
        border-bottom: 1px solid #e7e7e7;
      }
      .nav li {
        display: inline-block;
        position: relative;
        vertical-align: top;
        font-size: 0;
      }
      .nav a {
        display: block;
        padding: 10px 20px;
        text-decoration: none;
        color: #333;
        font-size: 16px;
      }
      .nav li ul {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        list-style: none;
        padding: 0;
        margin: 0;
        background-color: #fff;
        border: 1px solid #e7e7e7;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      }
      .nav li:hover > ul {
        display: block;
      }
      .nav ul li {
        display: block;
      }
      .nav ul a {
        padding: 10px 15px;
        white-space: nowrap;
      }
    </style>
  </head>
  <body>
    <ul class="nav">
      <li>
        <a href="#">微博</a>
        <ul>
          <li><a href="#">关注</a></li>
          <li><a href="#">粉丝</a></li>
        </ul>
      </li>
      <li>
        <a href="#">微博</a>
        <ul>
          <li><a href="#">关注</a></li>
          <li><a href="#">粉丝</a></li>
        </ul>
      </li>
      <li>
        <a href="#">微博</a>
        <ul>
          <li><a href="#">关注</a></li>
          <li><a href="#">粉丝</a></li>
        </ul>
      </li>
      <li>
        <a href="#">微博</a>
        <ul>
          <li><a href="#">关注</a></li>
          <li><a href="#">粉丝</a></li>
        </ul>
      </li>
      <li>
        <a href="#">微博</a>
        <ul>
          <li><a href="#">关注</a></li>
          <li><a href="#">粉丝</a></li>
        </ul>
      </li>
    </ul>
  </body>
</html>

消除行内块元素的默认空白(字符)间隙: 对父元素设置font-size属性为0,再对要显示的子元素单独设置font-size

动态生成表格

  • 因为里面的学生数据都是动态的,我们需要 js 动态生成。这里我们模拟数据,自己定义好数据。数据我们采取对象形式存储。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>动态创建表格</title>
  </head>
  <style>
    table {
      border-collapse: collapse;
      width: 60%;
    }
    th,
    td {
      border: 1px solid #6c6c6c;
      text-align: center;
      padding: 8px;
      border: 1px solid #000000;
    }
    th {
      background-color: rgb(200, 200, 200);
    }
  </style>
  <body>
    <button>添加</button>
    <table cellspacing="0">
      <thead>
        <tr>
          <th>姓名</th>
          <th>科目</th>
          <th>成绩</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <!-- <tr>
          <td>1</td>
          <td>2</td>
          <td>3</td>
          <td><a href="javascript:void(0)">修改</a></td>
        </tr>
        <tr>
          <td>4</td>
          <td>5</td>
          <td>6</td>
          <td><a href="javascript:void(0)">修改</a></td>
        </tr> -->
      </tbody>
    </table>
  </body>
  <script>
    // 准备数据
    var datas = [
      { name: "张三", subject: "语文", score: 80 },
      { name: "王五", subject: "英语", score: 85 },
      { name: "赵六", subject: "物理", score: 95 },
      { name: "周七", subject: "化学", score: 88 },
      { name: "陈八", subject: "生物", score: 90 },
      { name: "吴九", subject: "历史", score: 85 },
    ];
    // 动态创建表格
    function createTable() {
      var table = document.querySelector("table");
      var tbody = table.querySelector("tbody");
      for (var i = 0; i < datas.length; i++) {
        var tr = document.createElement("tr");
        var tdName = document.createElement("td");
        tdName.textContent = datas[i].name;
        var tdSubject = document.createElement("td");
        tdSubject.textContent = datas[i].subject;
        var tdScore = document.createElement("td");
        tdScore.textContent = datas[i].score;
        var tdOperation = document.createElement("td");
        tdOperation.innerHTML = "<a href='javascript:void(0)'>修改</a>";
        tr.appendChild(tdName);
        tr.appendChild(tdSubject);
        tr.appendChild(tdScore);
        tr.appendChild(tdOperation);
        tbody.appendChild(tr);

        tdOperation.querySelector("a").onclick = function () {
          var score = prompt(
            "请输入修改后的成绩:",
            this.parentNode.parentNode.children[2].textContent
          );
          if (Number.isInteger(Number(score))) {
            this.parentNode.parentNode.children[2].textContent = score;
          } else {
            alert("请输入正确的成绩!");
          }
        };
      }
    }
    var btnAdd = document.querySelector("button");
    btnAdd.onclick = function () {
      var tr = document.createElement("tr");
      var tdName = document.createElement("td");
      createTable();
    };
  </script>
</html>

事件高级

目标

  • 能够写出元素注册事件的两种方式
  • 能够说出删除事件的两种方式
  • 能够说出 DOM 事件流的三个阶段
  • 能够利用事件对象完成跟随鼠标案例
  • 能够封装阻止冒泡的兼容性函数
  • 能够说出事件委托的原理
  • 能够说出常用的鼠标和键盘事件

1.注册事件(绑定事件)

1.1 注册事件概述

给元素添加事件,称为注册事件或者绑定事件

注册事件有两种方式: 传统方式方法监听注册方式

传统注册方式
  • 利用 on 开头的事件 onclick, 如<button onclick= 'alert("hi~")'></button> 或者 btn.onclick = function(){}
  • 特点: 注册事件的唯一性同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
方法监听注册方式
  • w3c 标准推荐方式
  • addEventListener()它是一个方法
  • IE9 之前的 IE 不支持此方法,可使用 attachEvent() 代替
  • 特点: 同一个元素同一个事件可以注册多个监听器

1.2 addEventListener 事件监听方式

// 参数声明
eventTarget.addEventListener(type,listener[,useCapture])

eventTarget.addEventListener()方法将指定的监听器注册到**eventTarget(目标对象)**上,当该对象触发指定的事件时,就会执行事件处理函数。
该方法接收三个参数:

  • type:事件类型字符串,比如 click、mouseover,注意这里不要带 on
  • listener:事件处理函数,事件发生时,会调用该监听函数
  • useCapture:可选参数,是一个布尔值,默认是 false。学完 DOM 事件流后,我们再进一步学习

1.3 attachEvent 事件监听方法

eventTarget.attachEvent(eventNameWithon, callback);

eventTarget.attachEvent()方法将指定的监听器注册到**eventTarget(目标对象)**上,当该对象触发指定的事件时,指定的回调函数就会被执行。
该方法接收两个参数:

  • eventNameWithOn: 类型字符串,比如 onclick、onmouseover,这里要带on
  • callback: 事件处理函数,当目标触发事件时回调函数被调用

注意: 仅IE8及以前版本的IE浏览器支持

1.4 兼容性处理

// 兼容性处理
function aaddEventListener(element, eventName, fn) {
  //判断当前浏览器是否支持 addEventListener 方法
  if (element.addEventListener) {
    element.addEventListener(eventName, fn);
  } //第三个参数默认是false
  else if (element.attachEvent) {
    element.attachEvent("on" + eventName, fn);
  } else {
    //相当于element.onclick=fn;
    element["on" + eventName] = fn;
  }
}

2.删除事件(解绑事件)

2.1 删除事件的方式

  • 传统注册方式 element.onclick = null;
  • 方法监听注册方式 eventTarget.removeEventListener(type,listener[,useCapture]);
  • IE8 方法 eventTarget.detachEvent(type,listener[,useCapture]);
var divs = document.getElementsByTagName("div");

divs[0].onclick = function () {
  alert("点击了第1个div");
  divs[0].onclick = null;
  //   divs[0].remove();
};

divs[1].addEventListener("click", function () {
  alert("点击了第2个div");
  divs[1].removeEventListener("click", arguments.callee); //arguments.callee指向当前函数,这里可以用匿名函数来实现
  //   divs[0].remove();
});

divs[2].attachEvent("onclick", fn1),
  function fn1() {
    alert("点击了第3个div");
    divs[2].detachEvent("onclick", fn1);
  };

3.DOM 的事件流

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

注意

  1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
  2. onclick 和 attachEvent 只能得到冒泡阶段
  3. addEventListener(type,listener[,useCapture])第三个参数如果是 true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是 false),表示在事件冒泡阶段调用事件处理程序。
  4. 实际开发中我们很少使用事件捕获,我们更关注事件冒泡。
  5. 有些事件是没有冒泡的,比如 onbluronfocusonmouseenteronmouseleave

image-20240920102546864

  • 事件冒泡:IE 最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点的过程。
  • 事件捕获:网景最早提出,由 DOM 最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。
<!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>
                body {
                    width: 100%;
                }
.father {
    width: 200px;
    height: 200px;
    background-color: blueviolet;
    position: relative;
    margin: auto;
}
.son {
    width: 100px;
    height: 100px;
    background-color: pink;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    cursor: pointer;
}
</style>
</head>
<body>
    <div class="father">
        <div class="son">子元素</div>
</div>
</body>
<script>
            // 捕获阶段 从上到下,所以假如father和son都有click事件,则先捕获father的事件,然后再到son
            var son = document.querySelector(".son");
son.addEventListener(
    "click",
    function () {
        alert("son");
    },
    true
);

var father = document.querySelector(".father");
father.addEventListener(
    "click",
    function () {
        alert("father");
    },
    true
);

// 冒泡阶段 从下到上,所以假如father和son都有click事件,则先冒泡son的事件,然后再到father
var son = document.querySelector(".son");
son.addEventListener(
    "click",
    function () {
        alert("son");
    },
    false
);

var father = document.querySelector(".father");
father.addEventListener(
    "click",
    function () {
        alert("father");
    },
    false
);
</script>
</html>

4.事件对象

  1. event 就是一个事件对象,写到我们侦听函数的小括号里面,当形参来看
  2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
  3. 事件对象是我们事件的一系列相关数据的集合,跟事件相关的,比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
  4. 这个事件对象我们可以自己命名 比如 eventevte
  5. 事件对象也有兼容性问题,ie678 通过 window.event,兼容性写法 e = window.event || e;

官方解释: event 对象代表事件的状态,比如键盘按键的状态、鼠标的位置、鼠标按钮的状态。

简单理解:事件发生后,跟事件相关的一系列信息数据的集合都放到这个对象里面,这个对象就是事件对象 event,它有很多属性和方法。

4.1 事件对象的常见属性和方法

事件对象属性方法 说明
e.target 返回触发事件的对象 标准,this不同,this 指向的是绑定事件的对象,例如点击ul>li,target 返回的是 li,this 指向的是 ul
e.srcElement 返回触发事件的对象 非标准 ie6-8 使用
e.type 返回事件的类型 比如 click mouseover 不带 on
e.cancelBubble 该属性阻止冒泡 非标准 ie6-8 使用
e.returnValue 该属性 阻止默认事件(默认行为) 非标准 ie6-8 使用 比如不让链接跳转
e.preventDefault() 该方法 阻止默认事件(默认行为) 标准 比如不让链接跳转,也可以使用return false(仅限于传统注册方式)
e.stopPropagation() 阻止冒泡 标准

5.阻止事件冒泡

5.1 阻止事件冒泡的两种方式

事件冒泡:开始时由最具体的元素接收,然后逐级向上传播到到 DOM 最顶层节点。

事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。

  • 标准写法: 利用事件对象里面的 stopPropagation() 方法
  • 非标准写法:IE6-8 利用事件对象 cancelBubble 属性
var father = document.querySelector(".father");
var son = document.querySelector(".son");

son.addEventListener(
  "click",
  function (event) {
    if (event && event.stopPropagation) {
      event.stopPropagation(); // 阻止事件冒泡
    } else {
      window.event.cancelBubble = true; // 阻止事件冒泡
    }
    alert("son clicked");
  },
  false
);
father.addEventListener(
  "click",
  function (event) {
    alert("father clicked");
  },
  false
);

document.addEventListener(
  "click",
  function (event) {
    if (event && event.stopPropagation) {
      event.stopPropagation(); // 阻止事件冒泡
    } else {
      window.event.cancelBubble = true; // 阻止事件冒泡
    }
    alert("document clicked");
  },
  false
);

6.事件委托(事件代理)

事件冒泡本身的特性,会带来的坏处,也会带来的好处,需要我们灵活掌握。程序中也有如此场景

事件委托

事件委托也称为事件代理,在 jQuery 里面称为事件委派

事件委托的原理

不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

以上案例:给 ul 注册点击事件,然后利用事件对象的 target 来找到当前点击的 li,因为点击 li,事件会冒泡到 ul 上, ul 有注册事件,就会触发事件监听器。

事件委托的作用

我们只操作了一次 DOM,提高了程序的性能

<ul>
<li>"知否知否,点我应有弹窗在手"</li>
<li>"知否知否,点我应有弹窗在手"</li>
<li>"知否知否,点我应有弹窗在手"</li>
<li>"知否知否,点我应有弹窗在手"</li>
<li>"知否知否,点我应有弹窗在手"</li>
</ul>
<script>
    // 事件委托的核心原理:给父节点添加侦听器,利用事件冒泡影响每一个子节点
    ul = document.querySelector("ul");
ul.addEventListener("click", function (event) {
    event.target.style.backgroundColor = "red";
});
</script>

7.常用的鼠标事件

7.1 常用的鼠标事件

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获得鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发
  • 禁止鼠标右键菜单

contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单

document.addEventListener("contextmenu", function (e) {
  e.preventDefault();
});
  • 禁止鼠标选中(selectstart 开始选中)
document.addEventListener("selectstart", function (e) {
  e.preventDefault();
});

7.2 鼠标事件对象

event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent

鼠标事件对象 说明
e.clientX 返回鼠标相对于浏览器窗口可视区的 X 坐标
e.clientY 返回鼠标相对于浏览器窗口可视区的 Y 坐标
e.pageX 返回鼠标相对于文档页面的 X 坐标 IE9+ 支持
e.pageY 返回鼠标相对于文档页面的 Y 坐标 IE9+ 支持
e.screenX 返回鼠标相对于电脑屏幕的 X 坐标
e.screenY 返回鼠标相对于电脑屏幕的 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>
      body {
        position: relative;
      }
      img {
        position: absolute;
        top: 0;
        left: 0;
        /* 鼠标样式 */
        cursor: none;
      }
    </style>
  </head>
  <body>
    <img src="../src/jumpfire.gif" alt="" />
  </body>
  <script>
    const img = document.querySelector("img");
    document.addEventListener("mousemove", function (event) {
      img.style.top = event.clientY - img.height / 2 + "px";
      img.style.left = event.clientX - img.width / 2 + "px";
    });
  </script>
</html>
  • 鼠标不断的移动,使用鼠标移动事件:mousemove
  • 在页面中移动,给 document 注册事件
  • 图片要移动距离,而且不占位置,我们使用绝对定位即可
  • 核心原理:每次鼠标移动,我们都会获得最新的鼠标坐标,把这个 x 和 y 坐标做为图片的 top 和 left 值就可以移动图片

8.常用的键盘事件

8.1 常用键盘事件

事件除了使用鼠标触发,还可以使用键盘触发

键盘事件 触发条件
onkeyup 某个键盘按键被松开时触发
onkeydown 某个键盘按键被按下时触发
onkeypress 某个键盘按键被按下时触发 但是它不识别功能键 比如 ctrl shift 箭头等

注意

  1. 如果使用 addEventListener 不需要加 on
  2. onkeypress 和前面 2 个的区别是,它不识别功能键,比如左右箭头,shift 等
  3. 三个事件的执行顺序是:keydown --- keypress --- keyup
  4. keyup 和 keydown 不区分大小写

8.2 键盘事件属性

  • keyCode返回按下按键的Ascii 码值
  • key返回按下按键的键

京东光标定位案例

var input = document.querySelector("input");
document.addEventListener("keyup", function (event) {
  if (event.key === "s") {
    input.focus();
    input.value = "";
  }
});

京东快递查询案例

<!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: 2px;
      }
      .search {
        display: block;
        width: 300px;
        margin: auto;
        margin-top: 100px;
      }
      .con {
        width: 100%;
        height: 30px;
        line-height: 30px;
        border: 1px solid #ccc;
        display: none;
        margin-bottom: 10px;
        font-size: larger;
        position: relative;
        box-shadow: 2px 3px 3px #ccc;
      }
      .con::before {
        content: "";
        position: absolute;
        top: 34px;
        left: 17px;
        display: inline-block;

        /* 三角 */
        border-top: 10px solid white;
        border-left: 5px solid transparent;
        border-bottom: 5px solid transparent;
        border-right: 5px solid transparent;
      }
      input {
        display: inline-block;
        width: 100%;
        height: 100%;
        color: rgb(186, 188, 187);
      }
    </style>
  </head>
  <body>
    <div class="search">
      <div class="con">123</div>
      <input type="text" value="请输入快递单号" />
    </div>
  </body>
  <script>
    const input = document.querySelector("input");
    const con = document.querySelector(".con");
    input.addEventListener("focus", function () {
      if (this.value === "请输入快递单号") {
        this.value = "";
        this.style.color = "black";
      } else {
        con.style.display = "block";
      }
    });
    input.addEventListener("blur", function () {
      con.style.display = "none";
    });
    input.addEventListener("keyup", function () {
      if (this.value === "") {
        con.style.display = "none";
      } else {
        con.style.display = "block";
      }
    });
    input.addEventListener("input", function () {
      con.style.display = "block";
      con.textContent = this.value;
    });
  </script>
</html>

注意:keydownkeypress在文本框里面的特点:他们两个事件触发的时候,文字还没有落入文本框中。keyup事件触发的时候,文字已经落入文本框里面了

BOM 浏览器对象模型

  • 能够说出什么是 BOM
  • 能够知道浏览器的顶级对象 window
  • 能够写出页面加载事件以及注意事项
  • 能够写出两种定时器函数并说出区别
  • 能够说出 JS 执行机制
  • 能够使用 location 对象完成页面之间的跳转
  • 能够知晓 navigator 对象涉及的属性
  • 能够使用 history 提供的方法实现页面刷新

1.BOM 概述

1.1 什么是 BOM

BOM(BrowserObjectModel)即浏览器对象模型它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。

BOM 由一系列相关的对象构成,并且每个对象都提供了很多方法与属性。

BOM 缺乏标准,JavaScript 语法的标准化组织是 ECMA,DOM 的标准化组织是 W3C,BOM 最初是 Netscape 浏览器标准的一部分。
image-20240921115514114

1.2 BOM 的构成

BOM 比 DOM 更大,它包含 DOM.

window对象是浏览器的顶级对象,它具有双重角色。

  1. 它是 JS 访问浏览器窗口的一个接口。
  2. 它是一个全局对象。定义在全局作用域中的变量、函数都会变成 window 对象的属性和方法。在调用的时候可以省略 window,前面学习的对话框都属于 window 对象方法,如 alert()、prompt()等
  3. 注意:window 下的一个特殊属性window.name

2.window 对象的常见事件

2.1 窗口加载事件

window.onload = function () {};
或者;
window.addEventListener("load", function () {});

window.onload 是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等),就调用的处理函数。

注意:

  1. 有了 window.onload 就可以把 JS 代码写到页面元素的上方,因为 onload 是等页面内容全部加载完毕再去执行处理函数。
  2. window.onload 传统注册事件方式只能写一次,如果有多个,会以最后一个 window.onload 为准,
  3. 如果使用 addEventListener 则没有限制
document.addEventListener("DOMContentLoaded", function () {});

DOMContentLoaded事件触发时,仅当 DOM 加载完成,不包括样式表,图片,flash 等等,加载速度比 onload 快

2.2 调整窗口大小事件

window.onresize = function () {};
window.addEventListener("resize", function () {});

window.onresize 是调整窗口大小加载事件,当触发时就调用的处理函数。

注意:

  1. 只要窗口大小发生像素变化,就会触发这个事件。
  2. 我们经常利用这个事件完成响应式布局。window.innerWidth当前屏幕的宽度

3.定时器

3.1 两种定时器

window 对象给我们提供了 2 个非常好用的方法-定时器

  • setTimeout()
  • setInterval()

3.2 setTimeout()定时器

window.setrimeout(调用函数,[延迟的毫秒数]);
  • setTimeout() 方法用于设置一个定时器,该定时器在定时器到期后执行调用函数。

  • 调用函数可以写匿名函数函数名'函数名()'

  • setTimeout()这个调用函数我们也称为回调函数callback

3.3 停止setTimeout()定时器

window.clearTimeout(timeoutID);

var boom = window.setTimeout(function () {
  alert("BOOM");
}, 5000);

var btn = document.querySelector("button");
btn.addEventListener("click", function () {
  window.clearTimeout(boom);
  console.log("炸弹拆除成功");
});

3.4 setInterval()定时器

window.setInterval(回调函数,[间隔的毫秒数]);

setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。

注意:

  1. window 可以省略。
  2. 这个调用函数可以直接写函数,或者写函数名或者采取字符串'函数名()'三种形式
  3. 间隔的毫秒数省略默认是 0,如果写,必须是毫秒,表示每隔多少毫秒就自动调用这个函数。
  4. 因为定时器可能有很多,所以我们经常给定时器赋值一个标识符

3.5 京东定时器案例

  1. 这个倒计时是不断变化的,因此需要定时器来自动变化(setInterval)
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>定时器案例</title>
    <style>
      .hour,
      .min,
      .sec {
        width: 50px;
        height: 50px;
        background-color: rgb(50, 50, 50);
        color: white;
        text-align: center;
        line-height: 50px;
        font-family: "Courier New", Courier, monospace;
        font-size: 20px;
        float: left;
        margin-left: 5px;
      }
    </style>
  </head>
  <body>
    <div class="time">
      <div class="hour">1</div>
      <div class="min">2</div>
      <div class="sec">3</div>
    </div>
  </body>
  <script>
    var hour = document.querySelector(".hour");
    var min = document.querySelector(".min");
    var sec = document.querySelector(".sec");
    var inputTime = +new Date("2024-09-22 23:59:59"); // 返回的是用户输入时间总的毫秒数
    function getTime() {
      var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
      var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数
      var h = parseInt((times / 60 / 60) % 24); // 时
      h = h < 10 ? "0" + h : h;
      hour.innerHTML = h;
      var m = parseInt((times / 60) % 60); // 分
      m = m < 10 ? "0" + m : m;
      min.innerHTML = m;
      var s = parseInt(times % 60); // 当前的秒
      s = s < 10 ? "0" + s : s;
      sec.innerHTML = s;
    }
    getTime(); // 第一次调用getTime函数
    setInterval(getTime, 1000); // 每秒调用一次getTime函数
  </script>
</html>

3.6 清除clearInterval()定时器

window.clearInterval(IntervalID);

3.7 发送短信按钮

<body>
  <input type="" />
  <button>发送</button>
</body>
<script>
  var btn = document.querySelector("button");
  var input = document.querySelector("input");
  var totalTime = 60;
  var timer = null;
  btn.addEventListener("click", function () {
    btn.disabled = true;
    timer = setInterval(function () {
      totalTime--;
      if (totalTime < 0) {
        clearInterval(timer);
        totalTime = 60;
        btn.disabled = false;
        input.value = "发送成功";
        return;
      }
      btn.innerText = "发送(" + totalTime + ")";
    }, 1000);
  });
</script>

3.8 this 指向问题

  1. this 指向问题,一般情况下 this 的最终指向的是那个调用它的对象
  2. 方法调用中谁调用 this 指向谁
  3. 全局作用域或者普通函数中,this 指向全局对象 window(注意定时器里面的 this 指向 window)
  4. 构造函数中 this 指向构造函数的实例

4.JS 执行机制

JavaScript 语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。

这是因为Javascript 这门脚本语言诞生的使命所致–JavaScript 是为处理页面中用户的交互,以及操作 DOM 而诞生的。比如我们对某个 DOM 元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。

4.1 同步和异步

为了解决这个问题,利用多核 CPU 的计算能力,HTML5 提出WebWorker标准,允许 JavaScript 脚本创建多个线程。于是 JS 中出现了同步和异步

  • 同步: 一个任务结束后再执行后一个任务,程序的执行顺序与任务的排列顺序是一致的、同步的。

  • 异步: 你在做一件事情时,因为这件事情会花费很长时间,在做这件事的同时,你还可以去处理其他事情。

  • 同步任务

同步任务都在主线程上执行,形成一个执行栈。

  • 异步任务

JS 的异步是通过回调函数实现的。
一般而言,异步任务有以下三种类型:

  1. 普通事件,如clickresize
  2. 资源加载,如loaderror
  3. 定时器,包括setlntervalsetTimeout
  4. 异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。

4.2 Js 执行机制

  1. 先执行执行栈中的同步任务
  2. 异步任务(回调函数)放入任务队列中。
  3. 一旦执行栈中的所有同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。
image-20240922194648727

4.3 Js 事件循环机制

image-20240922195117756

5.location 对象

5.1 什么是 location 对象

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

因为这个属性返回的是一个对象,所以我们将这个属性也称为 location 对象。

5.2 URL

统一资源定位符(Uniform Resource Locator,URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

URL 的一般语法格式为:

protocol://host[:port]/path/[?query]#fragment
http://www.itcast.cn/index.html?name=andy&age=18#link
组成 说明
protocol 通信协议 常用的 http, ftp, mailto 等
host 主机(域名) www.itheima.com
port 端口号 可选,省略时使用方案的默认端口 如 http 的默认端口为 80
path 路径 由零或多个’/‘符号隔开的字符串,一般用来表示主机上的一个目录或文件地址
query 参数 以键值对的形式,通过’&’符号分隔开来
fragment 片段 #后面内容 常见于链接 锚点

5.3 location 对象的属性和方法

location 对象属性 返回值
location.href 获取或者设置 整个 URL
location.host 返回主机(域名) www.itheima.com
location.port 返回端口号 如果未写返回 空字符串
location.pathname 返回路径
location.search 返回参数
location.hash 返回片段 #后面内容 常见于链接 锚点

5.4 定时跳转页面

// 定时跳转页面
setTimeout("location.href='http://www.baidu.com'", 3000); // 3秒后跳转到百度

5.5 多页面间参数传递

  • 第一个登录页面,里面有提交表单,action 提交到 index.html 页面
  • 第二个页面,可以使用第一个页面的参数,这样实现了一个数据不同页面之间的传递效果
  • 第二个页面之所以可以使用第一个页面的数据,是利用了 URL 里面的location.search参数
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>获取url参数</title>
  </head>
  <body>
    <form action="74_获取url参数_2.html">
      用户名: <input type="text" name="uname" />
      <input type="submit" value="登陆" />
    </form>
  </body>
</html>

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>获取url参数</title>
  </head>
  <body>
    <script>
      var s = window.location.search;
      var params = s.substr(1).split("&");
      for (var i = 0; i < params.length; i++) {
        console.log(params[i]);
        var param = params[i].split("=");
        if (param[0] == "uname") {
          document.write("<p>你好," + param[1] + "!欢迎来到我的博客。</p>");
        }
      }
    </script>
  </body>
</html>

5.6 location 对象方法

location 对象方法 返回值
location.assign() 跟 href 一样,可以跳转页面(也称为重定向页面)
location.replace() 替换当前页面,因为不记录历史,所以不能后退页面
location.reload() 重新加载页面,相当于刷新按钮或者 f5 如果参数为 true 强制刷新 ctrl+f5

6.navigator 对象

navigator 对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的 user-agent 头部的值。

下面前端代码可以判断用户那个终端打开页面,实现跳转

if (
  navigator.userAgent.match(
    /(phone|pad|iPhone|iPod|Android|BlackBerry|IEMobile|Opera Mini|Windows Phone)/i
  )
) {
  // 手机
  window.location.href = "https://m.example.com"; // 将用户重定向到移动版网页
} else {
  // 电脑
  window.location.href = "https://www.example.com"; // 将用户重定向到桌面版网页
}

7.history 对象

window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的 URL。

history 对象方法 作用
back() 可以后退功能
forward() 前进功能
go(参数) 前进后退功能 参数如果是 1 前进 1 个页面 如果是 -1 后退 1 个页面

history 对象一般在实际开发中比较少用,但是会在一些 OA 办公系统中见到。

PC 端网页特效

  • 能够说出常见 offset 系列属性的作用
  • 能够说出常见 client 系列属性的作用
  • 能够说出常见 scroll 系列属性的作用 R
  • 能够封装简单动画函数
  • 能够写出网页轮播图案例

0.立即执行函数

立即执行函数(function() {})(); 或者 (function(){} ());

主要作用:

  • 创建一个独立的作用域,里面所有变量都是局部变量,不会存在命名冲突
  • 不需要调用,立即执行
  • 可以传参,可以起函数名
(function sum(a, b) {
  console.log(a + b); // 输出4
})(1, 3);

1.offset 系列属性

1.1 offset 概述

offset翻译过来就是偏移量,我们使用 offset 系列相关属性可以动态的得到该元素的位置(偏移)、大小

  • 获得元素距离带有定位父元素的位置
  • 获取自身属性
offset 系列属性 作用
element.offsetParent 返回作为该元素带有定位的父级元素 如果父级都没有定位则返回 body
element.offsetTop 返回元素相对带有定位父元素上方的偏移
element.offsetLeft 返回元素相对带有定位父元素左边框的偏移
element.offsetWidth 返回自身包括 padding、边框、内容区的宽度,返回数值不带单位
element.offsetHeight 返回自身包括 padding、边框、内容区的高度,返回数值不带单位

1.2 offset 和 style 的区别

属性 offset style
可获取样式 可以得到任意样式表中的样式值 只能得到行内样式表中的样式值
返回值 获得的数值是没有单位的 获得的是带有单位的字符串
包含内容 offsetWidth 包含 padding + border + width style.width获得的值不包含 padding 和 border
属性类型 只读属性,只能获取不能赋值 可读写属性,可以获取也可以赋值
适用场景 想要获取元素大小位置,用 offset 更合适 想要给元素更改值,则需要用 style 改变

1.3 案例

放大镜效果

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>放大镜效果</title>
    <style>
      .small {
        width: 500px;
        height: 300px;
        position: relative;
      }
      .small .mask {
        display: none;
        position: absolute;
        width: 200px;
        height: 200px;
        background-color: rgba(210, 229, 124, 0.5);
        cursor: move;
      }
      img {
        width: 100%;
        height: 100%;
      }
      .small .big {
        position: absolute;
        top: 50px;
        left: 600px;
        display: none;
        width: 200px;
        height: 200px;
        background-image: url("../../html下/image.png");
        background-repeat: no-repeat;
        z-index: 999;
      }
    </style>
  </head>
  <body>
    <div class="small">
      <img src="../../html下/image.png" alt="" />
      <div class="mask"></div>
      <div class="big"></div>
    </div>
  </body>
  <script>
    var small = document.querySelector(".small");
    var img = small.querySelector("img");
    var mask = small.querySelector(".mask");
    var big = document.querySelector(".small .big");

    function showImg(x, y) {
      big.style.transform = "scale(1.5)";
      big.style.backgroundPosition = -x + "px" + " " + (-y + "px");
    }

    small.addEventListener("mousedown", function (e) {
      mask.style.display = "block";
      big.style.display = "block";
      document.addEventListener("mousemove", function (e) {
        var x = e.pageX - small.offsetLeft - 100;
        var y = e.pageY - small.offsetTop - 100;
        if (x < 0) {
          x = 0;
        }
        if (x > small.offsetWidth - mask.offsetWidth) {
          x = small.offsetWidth - mask.offsetWidth;
        }
        if (y < 0) {
          y = 0;
        }
        if (y > small.offsetHeight - mask.offsetHeight) {
          y = small.offsetHeight - mask.offsetHeight;
        }
        showImg(x, y);
        mask.style.left = x + "px";
        mask.style.top = y + "px";
      });
      document.addEventListener("mouseup", function (e) {
        mask.style.display = "none";
        big.style.display = "none";
      });
    });
  </script>
</html>

2. 元素可视区 client 系列

client 翻译过来就是客户端,我们使用client 系列的相关属性来获取元素可视区的相关信息。通过 client 系列的相关属性 可以动态的得到该元素的边框大小、元素大小等。

2.1 常见 client 属性

client 系列属性 作用
element.clientTop 返回元素上边框的大小
element.clientLeft 返回元素左边框的大小
element.clientWidth 返回自身包括 padding、内容区的宽度,不含边框,返回数值不带单位
element.clientHeight 返回自身包括 padding、内容区的高度,不含边框,返回数值不带单位

3. 元素滚动 scorll 系列

3.1 元素 scroll 系列属性

scroll 翻译过来就是滚动的,我们使用 scroll 系列的相关属性可以动态的得到该元素的大小、滚动距离等。

scroll 系列属性 作用
element.scrollTop 返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft 返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth 返回自身实际的宽度,不含边框,返回数值不带单位
element.scrollHeight 返回自身实际的高度,不含边框,返回数值不带单位
image-20240928202943684

3.2 仿淘宝滚动栏案例

  1. 原先侧边栏是绝对定位
  2. 当页面滚动到一定位置,侧边栏改为固定定位
  3. 页面继续滚动,会让返回顶部显示出来
  4. 需要用到页面滚动事件 scroll 因为是页面滚动,所以事件源是 document
  5. 滚动到某个位置,就是判断页面被卷去的上部值。
  6. 页面被卷去的头部:可以通过window.pageYOffset 获得 如果是被卷去的左侧 window.pageXOffset

3.3 页面被卷去的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:

  1. 声明了 DTD,使用 document.documentElement.scrollTop
  2. 未声明 DTD,使用 document.body.scrollTop
  3. 新方法window.pageYOffsetwindow.pageXOffset,IE9 开始支持
function getscroll(){
    return {
        left: window.pageXoffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0,
        top: window.pageYoffset || document.documentElement.scrollTop ||  document.body.scrollTop ||  0
    };
    使用的时候getScro1l().left

三大系列总结

三大系列大小对比 作用
element.offsetWidth 返回自身包括 padding、边框、内容区的宽度,返回数值不带单位
element.clientWidth 返回自身包括 padding、内容区的宽度,不含边框,返回数值不带单位
element.scrollWidth 返回自身实际的宽度,不含边框,返回数值不带单位
  1. offset 系列经常用于获得元素位置 offsetLeft offsetTop
  2. client 经常用于获取元素大小 clientWidth clientHeight
  3. scroll 经常用于获取滚动距离 scrollTop scrollLeft
  4. 注意页面滚动的距离通过 window.pagexoffset 获得

4. mouseenter 和 mouseover 事件

mouseenter 鼠标事件

  • 当鼠标移动到元素上时就会触发mouseenter 事件
  • 类似 mouseover,它们两者之间的差别是
  • mouseover 鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发
  • 之所以这样,就是因为 mouseenter 不会冒泡
  • 跟 mouseenter 搭配 鼠标离开 mouseleave 同样不会冒泡

5. 动画函数封装

5.1 动画实现原理

核心原理: 通过定时器 setInterval() 不断移动盒子位置。

1.获得盒子当前位置

2.让盒子在当前位置加上 1 个移动距离

3.利用定时器不断重复这个操作

4.加一个结束定时器的条件

5.注意此元素需要添加定位,才能使用element.style.left

5.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>
      div {
        /* 记得加定位 */
        position: absolute;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div></div>
  </body>
  <script>
    function animate(element, moveDistance) {
      var timer = setInterval(function () {
        if (element.offsetLeft >= moveDistance) {
          clearInterval(timer);
        } else {
          element.style.left = element.offsetLeft + 1 + "px";
        }
      });
    }
    var div = document.querySelector("div");
    animate(div, 400);
  </script>
</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>
      div {
        position: absolute;
        left: 0;
        width: 100px;
        height: 100px;
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div></div>
  </body>
  <script>
    function animate(element, moveDistance) {
      var timer = setInterval(function () {
        if (element.offsetLeft >= moveDistance) {
          clearInterval(timer);
        } else {
          element.style.left = element.offsetLeft + 1 + "px";
        }
      });
    }
    var div = document.querySelector("div");
    animate(div, 400);
  </script>
</html>

5.3 动画函数给不同元素记录不同定时器

如果多个元素都使用这个动画函数,每次都要 var 声明定时器。我们可以给不同的元素使用不同的定时器**(自己专门用自己的定时器)**。

核心原理:利用 Js 是一门动态语言,可以很方便的给当前对象添加属性。

function animate(element, moveDistance) {
  clearInterval(element.timer);
  element.timer = setInterval(function () {
    if (element.offsetLeft >= moveDistance) {
      clearInterval(element.timer);
    } else {
      element.style.left = element.offsetLeft + 1 + "px";
    }
  });
}

5.4 缓动效果原理

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

思路:

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
  2. 核心算法: (目标值-现在的位置)/10 做为每次移动的距离步长
function animate(element, distance) {
  clearInterval(element.timer);
  element.timer = setInterval(function () {
    step = (distance - element.offsetLeft + 10) / 10;
    if (element.offsetLeft == distance) {
      clearInterval(element.timer);
    } else {
      element.style.left = element.offsetLeft + step + "px";
      console.log(element.offsetLeft, step);
    }
  }, 15);
}
var box = document.getElementById("box");
var btn = document.querySelector("button");
btn.addEventListener("click", function () {
  animate(box, 900);
});

5.5 动画函数添加回调函数

回调函数原理: 函数可以作为一个参数。

将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调

回调函数写的位置:定时器结束的位置。

5.6 动画函数封装到单独 JS 文件里面

因为以后经常使用这个动画函数,可以单独封装到一个 js 文件里面,使用的时候引用这个 js 文件即可。

6. 常见网页特效案例

滚动条案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>滑动条</title>
    <script src="animate.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box; /* 设置所有元素的 box-sizing 为 border-box */
      }
      body {
        display: flex; /* 使用 flexbox 来控制布局 */
        justify-content: flex-end; /* 使内容右对齐 */
        height: 100vh; /* 全高 */
        align-items: center; /* 垂直居中 */
        overflow: hidden; /* 隐藏滚动条 */
      }
      .sliderbar {
        position: relative;
        height: 40px;
        width: 200px; /* 固定宽度 */
        overflow: hidden; /* 保证内容不会溢出 */
      }
      span {
        display: block;
        position: absolute;
        width: 40px;
        height: 40px;
        background-color: rgb(149, 149, 220);
        line-height: 40px;
        text-align: center;
        font-size: 20px;
        right: 0; /* 右对齐 */
      }
      .con {
        position: absolute;
        left: 200px;
        top: 0;
        height: 40px;
        line-height: 40px;
        text-align: left;
        width: 160px; /* 减少宽度以适应 `span` */
        padding-left: 10px;
        background-color: rgb(149, 149, 220);
      }
    </style>
  </head>
  <body>
    <div class="sliderbar">
      <div class="con">问题反馈</div>
      <span>&larr;</span>
    </div>
    <script>
      var sliderbar = document.querySelector(".sliderbar");
      var con = document.querySelector(".con");
      var span = document.querySelector("span");

      sliderbar.addEventListener("mouseenter", function () {
        animate(con, 0);
        span.innerHTML = "&larr;";
      });

      sliderbar.addEventListener("mouseleave", function () {
        animate(con, 200, function () {});
        span.innerHTML = "&rarr;";
      });
    </script>
  </body>
</html>

网页轮播条案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>轮播焦点图案例</title>
    <script src="animate.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }
      .container {
        position: relative;
        width: 600px;
        height: 400px;
        margin: 0 auto;
        overflow: hidden;
        background-color: pink;
      }
      .box {
        position: absolute;
        top: 0;
        left: 0;
        width: 400%;
        height: 100%;
      }
      .box img {
        width: 600px;
        height: 400px;
        float: left;
      }
      span {
        position: absolute;
        right: 20px;
        top: 50%;
        display: block;
        width: 30px;
        height: 30px;
        line-height: 30px;
        text-align: center;
        font-size: 22px;
        border-radius: 50%;
        transform: translateY(-50%);
        background-color: rgba(213, 13, 13, 0.5);
        cursor: pointer;
      }
      .left {
        left: 20px; /* 左侧按钮位置 */
      }
      ul {
        position: absolute;
        bottom: 10px;
        left: 50%;
        transform: translateX(-50%);
        width: 45px;
        height: 14px;
        background-color: rgba(255, 255, 255, 0.5);
        border-radius: calc(13px / 2);
        overflow: hidden;
      }
      ul li {
        list-style: none;
        margin: 3px;
        float: left;
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background: skyblue;
      }
      .selected {
        background: red;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="box">
        <img src="https://picsum.photos/id/237/600/400" alt="" />
        <img src="https://picsum.photos/id/238/600/400" alt="" />
        <img src="https://picsum.photos/id/239/600/400" alt="" />
        <img src="https://picsum.photos/id/237/600/400" alt="" />
      </div>
      <ul class="dots">
        <li class="selected"></li>
        <li></li>
        <li></li>
        <li></li>
      </ul>
      <span class="left">&lt;</span>
      <span class="right">&gt;</span>
    </div>

    <script>
      var box = document.querySelector(".box");
      var right = document.querySelector(".right");
      var left = document.querySelector(".left");
      var index = 1; // 图片索引
      right.addEventListener("click", function () {
        index++;
        if (index > 3) {
          index = 1;
        }
        updateDotsAndAnimate(index);
      });

      left.addEventListener("click", function () {
        index--;
        if (index < 1) {
          index = 3;
        }
        updateDotsAndAnimate(index);
      });

      function updateDotsAndAnimate(index) {
        var lis = document.querySelectorAll("ul li");
        for (var i = 0; i < lis.length; i++) {
          lis[i].classList.remove("selected"); // 移除所有的选中状态
        }
        var li = document.querySelectorAll("ul li")[index - 1];
        li.classList.add("selected"); // 添加选中状态
        animate(box, -600 * (index - 1)); // 动画效果
      }

      var lis = document.querySelectorAll("ul li");
      for (var i = 0; i < lis.length; i++) {
        (function (i) {
          // 使用 IIFE 捕获当前索引
          lis[i].addEventListener("click", function () {
            updateDotsAndAnimate(i + 1); // 传递正确的索引
          });
        })(i); // 立即调用函数表达式
      }

      var timer = setInterval(function () {
        // 怎么判断是否聚焦
        if (box == document.activeElement) {
          return; // 聚焦则不切换图片
        }
        right.click();
      }, 2000); // 定时切换图片
    </script>
  </body>
</html>

let关键字

varlet 是 JavaScript 中用来声明变量的关键字,它们之间有几个重要的区别:

  1. 作用域

    • var 声明的变量是函数作用域(function scope)或全局作用域(global scope)。如果在函数内部使用 var 声明变量,那么这个变量的作用域仅限于该函数内部。
    • let 声明的变量是块作用域(block scope)。这意味着 let 声明的变量只在包含它的块中可用(例如,if 语句、for 循环等)。
    if (true) {
      var x = 10; // x 在整个函数或全局作用域可用
      let y = 20; // y 仅在这个块内可用
    }
    console.log(x); // 输出 10
    console.log(y); // 报错: y is not defined
  2. 提升(Hoisting)

    • var 声明的变量会被提升到作用域的顶部,但在赋值之前,变量的值是 undefined
    • let 声明的变量也会被提升,但在赋值之前,不能访问这个变量,这会导致”暂时性死区”(temporal dead zone)的错误。
    console.log(a); // 输出 undefined
    var a = 5;
    
    console.log(b); // 报错: Cannot access 'b' before initialization
    let b = 10;
  3. 重复声明

    • 使用 var 可以在同一作用域内重复声明变量,而不会报错。
    • 使用 let 不允许在同一作用域内重复声明同名变量,这会导致语法错误。
    var c = 1;
    var c = 2; // 不报错
    
    let d = 3;
    let d = 4; // 报错: Identifier 'd' has already been declared
  4. 总结

  • 使用 let 声明变量时,它有更严格的作用域规则,并且不会被意外地重复声明。
  • 一般建议使用 let(或 const,用于声明不可变变量)来替代 var,以提高代码的可读性和可维护性。

节流阀

防止轮播图按钮连续点击造成播放过快,

节流阀目的: 当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路: 利用回调函数,添加一个变量来控制,锁住函数和解锁函数。

var flag = true;
arrow_right.addEventListener("click", function () {
  flag = false;
  // 其余代码 ...
  animate(1000, function () {
    // 在回调函数中,等动画结束在改变flag值
    flag = true;
  });
});

返回顶部

滚动窗口至文档中的特定位置。

window.scroll(x, y);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>窗口滚动</title>
    <style>
      .header {
        height: 100px;
        background-color: #de9898;
      }
      .main {
        height: 1500px;
        background-color: #5f3434;
      }
      .footer {
        height: 100px;
        background-color: #b12727;
      }
      div {
        margin-bottom: 30px;
      }
      .backtop {
        position: fixed;
        bottom: 100px;
        right: 100px;
        width: 50px;
        height: 50px;
        background-color: #342a2a;
        border-radius: 50%;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div class="header"></div>
    <div class="main"></div>
    <div class="footer"></div>
    <div class="backtop"></div>
  </body>
  <script>
    backtop = document.querySelector(".backtop");
    backtop.addEventListener("click", function () {
      animate(window, 0, 0, function () {
        console.log("动画结束");
      });
    });

    function animate(element, distance, duration, callback) {
      clearInterval(element.timer);
      element.timer = setInterval(
        function () {
          var step = (distance - window.pageYOffset) / 10;
          step > 0 ? (step = Math.ceil(step)) : (step = Math.floor(step));

          if (window.pageYOffset == distance) {
            clearInterval(element.timer);
            if (callback) {
              callback();
            }
          } else {
            window.scroll(0, window.pageYOffset + step);
          }
        },
        duration ? duration : 15
      );
    }
  </script>
</html>

移动端特效

1.触屏事件

1.1 触屏事件概述

移动端浏览器兼容性较好,我们不需要考虑以前 JS 的兼容性问题,可以放心的使用原生 JS 书写效果,但是移动端也有自己独特的地方。比如触屏事件touch(也称触摸事件),Android 和 IOS 都有。

touch对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。

常见的触摸事件有:

触屏 touch 事件 说明
touchstart 手指触摸到一个 DOM 元素时触发
touchmove 手指在一个 DOM 元素上滑动时触发
touchend 手指从一个 DOM 元素上移开时触发

1.2 触摸事件对象(TouchEvent)

  • TouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等
  • touchstart、touchmove、touchend 三个事件都会各自有事件对象。

触摸事件对象重点我们看三个常见对象列表:

触摸列表 说明
touches 正在触摸屏幕的所有手指的一个列表
targetTouches 正在触摸当前 DOM 元素上的手指的一个列表
changedTouches 手指状态发生了改变的列表,从无到有,从有到无变化
  • 当我们手指离开屏幕的时候,就没有了touches 和 targetTouches 列表,但是会有 changedTouches (从有到无)

1.3 移动端拖动事件

  1. touchstart、touchmove、touchend 可以实现拖动元素

  2. 但是拖动元素需要当前手指的坐标值我们可以使用 targetTouches[0] 里面的 pageX 和 pageY

  3. 移动端拖动的原理:手指移动中,计算出手指移动的距离。然后用盒子原来的位置 + 手指移动的距离

  4. 手指移动的距离:手指滑动中的位置减去手指刚开始触摸的位置拖动元素三步曲:
    (1) 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置

    (2) 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子

    (3) 离开手指 touchend:

注意:手指移动也会触发滚动屏幕所以这里要阻止默认的屏幕滚动e.preventDefault();

var startX, startY, x, y;
var div = document.querySelector("div");
div.addEventListener("touchstart", function (event) {
  console.log("touchstart" + event.targetTouches[0].pageX);
  event.preventDefault();
  startX = event.targetTouches[0].pageX;
  startY = event.targetTouches[0].pageY;
  x = div.offsetLeft;
  y = div.offsetTop;
});
div.addEventListener("touchmove", function (event) {
  console.log(event.targetTouches[0].pageX);
  event.preventDefault();
  var moveX = event.targetTouches[0].pageX - startX;
  var moveY = event.targetTouches[0].pageY - startY;
  div.style.left = x + moveX + "px";
  div.style.top = y + moveY + "px";
});

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>
    <link rel="stylesheet" href="../综合案例/携程移动端/css/normalize.css" />
    <link rel="stylesheet" href="../综合案例/携程移动端/css/index.css" />
    <title>携程在手,说走就走</title>
  </head>
  <body>
    <!-- 焦点图模块 -->
    <div class="focus">
      <ul>
        <li><img src="../综合案例/携程移动端/upload/focus.jpg" alt="" /></li>
        <li><img src="../综合案例/携程移动端/upload/focus.jpg" alt="" /></li>
        <li><img src="../综合案例/携程移动端/upload/focus.jpg" alt="" /></li>
        <li><img src="../综合案例/携程移动端/upload/focus.jpg" alt="" /></li>
        <li><img src="../综合案例/携程移动端/upload/focus.jpg" alt="" /></li>
      </ul>
      <!-- 小圆点 -->
      <ol>
        <li class="current"></li>
        <li></li>
        <li></li>
      </ol>
    </div>
  </body>
  <script>
    // 移动端轮播
    // 移动端轮播
    window.addEventListener("load", function () {
      // 获取元素
      var focus = document.querySelector(".focus");
      var ul = focus.children[0];
      var ol = focus.querySelector("ol");
      // 获得focus的宽度
      var w = focus.offsetWidth;
      // 利用定时器
      var index = 0;
      var timer = setInterval(function () {
        index++;
        // 切换样式
        ul.style.transition = "transform 0.5s ease";
        ul.style.transform = "translateX(" + -w * index + "px)";
      }, 2000);

      // 等着过渡完成
      ul.addEventListener("transitionend", function () {
        // 无缝切换
        if (index >= 3) {
          index = 0;
          ul.style.transition = "none";
          ul.style.transform = "translateX(" + -w * index + "px)";
        } else if (index < 0) {
          index = 2;
          ul.style.transition = "none";
          ul.style.transform = "translateX(" + -w * index + "px)";
        }
        // 小圆点切换
        ol.querySelector(".current").classList.remove("current");
        ol.children[index].classList.add("current");
      });

      // 手机滑动轮播
      var startX = 0;
      var moveX = 0;
      var flag = false;
      ul.addEventListener("touchstart", function (e) {
        startX = e.targetTouches[0].pageX;
        clearInterval(timer); // 停止定时器
      });

      ul.addEventListener("touchmove", function (e) {
        // e.preventDefault();
        // 计算移动距离
        moveX = e.targetTouches[0].pageX - startX;
        // 移动盒子
        ul.style.transition = "none"; // 禁止transition动画
        ul.style.transform = "translateX(" + (-w * index + moveX) + "px)";
        flag = true; // 标记移动状态
      });

      ul.addEventListener("touchend", function (e) {
        if (flag) {
          // 根据滑动距离决定是切换到上一张还是下一张
          if (Math.abs(moveX) > 50) {
            if (moveX > 0) {
              index--;
            } else {
              index++;
            }
            var translatex = -index * w;
            ul.style.transition = "all .3s";
            ul.style.transform = "translateX(" + translatex + "px)";
          } else {
            // 小于50px回弹效果
            var translatex = -index * w;
            ul.style.transform = "translateX(" + translatex + "px)";
          }
          // 手指离开后重新启动定时器
          clearInterval(timer);
        }
      });
    });
  </script>
</html>

3.返回顶部效果

<!DOCTYPE html>
<html lang="zh">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>返回顶部示例</title>
    <style>
      body {
        font-family: Arial, sans-serif;
        line-height: 1.6;
      }

      .content {
        height: 2000px; /* 使页面足够长以便测试滚动 */
        padding: 20px;
      }

      .goBack {
        position: fixed;
        bottom: 20px;
        right: 20px;
        width: 50px;
        height: 50px;
        background-color: skyblue;
        color: white;
        border: none;
        border-radius: 25px;
        display: none; /* 初始状态隐藏 */
        justify-content: center;
        align-items: center;
        cursor: pointer;
        font-size: 24px;
        box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
        z-index: 1000; /* 确保按钮在最上层 */
      }

      .goBack.show {
        z-index: 1000; /* 确保按钮在最上层 */
        display: flex; /* 显示按钮 */
      }
    </style>
  </head>
  <body>
    <div class="content">
      <h1>这是一个返回顶部示例</h1>
      <p>这里是一些内容...</p>
      <p>内容很多...</p>
      <p>更多内容...</p>
      <p>甚至更多内容...</p>
      <p>继续添加内容以便滚动...</p>
      <p>更多...</p>
    </div>

    <div class="goBack" id="goBack"></div>

    <script>
      window.onscroll = function () {
        const goBackButton = document.getElementById("goBack");

        if (
          document.body.scrollTop > 100 ||
          document.documentElement.scrollTop > 100
        ) {
          goBackButton.classList.add("show");
        } else {
          goBackButton.classList.remove("show");
        }
      };

      document.getElementById("goBack").onclick = function () {
        window.scrollTo({
          top: 0,
          behavior: "smooth", // 平滑滚动
        });
      };
    </script>
  </body>
</html>

4.移动端 click 延时处理

移动端 click 事件会有 300ms 的延时,原因是移动端屏幕双击会缩放(double tap to zoom) 页面。

解决方案:

  1. 禁用缩放。浏览器禁用默认的双击缩放行为并且去掉 300ms 的点击延迟
<meta name="viewport" content="user-scalable=no" />
  1. 利用 touch 事件自己封装这个事件解决 300ms 延迟,

原理就是: 1.当我们手指触摸屏幕,记录当前触摸时间 2.当我们手指离开屏幕,用离开的时间减去触摸的时间 3.如果时间小于 150ms,并且没有滑动过屏幕,那么我们就定义为点击

// 封装tap,解决click 300ms 延时
function tap(obj, callback) {
  var isMove = false;
  var startTime = 0; // 记录触摸时候的时间变量

  obj.addEventListener("touchstart", function (e) {
    isMove = false; // 重置移动状态
    startTime = Date.now(); // 记录触摸时间
  });

  obj.addEventListener("touchmove", function (e) {
    isMove = true; // 如果有滑动,标记为拖拽
  });

  obj.addEventListener("touchend", function (e) {
    if (!isMove && Date.now() - startTime < 150) {
      // 手指触摸和离开时间小于150ms
      callback && callback(); // 执行回调函数
    }

    // 重置状态
    isMove = false;
    startTime = 0;
  });
}

// 调用示例
var div = document.getElementById("myDiv"); // 假设你有一个id为myDiv的元素
tap(div, function () {
  console.log("Tapped!"); // 执行识别代码
});
  1. 使用插件。fastclick 插件解决 300ms 延迟。

5.移动端常用开发插件

5.1 什么是插件

移动端要求的是快速开发,所以我们经常会借助于一些插件来帮我完成操作,那么什么是插件呢?

插件是 javascript 文件,它遵循一定规范编写,方便程序展示效果,拥有特定功能且方便调用。如轮播图和瀑布流插件。

特点:它一般是为了解决某个问题而专门存在,其功能单一,并且比较小。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../插件/fastclick.js"></script>
    <style>
      div {
        width: 100px;
        height: 100px;
        background-color: red;
      }
    </style>
  </head>
  <body>
    <div></div>
    <script>
      if ("addEventListener" in document) {
        document.addEventListener(
          "DOMContentLoaded",
          function () {
            FastClick.attach(document.body);
          },
          false
        );
      }
      var div = document.querySelector("div");
      div.addEventListener("click", function () {
        alert("div被点击了");
      });
    </script>
  </body>
</html>

5.2 Swiper 插件的使用

中文官网地址: https://www.swiper.com.cn/

  1. 引入插件相关文件。
  2. 按照规定语法使用

5.3 其他插件

5.4 练习-移动端视频插件 zy.media.js

H5 给我们提供了 video 标签,但是浏览器的支持情况不同。

不同的视频格式文件,我们可以通过 source 解决;

但是外观样式,还有暂停,播放,全屏等功能我们只能自己写代码解决,这个时候我们可以使用插件方式来制作。

<!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="../src/插件/zy.media.js/examples/zy.media.min.css"
    />
  </head>
  <body>
    <div class="zy_media">
      <video data-config='{"mediaTitle": "小米宣传片"}'>
        <source
          src="../html5和css3提高/opening_idea_movie_final.mp4"
          type="video/mp4"
        />
        您的浏览器不支持HTML5视频
      </video>
      <script src="../src/插件/zy.media.js/zy.media.js"></script>
      <script>
        zymedia("video");
      </script>
    </div>
  </body>
</html>

6. 移动端常用开发框架

6.1 框架概述

框架,顾名思义就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。

框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。

插件一般是为了解决某个问题而专门存在,其功能单一,并且比较小。

  • 前端常用的框架有 Bootstrap、Vue、Angular、React 等。既能开发 PC 端,也能开发移动端

  • 前端常用的移动端插件有 swiper、superslide、iscroll 等

    区别

  • 框架:大而全,一整套解决方案

  • 插件:小而专一,某个功能的解决方案

6.2 Bootstrap

  • Bootstrap 是一个简洁、直观、强悍的前端开发框架,它让 web 开发更迅速、简单。
    它能开发 PC 端,也能开发移动端
  • BootstrapJS 插件使用步骤:
    1. 引入相关 对应 版本javascipt 文件
    2. 复制 HTML 结构(在对应版本的官方文档里Bootstrap v4 中文文档 v4.6)
    3. 修改对应 CSS 样式
    4. 修改相应 JS 参数
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>Bootstrap轮播图插件</title>
    <link
      rel="stylesheet"
      href="../src/插件/bootstrap-4.6.2/dist/css/bootstrap.min.css"
    />
    <script src="../src/插件/jquery/jquery3.7.1_slim.js"></script>
    <script src="../src/插件/bootstrap-4.6.2/dist/js/bootstrap.min.js"></script>
    <style>
      .facous {
        width: 800px;
        height: 300px;
        background-color: pink;
        margin: 100px auto;
      }
    </style>
  </head>
  <body>
    <div class="facous">
      <div
        id="carouselExampleControls"
        class="carousel slide"
        data-ride="carousel"
      >
        <div class="carousel-inner">
          <div class="carousel-item active">
            <img src="../src/bear.png" class="d-block w-100" alt="..." />
          </div>
          <div class="carousel-item">
            <img src="../src/bear.png" class="d-block w-100" alt="..." />
          </div>
          <div class="carousel-item">
            <img src="../src/bear.png" class="d-block w-100" alt="..." />
          </div>
        </div>
        <button
          class="carousel-control-prev"
          type="button"
          data-target="#carouselExampleControls"
          data-slide="prev"
        >
          <span class="carousel-control-prev-icon" aria-hidden="true"></span>
          <span class="sr-only">Previous</span>
        </button>
        <button
          class="carousel-control-next"
          type="button"
          data-target="#carouselExampleControls"
          data-slide="next"
        >
          <span class="carousel-control-next-icon" aria-hidden="true"></span>
          <span class="sr-only">Next</span>
        </button>
      </div>
    </div>
  </body>
</html>

本地储存

target

  • 能够写出 sessionStorage 数据的存储以及获取
  • 能够写出 localStorage 数据的存储以及获取
  • 能够说出它们两者的区别

1.本地存储

随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。

本地存储特性

1、数据存储在用户浏览器中

2、设置、读取方便、甚至页面刷新不丢失数据

3、容量较大,sessionStorage约5M、localStorage约20M

4、只能存储字符串,可以将对象JSON.stringify()编码后存储

2.window.sessionStorage

  1. 生命周期为关闭浏览器窗口
  2. 在同一个窗口(页面)下数据可以共享
  3. 以键值对的形式存储使用

存储数据:

sessionStorage.setItem(key, value);

获取数据:

sessionStorage.getItem(key);

删除数据:

sessionStorage.removeItem(key);

删除所有数据:

sessionStorage.clear();

3.window.localStorage

  1. 生命周期永久生效,除非手动删除否则关闭页面也会存在
  2. 可以多窗口(页面)共享(同一浏览器可以共享)
  3. 以键值对的形式存储使用

存储数据:

localStorage.setItem(key,value);

获取数据:

localStorage.getItem(key);

删除数据:

localStorage.removeItem(key);

删除全部数据:

localStorage.clear();

4. 记住用户名案例

如果勾选记住用户名,下次用户打开浏览器,就在文本框里面自动显示上次登录的用户名

  1. 把数据存起来,用到本地存储
  2. 关闭页面,也可以显示用户名,所以用到localStorage
  3. 打开页面,先判断是否有这个用户名,如果有,就在表单里面显示用户名,并且勾选复选框
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>记住用户名案例</title>
    </head>
    <body>
        <input type="text" id="username" />
        <input type="checkbox" id="remember" /> 记住用户名
        <script>
            var username = document.querySelector("#username");
            var remember = document.querySelector("#remember");
            if (localStorage.getItem("username")) {
                username.value = localStorage.getItem("username");
                remember.checked = true;
            }
            remember.addEventListener("change", function () {
                if (remember.checked) {
                    localStorage.setItem("username", username.value);
                } else {
                    localStorage.removeItem("username");
                }
            });
        </script>
    </body>
</html>

JQuery

1.jQuery概述

1.1 JavaScript库

仓库: 可以把很多东西放到这个仓库里面。找东西只需要到仓库里面查找到就可以了

JavaScript库:即library,是一个封装好的特定的集合(方法和函数)。从封装一大堆函数的角度理解库,就是在这个库中,封装了很多预先定义好的函数在里面,比如动画animate、hide、show,比如获取元素等

比如jQuery,就是为了快速方便的操作DOM,里面基本都是函数(方法)。

1.2 jQuery的概念

jQuery 是一个快速、简洁的 JavaScript 库,其设计的宗旨是 **”write Less,Do More”**,即倡导写更少的代码做更多的事情。

jQuery 封装了JavaScript常用的功能代码,优化了 DOM 操作、事件处理、动画设计和 Ajax交互

  • jQuery 的优点
    • 轻量级。核心文件才几十kb,不会影响页面加载速度
    • 跨浏览器兼容。基本兼容了现在主流的浏览器
    • 链式编程、隐式迭代
    • 对事件、样式、动画支持,大大简化了DOM操作
    • 支持插件扩展开发。有着丰富的第三方的插件
    • 例如:树形菜单、日期控件、轮播图等
    • 免费、开源

2.jQuery的基本使用

2.1 jQuery 的下载

官网地址:https://jquery.com/

code.jquery.com/jquery-3.5.1.min.js

版本

  • 1x: 兼容IE 678等低版本浏览器,官网不再更新
  • 2x: 不兼容IE 678等低版本浏览器,官网不再更新
  • 3x: 不兼容IE 678等低版本浏览器,是官方主要更新维护的版本

2.2 jQuery 的入口函数

$(function (){
    //此处是页面 DOM 加载完成的入口
});

$(document).ready(function(){
    //此处是页面DOM加载完成的入口
});
  1. 等着 DOM 结构渲染完毕即可执行内部代码,不必等到所有外部资源加载完成,jQuery 帮我们完成了封装。
  2. 相当于原生 javascript 中的DOMContentLoaded

2.4 jQuery 的顶级对象$

  1. $是jQuery的别称,在代码中可以使用jQuery代替$,但一般为了方便,通常都直接使用$
  2. $是jQuery的顶级对象,相当于原生JavaScript中的window。把元素利用$包装成jQuery对象,就可以调用jQuery的方法。

2.5 jQuery 对象和 DOM 对象

  1. 用原生 JS 获取来的对象就是 DOM 对象
  2. jQuery方法获取的元素就是jQuery对象。
  3. jQuery 对象只能使用 jQuery 方法,DOM 对象则使用原生的 Javascirpt 属性和方法

DOM 对象与jQuery对象之间是可以相互转换的。

因为原生 js 比 jQuery 更大,原生的一些属性和方法jQuery没有给我们封装.要想使用这些属性和方法需要把jQuery对象转换为DOM对象才能使用。

  1. DOM 对象转换为jQuery对象:$(DOM对象)
  2. jQuery对象转换为 DOM 对象(两种方式)
$('div')[index]
// index是索引号
$('div'),get(index)

3.jQuery的选择器

3.1 jQuery的基础选择器

原生JS获取元素方式很多,很杂,而且兼容性情况不一致,因此jQuery给我们做了封装,使获取元素统一标准。

$("选择器") //里面选择器直接写CSS选择器即可,但是要加引号
名称 用法 描述
ID选择器 $(“#id”) 获取指定ID的元素
全选选择器 $(“*”) 匹配所有元素
类选择器 $(“.class”) 获取同一类class的元素
标签选择器 $(“div”) 获取同一类标签的所有元素
并集选择器 $(“div,p,li”) 选取多个元素
交集选择器 $(“li.current”) 交集元素

3.2 层级选择器

名称 用法 描述
子代选择器 $(“ul>li”) 使用>号,获取亲儿子层级的元素;注意,并不会获取孙子层级的元素
后代选择器 $(“ul li”) 使用空格,代表后代选择器,获取ul下的所有li元素,包括孙子等

3.3 隐式迭代

遍历内部DOM元素(伪数组形式存储)的过程就叫做隐式迭代

简单理解: 给匹配到的所有元素进行循环遍历,执行相应的方法,而不用我们再进行循环,简化我们的操作方便我们调用。

3.4 jQuery筛选选择器

语法 用法 描述
:first $(‘li:first’) 获取第一个li元素
:last $(‘li:last’) 获取最后一个li元素
:eq(index) $(“li:eq(2)”) 获取到的li元素中,选择索引号为2的元素,索引号index从0开始
:odd $(“li:odd”) 获取到的li元素中,选择索引号为奇数的元素
:even $(“li:even”) 获取到的li元素中,选择索引号为偶数的元素

3.5 jQuery筛选方法(重点)

语法 用法 说明
parent() $(“li”).parent(); 查找父级
children(selector) $(“ul”).children(“li”); 相当于$(“ul>li”),最近一级(亲儿子)
find(selector) $(“ul”).find(“li”); 相当于$(“ul li”),后代选择器
siblings(selector) $(“.first”).siblings(“li”); 查找兄弟节点,不包括自身
nextAll([expr]) $(“.first”).nextAll() 查找当前元素之后所有的同辈元素
prevtAll([expr]) $(“.last”).prevAll() 查找当前元素之前所有的同辈元素
hasClass(class) $(“div”).hasClass(“protected”) 检查当前的元素是否含有某个特定的类,如果有,则返回true
eq(index) $(“li”).eq(2); 相当于$("li:eq(2)"),index从0开始

3.6 jQuery的排他思想

思路: 利用siblings()筛选方法选出除自身外元素修改为默认样式

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>jQuery的排他思想</title>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    </head>

    <body>
        <button>按钮</button>
        <button>按钮</button>
        <button>按钮</button>
        <button>按钮</button>
        <button>按钮</button>
        <script>
            $(function () {
                $("button").click(function () {
                    $(this).css("background-color", "red");
                    // $("button").not(this).css("background-color", "");
                    $(this).siblings("button").css("background-color", "");
                });
            });
        </script>
    </body>
</html>

index()方法

$("button").click(function () {
    // index() 方法可以获取当前元素在其同辈元素中的位置索引
    console.log($(this).index());
});

4. jQuery样式操作

4.1 操作CSS方法

jQuery可以使用css方法来修改简单元素样式;也可以操作类,修改多个样式

  1. 参数只写属性名,则是返回属性值
$(this).css("'color");
  1. 参数是属性名,属性值,逗号分隔,是设置一组样式,属性必须加引号,值如果是数字可以不用跟单位和引号
$(this).css("color", "red");
  1. 参数可以是对象形式,方便设置多组样式。属性名和属性值用冒号隔开,属性可以不用加引号
$(this).css({"color":"white","font-size":"20px"});

4.2 设置类样式方法

作用等同于以前的 classList,可以操作类样式,注意操作类里面的参数不要加点

  1. 添加类
$("div").addClass("current");
  1. 删除类
$("div").removeClass("current");
  1. 切换类
$("div").toggleClass("current");

5. jQuery效果

5.1 元素的显示和隐藏

  1. 显示语法规范

    show([speed,[easing],[fn]])
  2. 显示参数

  • 参数都可以省略,无动画直接显示。

  • speed: 三种预定速度之一字符串(“slow”,”normal”,or “fast”)或表示动画时长的毫秒数值(如:1000)

  • easing: (Optional)用来指定切换效果,默认是 “swing” ,可用参数 “linear”

  • fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

  1. 隐藏语法规范

    show([speed,[easing],[fn]])
  2. 隐藏参数

  • 参数都可以省略,无动画直接显示。

  • speed: 三种预定速度之一字符串(“slow”,”normal”,or “fast”)或表示动画时长的毫秒数值(如:1000)

  • easing: (Optional)用来指定切换效果,默认是 “swing” ,可用参数 “linear”

  • fn: 回调函数,在动画完成时执行的函数,每个元素执行一次

切换语法规范

toggle([speed,[easing],[fn]]);

5.2 滑动效果

  1. 滑动切换效果语法规范

    slideToggle([speed,[easing],[fn]]);
  2. 滑动切换效果参数

    • 参数都可以省略。
    • speed: 三种预定速度之一的字符串(“slow”,”normal”,or “fast”)或表示动画时长的毫秒数值(如:1000)
    • easing: (Optional)用来指定切换效果,默认是 “swing” 可用参数 “linear”
    • fn: 回调函数,在动画完成时执行的函数,每个元素执行一次。

5.3 事件切换

hover([over,]out)
  1. over:鼠标移到元素上要触发的函数(相当于mouseenter)
  2. out:鼠标移出元素要触发的函数(相当于mouseleave)

如果只写一个函数,鼠标移入和离开都会触发这个函数

5.4 动画队列及其停止排队方法

  1. 动画或效果队列

动画或者效果一旦触发就会执行,如果多次触发,就造成多个动画或者效果排队执行

2.停止排队

stop();
  1. stop()方法用于停止动画或效果,
  2. 注意:stop()写到动画或者效果的前面,相当于停止结束上一次的动画。
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>导航栏</title>
        <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
        <style>
            ul {
                list-style: none;
                padding: 0;
            }
            ul li {
                float: left;
                margin-right: 10px;
                position: relative;
            }
            ul li span {
                display: inline-block;
                width: 50px;
                height: 20px;
                margin: 0;
                text-align: center;
            }
            ul li .content {
                display: none;
                width: 100%;
                height: 290px;
                background-color: blue;
                position: absolute;
                top: 100%;
                left: 0;
            }
        </style>
    </head>
    <body>
        <div class="box">
            <ul>
                <li>
                    <span>导航</span>
                    <div class="content"></div>
                </li>
                <li>
                    <span>导航</span>
                    <div class="content"></div>
                </li>
                <li>
                    <span>导航</span>
                    <div class="content"></div>
                </li>
                <li>
                    <span>导航</span>
                    <div class="content"></div>
                </li>
                <li>
                    <span>导航</span>
                    <div class="content"></div>
                </li>
            </ul>
        </div>
        <script>
            $("ul>li").hover(function () {
                // 先停止动画
                $(this).children(".content").stop().slideToggle();
            });
        </script>
    </body>
</html>

5.5 淡入淡出效果

  1. 淡入效果语法规范
fadeIn([speed,[easing],[fn]])
  1. 淡入效果参数
    • 参数都可以省略。
    • speed:三种预定速度之一的字符串(“slow”,”normal”,or “fast”)或表示动画时长的亳秒数值(如:1000)
    • easing: (Optional)用来指定切换效果,默认是 “swing” 可用参数 “linear”
    • fn: 回调函数,在动画完成时执行的函数,每个元素执行一次。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>淡入淡出效果</title>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <style>
      div {
        width: 200px;
        height: 200px;
        background-color: red;
      }
    </style>
  </head>
  <body>
    <button>淡入</button>
    <button>淡出</button>
    <button>淡入淡出切换</button>
    <button>修改透明度</button>
    <div></div>
    <script>
      $(function () {});
      $("button")
        .eq(0)
        .click(function () {
          $("div").fadeIn();
        });
      $("button")
        .eq(1)
        .click(function () {
          $("div").fadeOut();
        });
      $("button")
        .eq(2)
        .click(function () {
          $("div").fadeToggle();
        });
      $("button")
        .eq(3)
        .click(function () {
          $("div").fadeTo("slow", 0.5);
        });
    </script>
  </body>
</html>

5.6 自定义动画animate

  1. 语法
animate(params,[speed],[easing],[fn]);
  1. 参数
    • params:想要更改的样式属性,以对象形式传递,必须写。属性名可以不用带引号,如果是复合属性则需要采取驼峰命名法。其余参数都可以省略。
    • speed:三种预定速度之一的字符串(“slow”,”normal”,or “fast”)或表示动画时长的亳秒数值(如:1000)
    • easing: (Optional)用来指定切换效果,默认是 “swing” 可用参数 “linear”
    • fn: 回调函数,在动画完成时执行的函数,每个元素执行一次。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>动画效果</title>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <style>
      div {
        position: absolute;
        width: 200px;
        height: 200px;
        background-color: blue;
      }
    </style>
  </head>
  <body>
    <div></div>
    <script>
        // 实现自定义动画
      $(function () {
        $("div").click(function () {
          $(this).animate(
            {
              left: "250px",
              top: "250px",
              width: "100px",
              height: "100px",
              opacity: 0.5,
            },
            1000
          );
        });
      });
    </script>
  </body>
</html>

6. jQuery的属性操作

6.1 设置或获取元素固有属性值 prop()

所谓元素固有属性就是元素本身自带的属性,比如<a>元素里面的 href,比如 <input>元素里面的type

  1. 获取属性语法
prop("属性")
  1. 设置属性语法
prop("属性""属性值")

6.2 设置或获取元素自定义属性值 attr()

用户自己给元素添加的属性,我们称为自定义属性。比如给 div 添加 index=“1“

  1. 获取属性语法
attr("属性")//类似原生 getAttribute()
  1. 设置属性语法
attr("属性""属性值")//类似原生 setAttribute()

6.3 数据缓存 data()

data()方法可以在指定的元素上存取数据,并不会修改 DOM 元素结构。一旦页面刷新,之前存放的数据都将被移除

1.附加数据语法

data("name""value")// 向被选元素附加数据

2.获取数据语法

date("name")// 向被选元素获取数据

同时,还可以读取 HTML5 自定义属性 data-index,得到的是数字型

<span data-index="1">test</span>

console.log($("span").data("index")) <- 输出1 ->

7.jQuery内容文本值

主要针对元素的内容还有表单的值操作。

7.1 普通元素内容html()(相当于原生innerHTML)

html() //获取元素内容
html("内容") // 设置元素内容值

7.2 text()文本内容值

text()
text("文本内容")

7.3 val()表单值

val()
val("文本内容")
  • parents()返回所有祖先元素,例如parents('.father')返回祖先元素中class属性等于father的元素
  • toFixed(2)可以保留指定位小数

8. jQuery元素操作

8.1 遍历元素

jQuery隐式迭代是对同一类元素做了同样的操作。(如果想要给同一类元素做不同操作,就需要用到遍历)

语法1:

$("div").each(function(index,domEle){ xxx;})
  1. each()方法遍历匹配的每一个元素。主要用DOM处理。each每一个

  2. 里面的回调函数有2个参数: index 是每个元素的索引号; demEle是每个DOM元素对象,,不是jQuery对象

  3. 所以要想使用jQuery方法,需要给这个DOM元素转换为jQuery对象$(domEle)

语法2:

$.each(object,function(index,element){ xxx;})
  1. $.each()方法可用于遍历任何对象。主要用于数据处理,比如数组,对象
  2. 里面的函数有2个参数: index是每个元素的索引号; element遍历内容
// each() 方法用于遍历集合中的每个元素,并对每个元素执行一个函数。
var colors = ["red", "green", "blue", "yellow", "purple"];
$("li").each(function (index, element) {
    $(this).css("color", colors[index]);
    // element是DOM对象,不能使用jQuery方法
});

// $.each() 方法用于遍历数组或对象,并对每个元素执行一个函数,主要用于数据处理
var arr = [1, 2, 3, 4, 5];
$.each(arr, function (index, value) {
    console.log(index + ":" + value);
});

8.2 创建元素

$("<li>我是新创建的元素</Ii>");
// 新创建一个元素

8.3 添加元素

1.内部添加

element.append("内容") // 把内容放入匹配元素内部`最后面`,类似原生appendChild。
element.prepend("内容")

2.外部添加

element.after("内容")// 把内容放入目标元素后面
element.before("内容") // 把内容放入目标元素前面

8.4 删除元素

element.remove()// 删除匹配的元素(本身)
element.empty() // 删除匹配的元素集合中所有的子节点
element.html("") // 清空匹配的元素内容

9. jQuery尺寸和位置操作

9.1 尺寸操作

语法 用法
width() / height() 取得匹配元素宽度和高度值,只算width / height
innerWidth() / innerHeight() 取得匹配元素宽度和高度值,包含padding
outerWidth() / outerHeight() 取得匹配元素宽度和高度值,包含padding、border
outerWidth(true) / outerHeight(true) 取得匹配元素宽度和高度值,包含padding、border、margin

9.2 位置操作

位置主要有三个:offset()position()scrollTop() / scrollLeft()

  1. offset()设置或获取元素相对文档偏移: offset()方法设置或返回被选元素相对于文档的偏移坐标,跟父级没有关系。

  2. position()获取元素相对带定位父级偏移: position()方法用于返回被选元素相对于带有定位的父级偏移坐标,如果父级都没有定位,则以文档为准。

  3. scrollTop()/scrollLeft()设置或获取元素被卷去的头部和左侧区域

    • scrollTop() 方法设置或返回被选元素被卷去的头部。
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>回到顶部jquery版</title>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <style>
      #top {
        position: fixed;
        bottom: 10px;
        right: 10px;
        width: 50px;
        height: 50px;
        background-color: #f00;
        color: #fff;
        text-align: center;
        line-height: 50px;
        cursor: pointer;
        border-radius: 50%;
        z-index: 999;
      }
      #content {
        height: 2000px;
        background-color: pink;
      }
    </style>
  </head>
  <body>
    <div id="top">顶部按钮</div>
    <div id="content">内容</div>
  </body>
  <script>
    $(function () {
      $("#top").hide();
      // 当页面滚动超出1000像素时,显示回到顶部按钮
      $(window).scroll(function () {
        if ($(window).scrollTop() > 1000) {
          console.log("显示回到顶部按钮");
          $("#top").fadeIn(1000);
        } else {
          $("#top").fadeOut(1000);
        }
      });
      // 点击回到顶部按钮,页面回到顶部
      $("#top").click(function () {
        $("html,body").stop().animate(
          {
            scrollTop: 0,
          },
          1000
        );
      });
    });
  </script>
</html>

10. jQuery事件

10.1 单个事件注册

语法:

element.事件(function(){});
$('div').click(function(){
    console.log("div被点击");
})

10.2 事件处理on()绑定事件

on()方法在匹配元素上绑定一个或多个事件的事件处理函数

语法:

element.on(events,[selector],fn)
  1. events: 一个或多个用空格分隔的事件类型,如 “click” 或 “keydown”
  2. selector: 元素的子元素选择器
  3. fn: 回调函数 即绑定在元素身上的侦听函数。
on()方法优势1

可以绑定多个事件,多个处理事件处理程序。

$("div").on({
    mouseover:function(){},
    mouseout:function(){},
    click:function(){},
});

如果事件处理程序相同

$("div").on("mouseover mouseout"function(){
    $(this).toggleClass("current");
});
on()方法优势2:

可以事件委派操作。

事件委派的定义就是,把原来加给子元素身上的事件绑定在父元素身上,就是把事件委派给父元素。

$("ul").on("click", "li", function () {
    $(this).css("background-color", "yellow");
});
// click 是绑定在 ul 身上的,但是 触发的对象是 ul 里面的小li, this指向的是触发对象
on()方法优势3

动态创建的元素,click()没有办法绑定事件,on()可以给动态生成的元素绑定事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>微博发布功能</title>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <style>
      ul li a {
        float: right;
      }
      ul li {
        border-bottom: 1px solid #ccc;
        display: none;
      }
    </style>
    <script>
      $(function () {
        $("button").on("click", function () {
          var content = $(".txt").val();
          if (content == "") {
            alert("请输入内容");
            return false;
          }
          var li = $("<li></li>");
          li.html(content + "<a href='javascript:;'>删除</a>");
          $("#weibo ul").append(li);
          li.slideDown();
          $(".txt").val("");
        });

        // 事件委托
        $("ul").on("click", "a", function () {
          console.log(this);

          $(this)
            .parent()
            .slideUp(function () {
              $(this).remove(); // 删除列表项
            });
        });
      });
    </script>
    <style>
      .box {
        width: 500px;
        margin: 50px auto;
        padding: 20px;
        border: 1px solid #ccc;
        border-radius: 5px;
      }
    </style>
  </head>
  <body>
    <div class="box" id="weibo">
      <span>微博发布</span>
      <textarea
        name=""
        id=""
        class="txt"
        cols="30"
        rows="10"
        placeholder="发布你的微博"
      ></textarea>
      <button>发布</button>
      <ul></ul>
    </div>
  </body>
</html>

10.3 事件off()解绑事件

off()方法可以移除通过on()方法添加的事件处理程序。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>off解绑事件</title>
    <script src="../jquery-1.12.4.js"></script>
    <style>
      div {
        width: 400px;
        height: 400px;
        background-color: pink;
        margin: 0 auto;
      }
    </style>
  </head>
  <body>
    <div></div>
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
  </body>
  <script>
    $(function () {
      $("div").on({
        click: function () {
          console.log("点击");
        },
        mouseover: function () {
          console.log("鼠标经过");
        },
      });
      $("ul").on("click", "li", function () {
        this.style.backgroundColor = "yellow";
      });
      // off解绑事件
      $("div").off(); // 默认解绑所有事件
      $("div").off("click"); // 参数是监听函数名
      $("div").off("mouseover");
      $("ul").off("click", "li"); // 解绑事件委托
    });
  </script>
</html>

如果有的事件只想触发一次,可以使用one()来绑定事件。

10.4 自动触发事件 trigger()

有些事件希望自动触发,比如轮播图自动播放功能跟点击右侧按钮一致。可以利用定时器自动触发右侧按钮点击事件,不必鼠标点击触发。

element.click()  //第一种简写形式
element.trigger("type")  //第二种自动触发模式
element.triggerHandler(type)  //第三种自动触发模式

triggerHandler()触发事件,不执行默认行为

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>自动触发事件</title>
    <script src="../jquery-1.12.4.js"></script>
    <style>
      div {
        width: 200px;
        height: 200px;
        background-color: red;
      }
    </style>
  </head>
  <body>
    <div></div>
    <input type="text" />
  </body>
  <script>
    $(function () {
      $("div").on("click", function () {
        $(this).css("background-color", "blue");
      });
      $("input").on("focus", function () {
        $(this).val("输入框获得焦点了");
      });
      $("input").triggerHandler("focus"); // 触发事件,但不执行默认行为(光标移动到输入框)
      
      // 自动触发事件
      //   $("div").click();
      //   $("div").trigger("click");
      $("div").triggerHandler("click"); // 触发事件,但不执行默认行为
    });
  </script>
</html>

10.5 jQuery事件对象

事件被触发,就会有事件对象的产生

element.on(events,[selector],function(event){})

阻止默认行为: event.preventDefault()或者 return false

阻止冒泡: event.stopPropagation()

11. jQuery的其他方法

11.1 jQuery拷贝对象

如果想要把某个对象拷贝(合并)给另外一个对象使用,此时可以使用$.extend()方法

语法

$.extend([deep],target,object1,[objectN])
  1. deep: 如果设为 true 为深拷贝,默认为 false 浅拷贝
  2. target: 要拷贝的目标对象
  3. object1: 待拷贝到第一个对象的对象。
  4. 浅拷贝是把被拷贝的对象复杂数据类型中的地址拷贝给目标对象,修改目标对象会影响被拷贝对象。
  5. 深拷贝,前面加true ,完全克隆(拷贝的对象,而不是地址),修改目标对象不会影响被拷贝对象。如果有不冲突的属性,会拷贝到一起

11.2 多库共存

问题概述: jQuery使用$作为标示符,随着jQuery的流行,其他JavaScript库也会用这$作为标识符,这样一起使用会引起冲突

客观需求: 需要一个解决方案,让jQuery和其他的js库不存在冲突,可以同时存在,这就叫做多库共存。

jQuery 解决方案:

  1. 把里面的$符号统一改为jQuery。比如jQuery(‘div’)
  2. jQuery变量规定新的名称: $.noConflict(),var xx = $.noConflict()
// 假设是其他库
$(function () {
    function $(ele) {
        return document.querySelector(ele);
    }
    console.log($("div")); // 输出<div></div>
    jQuery.each(); // 想调用jquery的each方法,肯定会报错

    // 解决办法:
    var xxx = jQuery.noConflict(); // 保存原jquery
    xxx.each(); // 调用原jquery的each方法
});

11.3 jQuery插件

jQuery功能比较有限,想要更复杂的特效效果,可以借助于jQuery插件完成

注意:这些插件也是依赖于jQuery来完成的,所以必须要先引入jQuery文件,因此也称为jQuery插件。

jQuery插件常用的网站:

  1. jQuery插件库 http://www.jq22.com/
  2. jQuery之家 http://www.htmleaf.com/

插件使用:

  1. 到对应网站下载插件
  2. 到示例文件中复制css,js
  3. 复制插件结构
  4. 修改内容

懒加载技术

图片懒加载(图片使用延迟加载在可提高网页下载速度。它也能帮助减轻服务器负载)当我们页面滑动到可视区域,再显示图片。

我们使用jquery插件库 EasyLazyload。注意,此时的js引入文件和js调用必须写到 DOM元素(图片)最后面

全局滚动插件

gitHub: https://github.com/alvarotrigo/fullPage.js
中文翻译网站: http://www.dowebok.com/demo/2014/77/

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, user-scalable=no, initial-scale=1.0"
    />
    <title>fullpage插件使用</title>
    <link
      rel="stylesheet"
      href="../../src/jQuery插件/fullPage.js-master/dist/fullpage.min.css"
    />
    <script src="../jquery-1.12.4.js"></script>
    <script src="../../src/jQuery插件/fullPage.js-master/dist/fullpage.js"></script>
  </head>
  <body>
    <div id="dowebok">
      <div class="section">
        <h3>第一屏</h3>
      </div>
      <div class="section">
        <h3>第二屏</h3>
      </div>
      <div class="section">
        <h3>第三屏</h3>
      </div>
      <div class="section">
        <h3>第四屏</h3>
      </div>
    </div>
    <script>
      // 调用fullpage插件
      $(function () {
        // 初始化fullpage
        $('#dowebok').fullpage({
          sectionsColor: ['#1bbc9b', '#4BBFC3', '#7BAABE', '#f90'],
          navigation: true, // 导航栏
        });
  
        // 使用插件里面的函数
        $(document).on('click', function () {
          console.log('点击了页面');
          $.fn.fullpage.moveSectionUp(); // 通过Fullpage.js实例调用moveSectionUp
        });
      });
    </script>
  </body>
</html>

11.4 bootstrap组件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bootstrap插件使用</title>
    <link
      rel="stylesheet"
      href="../../src/插件/bootstrap-4.6.2/dist/css/bootstrap.min.css"
    />
    <script src="../jquery-1.12.4.js"></script>
    <script src="../../src/插件/bootstrap-4.6.2/dist/js/bootstrap.bundle.min.js"></script>
    <script src="../../src/插件/bootstrap-4.6.2/dist/js/bootstrap.min.js"></script>
  </head>
  <body>
    <div class="box">
      <!-- Example single danger button -->
      <div class="btn-group">
        <button
          type="button"
          class="btn btn-danger dropdown-toggle"
          data-toggle="dropdown"
          aria-expanded="false"
        >
          Action
        </button>
        <div class="dropdown-menu">
          <a class="dropdown-item" href="#">Action</a>
          <a class="dropdown-item" href="#">Another action</a>
          <a class="dropdown-item" href="#">Something else here</a>
          <div class="dropdown-divider"></div>
          <a class="dropdown-item" href="#">Separated link</a>
        </div>
      </div>

      <!-- 导航条 -->
      <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="#">Navbar scroll</a>
        <button
          class="navbar-toggler"
          type="button"
          data-toggle="collapse"
          data-target="#navbarScroll"
          aria-controls="navbarScroll"
          aria-expanded="false"
          aria-label="Toggle navigation"
        >
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarScroll">
          <ul
            class="navbar-nav mr-auto my-2 my-lg-0 navbar-nav-scroll"
            style="max-height: 100px"
          >
            <li class="nav-item active">
              <a class="nav-link" href="#"
                >Home <span class="sr-only">(current)</span></a
              >
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">Link</a>
            </li>
            <li class="nav-item dropdown">
              <a
                class="nav-link dropdown-toggle"
                href="#"
                role="button"
                data-toggle="dropdown"
                aria-expanded="false"
              >
                Link
              </a>
              <ul class="dropdown-menu">
                <li><a class="dropdown-item" href="#">Action</a></li>
                <li><a class="dropdown-item" href="#">Another action</a></li>
                <li><hr class="dropdown-divider" /></li>
                <li>
                  <a class="dropdown-item" href="#">Something else here</a>
                </li>
              </ul>
            </li>
            <li class="nav-item">
              <a class="nav-link disabled">Link</a>
            </li>
          </ul>
          <form class="d-flex">
            <input
              class="form-control mr-2"
              type="search"
              placeholder="Search"
              aria-label="Search"
            />
            <button class="btn btn-outline-success" type="submit">
              Search
            </button>
          </form>
        </div>
      </nav>
    </div>
  </body>
</html>

11.5 bootstrap的javascript插件的使用

模态 ·Bootstrap v4 中文文档 v4.6 |Bootstrap 中文网

  1. 包含所需要的文件自然不用多说
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-7ymO4nGrkm372HoSbq1OY2DP4pEZnMiA+E0F3zPr+JQQtQ82gQ1HPY3QIVtztVua" crossorigin="anonymous"></script>
  1. 所有你选择的模态框源代码必须包含在html标签中
<div
     class="modal fade"
     id="exampleModal"
     tabindex="-1"
     aria-labelledby="exampleModalLabel"
     aria-hidden="true"
     >
源代码
</div>

image-20241118143006464

自定义调用模态框显示的方法有两种:

  1. 一种是设定好<button>标签的data-toggle="modal" data-target="#exampleModal"属性,指向调用的模态框组件
<!-- 自己定义模态框 -->
<button data-toggle="modal" data-target="#exampleModal">
    打开模态框
</button>

<div
     class="modal fade"
     id="exampleModal"
     tabindex="-1"
     aria-labelledby="exampleModalLabel"
     aria-hidden="true"
     >
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">Modal title</h5>
                <button
                        type="button"
                        class="close"
                        data-dismiss="modal"
                        aria-label="Close"
                        >
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <p>Modal body text goes here.</p>
            </div>
            <div class="modal-footer">
                <button
                        type="button"
                        class="btn btn-secondary"
                        data-dismiss="modal"
                        >
                    Close
                </button>
                <button type="button" class="btn btn-primary">
                    Save changes
                </button>
            </div>
        </div>
    </div>
</div>
  1. 还有一种是使用javascript调用
// 调用方法二
$(function () {
    $("#myBtn").click(function () {
        $("#exampleModal").modal();
    });
});

完整代码

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Bootstrap插件使用</title>
        <link
              rel="stylesheet"
              href="../../src/插件/bootstrap-4.6.2/dist/css/bootstrap.min.css"
              />
        <script src="../jquery-1.12.4.js"></script>
        <script src="../../src/插件/bootstrap-4.6.2/dist/js/bootstrap.bundle.min.js"></script>
        <script src="../../src/插件/bootstrap-4.6.2/dist/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="box">
            <!-- Example single danger button -->
            <div class="btn-group">
                <button
                        type="button"
                        class="btn btn-danger dropdown-toggle"
                        data-toggle="dropdown"
                        aria-expanded="false"
                        >
                    Action
                </button>
                <div class="dropdown-menu">
                    <a class="dropdown-item" href="#">Action</a>
                    <a class="dropdown-item" href="#">Another action</a>
                    <a class="dropdown-item" href="#">Something else here</a>
                    <div class="dropdown-divider"></div>
                    <a class="dropdown-item" href="#">Separated link</a>
                </div>
            </div>

            <!-- 导航条 -->
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <a class="navbar-brand" href="#">Navbar scroll</a>
                <button
                        class="navbar-toggler"
                        type="button"
                        data-toggle="collapse"
                        data-target="#navbarScroll"
                        aria-controls="navbarScroll"
                        aria-expanded="false"
                        aria-label="Toggle navigation"
                        >
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarScroll">
                    <ul
                        class="navbar-nav mr-auto my-2 my-lg-0 navbar-nav-scroll"
                        style="max-height: 100px"
                        >
                        <li class="nav-item active">
                            <a class="nav-link" href="#"
                               >Home <span class="sr-only">(current)</span></a
                                >
                        </li>
                        <li class="nav-item">
                            <a class="nav-link" href="#">Link</a>
                        </li>
                        <li class="nav-item dropdown">
                            <a
                               class="nav-link dropdown-toggle"
                               href="#"
                               role="button"
                               data-toggle="dropdown"
                               aria-expanded="false"
                               >
                                Link
                            </a>
                            <ul class="dropdown-menu">
                                <li><a class="dropdown-item" href="#">Action</a></li>
                                <li><a class="dropdown-item" href="#">Another action</a></li>
                                <li><hr class="dropdown-divider" /></li>
                                <li>
                                    <a class="dropdown-item" href="#">Something else here</a>
                                </li>
                            </ul>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link disabled">Link</a>
                        </li>
                    </ul>
                    <form class="d-flex">
                        <input
                               class="form-control mr-2"
                               type="search"
                               placeholder="Search"
                               aria-label="Search"
                               />
                        <button class="btn btn-outline-success" type="submit">
                            Search
                        </button>
                    </form>
                </div>
            </nav>

            <!-- 模态框 -->
            <!-- Button trigger modal -->
            <button
                    type="button"
                    class="btn btn-primary"
                    data-toggle="modal"
                    data-target="#staticBackdrop"
                    >
                Launch static backdrop modal
            </button>

            <!-- Modal -->
            <div
                 class="modal fade"
                 id="staticBackdrop"
                 data-backdrop="static"
                 data-keyboard="false"
                 tabindex="-1"
                 aria-labelledby="staticBackdropLabel"
                 aria-hidden="true"
                 >
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title" id="staticBackdropLabel">Modal title</h5>
                            <button
                                    type="button"
                                    class="close"
                                    data-dismiss="modal"
                                    aria-label="Close"
                                    >
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <div class="modal-body">...</div>
                        <div class="modal-footer">
                            <button
                                    type="button"
                                    class="btn btn-secondary"
                                    data-dismiss="modal"
                                    >
                                Close
                            </button>
                            <button type="button" class="btn btn-primary">Understood</button>
                        </div>
                    </div>
                </div>
            </div>

            <!-- 自己定义模态框 -->
            <button id="myBtn" data-toggle="modal" data-target="#exampleModal">
                打开模态框
            </button>

            <div
                 class="modal fade"
                 id="exampleModal"
                 tabindex="-1"
                 aria-labelledby="exampleModalLabel"
                 aria-hidden="true"
                 >
                <div class="modal-dialog">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h5 class="modal-title">Modal title</h5>
                            <button
                                    type="button"
                                    class="close"
                                    data-dismiss="modal"
                                    aria-label="Close"
                                    >
                                <span aria-hidden="true">&times;</span>
                            </button>
                        </div>
                        <div class="modal-body">
                            <p>Modal body text goes here.</p>
                        </div>
                        <div class="modal-footer">
                            <button
                                    type="button"
                                    class="btn btn-secondary"
                                    data-dismiss="modal"
                                    >
                                Close
                            </button>
                            <button type="button" class="btn btn-primary">
                                Save changes
                            </button>
                        </div>
                    </div>
                </div>
            </div>
            <script>
                // 调用方法二
                $(function () {
                    $("#myBtn").click(function () {
                        $("#exampleModal").modal();
                    });
                });
            </script>
        </div>
    </body>
</html>