From 27a591865bfd2d6c44a97bcfd0808e4bf214267c Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 16 Nov 2025 18:12:58 +0800 Subject: [PATCH 1/9] feat:zuoye --- .../20251110-\345\210\235\350\257\206JS.md" | 141 ++++++ ...14\350\277\220\347\256\227\347\254\246.md" | 460 ++++++++++++++++++ ...17\345\222\214\345\217\230\351\207\217.md" | 175 +++++++ 3 files changed, 776 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251110-\345\210\235\350\257\206JS.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251113-js\347\232\204\350\241\250\350\276\276\345\274\217\345\222\214\350\277\220\347\256\227\347\254\246.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251110-\345\210\235\350\257\206JS.md" "b/\344\270\245\345\201\245\345\256\207/20251110-\345\210\235\350\257\206JS.md" new file mode 100644 index 000000000..804b16cce --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251110-\345\210\235\350\257\206JS.md" @@ -0,0 +1,141 @@ +# JavaScript 引入 HTML 的三种方式 + +## 1. 行内引入(嵌入式) + +直接在 HTML 标签的事件属性中写入 JavaScript 代码。 + +```html + + + + 行内引入示例 + + + + + + +
+ 悬停变色 +
+ + + + + + + +``` + +## 2. 内部引入(内嵌式) + +在 HTML 文件内的 ` + + +``` + +## 3. 外部引入(文件式) + +将 JavaScript 代码写在单独的 `.js` 文件中,通过 `src` 属性引入。 + +### HTML 文件 (index.html) + +```html + + + + 外部引入示例 + + + + +

+ + + + + +``` + +### JavaScript 文件 (script.js) + +```javascript +// 等待DOM加载完成 +document.addEventListener("DOMContentLoaded", function () { + const btn = document.getElementById("btn"); + const input = document.getElementById("textInput"); + const output = document.getElementById("output"); + + btn.addEventListener("click", function () { + output.textContent = "你点击了按钮!"; + }); + + input.addEventListener("input", function () { + output.textContent = "输入内容: " + this.value; + }); +}); +``` + +## 总结对比 + +| 方式 | 优点 | 缺点 | 适用场景 | +| ------------ | ------------------ | ------------------ | -------------------- | +| **行内引入** | 简单快速,易于测试 | 代码混乱,难以维护 | 简单测试,小功能 | +| **内部引入** | 代码集中,易于管理 | 只能在当前页面使用 | 单页面应用,简单项目 | +| **外部引入** | 代码复用,易于维护 | 需要额外 HTTP 请求 | 中大型项目,团队开发 | + +## 老子名言 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/老子名义.png) + +## 明日学院官网地址 + +- js 代码 + +```js +alert("http://www.mingrisoft.com"); +``` + +- html 代码 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/明日地址.png) diff --git "a/\344\270\245\345\201\245\345\256\207/20251113-js\347\232\204\350\241\250\350\276\276\345\274\217\345\222\214\350\277\220\347\256\227\347\254\246.md" "b/\344\270\245\345\201\245\345\256\207/20251113-js\347\232\204\350\241\250\350\276\276\345\274\217\345\222\214\350\277\220\347\256\227\347\254\246.md" new file mode 100644 index 000000000..819b0fa6e --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251113-js\347\232\204\350\241\250\350\276\276\345\274\217\345\222\214\350\277\220\347\256\227\347\254\246.md" @@ -0,0 +1,460 @@ +## 三、运算符 + +### 算术运算符 + +```javascript +10 + 5; // 15 加法 +10 - 5; // 5 减法 +10 * 5; // 50 乘法 +10 / 5; // 2 除法 +10 % 3; // 1 取余 +10 ** 2; // 100 指数 +``` + +### 赋值运算符 + +```javascript +let x = 10; +x += 5; // x = 15 +x -= 3; // x = 12 +x *= 2; // x = 24 +x /= 4; // x = 6 +``` + +### 比较运算符 + +```javascript +// 严格相等(推荐) +5 === 5; // true +5 === "5"; // false + +// 宽松相等 +5 == 5; // true +5 == "5"; // true + +// 其他比较 +5 !== 3; // true +5 > 3; // true +5 <= 10; // true +``` + +### 逻辑运算符 + +```javascript +// 与运算 +true && false; // false +5 > 3 && 2 < 4; // true + +// 或运算 +true || false; // true +5 > 3 || 2 > 4; // true + +// 非运算 +!true; // false +!(5 > 3); // false +``` + +### 其他运算符 + +```javascript +// 三元运算符 +age >= 18 ? "成年" : "未成年"; + +// 类型运算符 +typeof 42; // "number" +typeof "hello"; // "string" + +// 空值合并运算符(ES2020) +null ?? "默认值"; // "默认值" +``` + +## 四、表达式 + +### 定义 + +- 任何能产生值的代码单元 +- 由操作数和运算符组成 + +### 常见表达式类型 + +```javascript +// 算术表达式 +(10 + 5) * 2; // 30 + +// 字符串表达式 +"Hello " + "World"; // "Hello World" + +// 逻辑表达式 +age >= 18 && hasID; // 布尔值 + +// 赋值表达式 +x = 10 + 5; // 15 + +// 函数调用表达式 +Math.max(1, 2, 3); // 3 + +// 对象属性访问 +user.name; // 属性值 +``` + +## 五、数据类型转换 + +### 显式转换(强制转换) + +#### 转为数字 + +```javascript +Number("123"); // 123 +Number("123abc"); // NaN +Number(true); // 1 +Number(false); // 0 +Number(null); // 0 +Number(undefined); // NaN + +parseInt("123px"); // 123 +parseFloat("3.14cm"); // 3.14 +``` + +#### 转为字符串 + +```javascript +String(123); // "123" +String(true); // "true" +String(null); // "null" +String(undefined)( + // "undefined" + + 123 +).toString(); // "123" +``` + +#### 转为布尔值 + +```javascript +Boolean(0); // false +Boolean(""); // false +Boolean(null); // false +Boolean(undefined); // false +Boolean(NaN); // false +Boolean(1); // true +Boolean("hello"); // true +Boolean([]); // true +Boolean({}); // true +``` + +### 隐式转换(自动转换) + +#### 字符串拼接 + +```javascript +"5" + 2; // "52" +"5" + true; // "5true" +"5" + null; // "5null" +"5" + undefined; // "5undefined" +``` + +#### 算术运算 + +```javascript +"5" - 2; // 3 +"5" * "2"; // 10 +"5" / "2"; // 2.5 +"abc" - 1; // NaN +``` + +#### 逻辑上下文 + +```javascript +if (0) { +} // false +if ("hello") { +} // true +if (null) { +} // false + +!!0; // false +!!"hello"; // true +``` + +#### 相等比较 + +```javascript +"5" == 5; // true +"0" == false; // true +null == undefined; // true +``` + +### 特殊转换规则 + +#### 对象转原始值 + +```javascript +// 对象转字符串 +String({}); // "[object Object]" +String([1, 2]); // "1,2" + +// 对象转数字 +Number({}); // NaN +Number([1]); // 1 +Number([]); // 0 +``` + +#### 布尔转换的 falsy 值 + +- `false` +- `0`、`-0`、`0n` +- `""`、`''`、` ` `` +- `null` +- `undefined` +- `NaN` + +所有其他值都为 truthy。 + +### 最佳实践 + +1. 使用 `===` 和 `!==` 代替 `==` 和 `!=` +2. 显式转换优于隐式转换 +3. 使用 `Number()`、`String()`、`Boolean()` 进行明确转换 + +## 实践与练习 + +```html + + + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/循环训练.png) + +## 电影院 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/电影院.png) + +## 第三章训练 + +```html + + + + + + Document + + + + + + + + + + + + +``` + +- 效果图 + +![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/训练三.png) diff --git "a/\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" "b/\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" new file mode 100644 index 000000000..665109335 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" @@ -0,0 +1,175 @@ +# JavaScript 基础语法详解 + +## 一、数据类型 + +### 基本类型(原始类型) + +1. **number** - 数字类型 + + - 整数:`42`、`-10` + - 浮点数:`3.14`、`0.5` + - 特殊值:`Infinity`、`-Infinity`、`NaN` + - 范围:±(2^53 - 1) + +2. **string** - 字符串类型 + + - 表示文本数据 + - 引号:`"双引号"`、`'单引号'`、`` `模板字符串` `` + - 转义字符:`\n`、`\t`、`\\` + +3. **boolean** - 布尔类型 + + - 只有两个值:`true`、`false` + - 用于逻辑判断 + +4. **undefined** - 未定义 + + - 变量声明但未赋值时的默认值 + - `let a;` → `a` 为 `undefined` + +5. **null** - 空值 + + - 表示空或不存在的对象引用 + - 需要显式赋值 + +6. **symbol** - 唯一值(ES6) + + - 创建唯一标识符:`Symbol('description')` + - 主要用于对象属性名 + +7. **bigint** - 大整数(ES2020) + - 表示任意精度的整数 + - 后缀 n:`123n`、`9007199254740991n` + +### 引用类型 + +1. **object** - 对象类型 + - 普通对象:`{ key: 'value' }` + - 数组:`[1, 2, 3]` + - 函数:`function() {}` + - 日期:`new Date()` + - 正则表达式:`/pattern/` + +## 二、变量与常量 + +### 声明方式 + +1. **var**(已淘汰) + + ```javascript + var name = "张三"; + ``` + + - 函数作用域 + - 存在变量提升 + - 可重复声明 + +2. **let**(推荐) + + ```javascript + let age = 25; + let score; // 可只声明不赋值 + ``` + + - 块级作用域(`{}` 内有效) + - 不存在变量提升 + - 不可重复声明 + - 可重新赋值 + +3. **const**(推荐) + ```javascript + const PI = 3.14159; + const user = { name: "李四" }; + ``` + - 块级作用域 + - 声明时必须赋值 + - 不可重新赋值(但对象属性可修改) + +### 命名规则 + +- 字母、数字、下划线、$ 组成 +- 不能以数字开头 +- 区分大小写 +- 不能使用保留字 + +## 编程训练 + +```html + +
+ +
+ +
+ +
+ +
+ +
+ +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/编程训练.png) + +## 实践与练习 + +```html + + + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/实践练习.png) -- Gitee From 1c2271b302257cfeef3c130edee593d2c448aa01 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 16 Nov 2025 23:45:37 +0800 Subject: [PATCH 2/9] feat:zuoye --- ...45\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename "\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" => "\344\270\245\345\201\245\345\256\207/20251112-js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" (100%) diff --git "a/\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" "b/\344\270\245\345\201\245\345\256\207/20251112-js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" similarity index 100% rename from "\344\270\245\345\201\245\345\256\207/js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" rename to "\344\270\245\345\201\245\345\256\207/20251112-js\347\232\204\346\225\260\346\215\256\347\261\273\345\236\213\357\274\214\345\270\270\351\207\217\345\222\214\345\217\230\351\207\217.md" -- Gitee From c9ff0305cf15d7632eff7e1498bb8897e67dd007 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 23 Nov 2025 12:28:03 +0800 Subject: [PATCH 3/9] feat:zuoye --- ...50\357\274\214\345\217\202\346\225\260.md" | 238 +++++++++ ...77\345\220\215\345\207\275\346\225\260.md" | 496 ++++++++++++++++++ ...ath,date,event\345\257\271\350\261\241.md" | 322 ++++++++++++ .../20251121-\346\225\260\347\273\204.md" | 208 ++++++++ 4 files changed, 1264 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251117-\345\207\275\346\225\260\347\232\204\345\256\232\344\271\211\357\274\214\350\260\203\347\224\250\357\274\214\345\217\202\346\225\260.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251119-js\345\207\275\346\225\260\347\232\204\345\265\214\345\245\227\350\260\203\347\224\250\357\274\214\351\200\222\345\275\222\345\207\275\346\225\260\357\274\214\345\206\205\347\275\256\345\207\275\346\225\260\345\214\277\345\220\215\345\207\275\346\225\260.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251120-math,date,event\345\257\271\350\261\241.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251121-\346\225\260\347\273\204.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251117-\345\207\275\346\225\260\347\232\204\345\256\232\344\271\211\357\274\214\350\260\203\347\224\250\357\274\214\345\217\202\346\225\260.md" "b/\344\270\245\345\201\245\345\256\207/20251117-\345\207\275\346\225\260\347\232\204\345\256\232\344\271\211\357\274\214\350\260\203\347\224\250\357\274\214\345\217\202\346\225\260.md" new file mode 100644 index 000000000..4161ff7b4 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251117-\345\207\275\346\225\260\347\232\204\345\256\232\344\271\211\357\274\214\350\260\203\347\224\250\357\274\214\345\217\202\346\225\260.md" @@ -0,0 +1,238 @@ +# JavaScript 函数笔记 + +## 1. 函数定义 + +### 1.1 函数声明 + +**说明:** 使用 function 关键字定义函数,存在函数提升 + +```javascript +function greet() { + console.log("Hello!"); +} +``` + +### 1.2 函数表达式 + +**说明:** 将函数赋值给变量,不存在函数提升 + +```javascript +const greet = function () { + console.log("Hello!"); +}; +``` + +### 1.3 箭头函数 + +**说明:** ES6 新语法,简洁的函数写法 + +```javascript +const greet = () => { + console.log("Hello!"); +}; +``` + +### 1.4 构造函数 + +**说明:** 使用 Function 构造函数创建函数(不推荐) + +```javascript +const greet = new Function('console.log("Hello!")'); +``` + +## 2. 函数调用 + +### 2.1 直接调用 + +**说明:** 使用函数名加括号调用 + +```javascript +function sayHello() { + console.log("Hello World!"); +} +sayHello(); // 输出: Hello World! +``` + +### 2.2 方法调用 + +**说明:** 作为对象的方法调用 + +```javascript +const person = { + name: "张三", + introduce: function () { + console.log("我叫" + this.name); + }, +}; +person.introduce(); // 输出: 我叫张三 +``` + +### 2.3 构造函数调用 + +**说明:** 使用 new 关键字调用构造函数 + +```javascript +function Person(name) { + this.name = name; +} +const person = new Person("李四"); +``` + +### 2.4 间接调用 + +**说明:** 使用 call、apply 方法调用 + +```javascript +function introduce(greeting) { + console.log(greeting + this.name); +} +const person = { name: "王五" }; +introduce.call(person, "你好,"); // 输出: 你好,王五 +``` + +## 3. 函数参数 + +### 3.1 形参和实参 + +**说明:** 形参是定义时的参数,实参是调用时传入的值 + +```javascript +function add(a, b) { + // a, b 是形参 + return a + b; +} +add(5, 3); // 5, 3 是实参 +``` + +### 3.2 默认参数 + +**说明:** ES6 支持为参数设置默认值 + +```javascript +function greet(name = "游客") { + console.log("你好," + name); +} +greet(); // 输出: 你好,游客 +greet("张三"); // 输出: 你好,张三 +``` + +### 3.3 剩余参数 + +**说明:** 使用 ... 语法接收多个参数为数组 + +```javascript +function sum(...numbers) { + return numbers.reduce((total, num) => total + num, 0); +} +sum(1, 2, 3, 4); // 返回: 10 +``` + +### 3.4 参数解构 + +**说明:** 直接解构对象或数组参数 + +```javascript +function printUser({ name, age }) { + console.log(`${name} 今年 ${age} 岁`); +} +printUser({ name: "张三", age: 25 }); // 输出: 张三 今年 25 岁 +``` + +### 3.5 arguments 对象 + +**说明:** 函数内置的类数组对象,包含所有参数 + +```javascript +function showArgs() { + console.log(arguments); +} +showArgs(1, 2, 3); // 输出: [1, 2, 3] +``` + +### 3.6 参数传递方式 + +**说明:** 基本类型按值传递,对象类型按引用传递 + +```javascript +// 基本类型(按值传递) +function changeValue(x) { + x = 10; +} +let num = 5; +changeValue(num); +console.log(num); // 输出: 5 + +// 对象类型(按引用传递) +function changeObj(obj) { + obj.name = "修改后"; +} +let person = { name: "原始" }; +changeObj(person); +console.log(person.name); // 输出: 修改后 +``` + +## 4. 返回值 + +### 4.1 return 语句 + +**说明:** 使用 return 返回函数结果,不写 return 返回 undefined + +```javascript +function multiply(a, b) { + return a * b; +} +const result = multiply(4, 5); // result = 20 + +function noReturn() { + // 没有 return 语句 +} +const value = noReturn(); // value = undefined +``` + +## 5. 综合示例 + +```javascript +// 函数定义 +function calculate(operation, ...numbers) { + switch (operation) { + case "add": + return numbers.reduce((sum, num) => sum + num, 0); + case "multiply": + return numbers.reduce((product, num) => product * num, 1); + default: + return 0; + } +} + +// 函数调用 +const sum = calculate("add", 1, 2, 3, 4); // 返回: 10 +const product = calculate("multiply", 2, 3, 4); // 返回: 24 +``` + +## 练习题 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/函数训练12.png) diff --git "a/\344\270\245\345\201\245\345\256\207/20251119-js\345\207\275\346\225\260\347\232\204\345\265\214\345\245\227\350\260\203\347\224\250\357\274\214\351\200\222\345\275\222\345\207\275\346\225\260\357\274\214\345\206\205\347\275\256\345\207\275\346\225\260\345\214\277\345\220\215\345\207\275\346\225\260.md" "b/\344\270\245\345\201\245\345\256\207/20251119-js\345\207\275\346\225\260\347\232\204\345\265\214\345\245\227\350\260\203\347\224\250\357\274\214\351\200\222\345\275\222\345\207\275\346\225\260\357\274\214\345\206\205\347\275\256\345\207\275\346\225\260\345\214\277\345\220\215\345\207\275\346\225\260.md" new file mode 100644 index 000000000..ecc236238 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251119-js\345\207\275\346\225\260\347\232\204\345\265\214\345\245\227\350\260\203\347\224\250\357\274\214\351\200\222\345\275\222\345\207\275\346\225\260\357\274\214\345\206\205\347\275\256\345\207\275\346\225\260\345\214\277\345\220\215\345\207\275\346\225\260.md" @@ -0,0 +1,496 @@ +# JavaScript 高级函数笔记 + +## 1. 函数嵌套调用 + +### 1.1 基本嵌套调用 + +**说明:** 在一个函数内部调用另一个函数 + +```javascript +function add(a, b) { + return a + b; +} + +function multiply(a, b) { + return a * b; +} + +function calculate(a, b) { + const sum = add(a, b); // 嵌套调用 add 函数 + const product = multiply(a, b); // 嵌套调用 multiply 函数 + return { sum, product }; +} + +console.log(calculate(3, 4)); // 输出: {sum: 7, product: 12} +``` + +### 1.2 链式嵌套 + +**说明:** 一个函数的返回值作为另一个函数的参数 + +```javascript +function double(x) { + return x * 2; +} + +function square(x) { + return x * x; +} + +const result = square(double(5)); // double(5)返回10,然后square(10)返回100 +console.log(result); // 输出: 100 +``` + +### 1.3 多层嵌套 + +**说明:** 多个函数层层嵌套调用 + +```javascript +function formatText(text) { + return text.trim(); +} + +function toUpperCase(text) { + return text.toUpperCase(); +} + +function addExclamation(text) { + return text + "!"; +} + +function processText(text) { + return addExclamation(toUpperCase(formatText(text))); +} + +console.log(processText(" hello ")); // 输出: "HELLO!" +``` + +## 2. 递归函数 + +### 2.1 基本递归 + +**说明:** 函数调用自身,必须有终止条件 + +```javascript +function factorial(n) { + if (n === 1) { + // 终止条件 + return 1; + } + return n * factorial(n - 1); // 递归调用 +} + +console.log(factorial(5)); // 输出: 120 (5*4*3*2*1) +``` + +### 2.2 斐波那契数列 + +**说明:** 经典的递归案例,每个数是前两个数之和 + +```javascript +function fibonacci(n) { + if (n <= 1) return n; // 终止条件 + return fibonacci(n - 1) + fibonacci(n - 2); // 递归调用 +} + +console.log(fibonacci(6)); // 输出: 8 (0,1,1,2,3,5,8) +``` + +### 2.3 递归遍历数组 + +**说明:** 使用递归处理数组元素 + +```javascript +function sumArray(arr, index = 0) { + if (index >= arr.length) return 0; // 终止条件 + return arr[index] + sumArray(arr, index + 1); // 递归调用 +} + +console.log(sumArray([1, 2, 3, 4, 5])); // 输出: 15 +``` + +### 2.4 递归注意事项 + +**说明:** 递归必须有基线条件,否则会栈溢出 + +```javascript +// 错误的递归:缺少终止条件 +function infiniteRecursion() { + return infiniteRecursion(); // 栈溢出! +} + +// 正确的递归:有明确的终止条件 +function countdown(n) { + if (n <= 0) { + console.log("结束!"); + return; + } + console.log(n); + countdown(n - 1); +} + +countdown(3); // 输出: 3, 2, 1, 结束! +``` + +## 3. JavaScript 内置函数 + +### 3.1 数学函数 + +**说明:** Math 对象提供的数学计算函数 + +```javascript +console.log(Math.abs(-5)); // 输出: 5 (绝对值) +console.log(Math.max(1, 5, 3)); // 输出: 5 (最大值) +console.log(Math.round(3.7)); // 输出: 4 (四舍五入) +console.log(Math.random()); // 输出: 0-1之间的随机数 +``` + +### 3.2 字符串函数 + +**说明:** 字符串处理相关函数 + +```javascript +const str = "Hello World"; +console.log(str.length); // 输出: 11 (字符串长度) +console.log(str.toUpperCase()); // 输出: "HELLO WORLD" (转大写) +console.log(str.indexOf("World")); // 输出: 6 (查找子串位置) +console.log(str.split(" ")); // 输出: ["Hello", "World"] (分割字符串) +``` + +### 3.3 数组函数 + +**说明:** 数组操作相关函数 + +```javascript +const arr = [1, 2, 3]; +console.log(arr.push(4)); // 输出: 4 (添加元素,返回新长度) +console.log(arr.pop()); // 输出: 4 (删除最后一个元素) +console.log(arr.map((x) => x * 2)); // 输出: [2, 4, 6] (映射新数组) +console.log(arr.filter((x) => x > 1)); // 输出: [2, 3] (过滤元素) +``` + +### 3.4 类型转换函数 + +**说明:** 数据类型转换函数 + +```javascript +console.log(Number("123")); // 输出: 123 (转数字) +console.log(String(123)); // 输出: "123" (转字符串) +console.log(Boolean(0)); // 输出: false (转布尔值) +console.log(parseInt("100px")); // 输出: 100 (解析整数) +``` + +### 3.5 时间函数 + +**说明:** 日期和时间相关函数 + +```javascript +const now = new Date(); +console.log(now.getFullYear()); // 输出: 当前年份 +console.log(now.getMonth() + 1); // 输出: 当前月份 (0-11) +console.log(now.getDate()); // 输出: 当前日期 +console.log(Date.now()); // 输出: 时间戳 +``` + +## 4. 匿名函数 + +### 4.1 函数表达式 + +**说明:** 没有函数名的函数,赋值给变量 + +```javascript +const greet = function (name) { + return "Hello, " + name; +}; +console.log(greet("Alice")); // 输出: "Hello, Alice" +``` + +### 4.2 立即执行函数 (IIFE) + +**说明:** 定义后立即执行的匿名函数 + +```javascript +(function () { + console.log("立即执行!"); +})(); // 输出: "立即执行!" + +const result = (function (a, b) { + return a + b; +})(5, 3); +console.log(result); // 输出: 8 +``` + +### 4.3 回调函数 + +**说明:** 作为参数传递给其他函数的匿名函数 + +```javascript +// setTimeout 回调 +setTimeout(function () { + console.log("3秒后执行"); +}, 3000); + +// 数组方法回调 +const numbers = [1, 2, 3, 4]; +const doubled = numbers.map(function (num) { + return num * 2; +}); +console.log(doubled); // 输出: [2, 4, 6, 8] +``` + +### 4.4 箭头函数作为匿名函数 + +**说明:** 使用箭头语法定义匿名函数 + +```javascript +// 箭头函数表达式 +const multiply = (a, b) => a * b; +console.log(multiply(4, 5)); // 输出: 20 + +// 箭头函数作为回调 +const numbers = [1, 2, 3]; +const squares = numbers.map((x) => x * x); +console.log(squares); // 输出: [1, 4, 9] + +// 立即执行的箭头函数 +(() => { + console.log("箭头函数立即执行!"); +})(); // 输出: "箭头函数立即执行!" +``` + +### 4.5 事件处理匿名函数 + +**说明:** 作为事件处理器的匿名函数 + +```javascript +// 假设有HTML按钮: +document.getElementById("myBtn").addEventListener("click", function () { + console.log("按钮被点击了!"); +}); + +// 箭头函数版本 +document.getElementById("myBtn").addEventListener("click", () => { + console.log("按钮被点击了!"); +}); +``` + +## 5. 综合示例 + +```javascript +// 综合使用:递归 + 嵌套 + 匿名函数 +function processData(data, callback) { + // 递归处理嵌套数据 + function traverse(obj) { + if (typeof obj === "object" && obj !== null) { + Object.keys(obj).forEach((key) => { + obj[key] = traverse(obj[key]); // 递归调用 + }); + return obj; + } + // 使用回调函数处理值 + return callback ? callback(obj) : obj; + } + + return traverse(data); +} + +// 使用匿名函数作为回调 +const result = processData( + { a: 1, b: { c: 2, d: 3 } }, + function (x) { + return x * 2; + } // 匿名回调函数 +); +console.log(result); // 输出: {a: 2, b: {c: 4, d: 6}} +``` + +## 训练 3~8 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/微信图片_20251123122432_261_54.png) + +## 综合练习 + +```css + +``` + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/屏幕录制 2025-11-23 122412.gif) + +## 斐波那契数列 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/微信图片_20251123122310_260_54.png) diff --git "a/\344\270\245\345\201\245\345\256\207/20251120-math,date,event\345\257\271\350\261\241.md" "b/\344\270\245\345\201\245\345\256\207/20251120-math,date,event\345\257\271\350\261\241.md" new file mode 100644 index 000000000..580136482 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251120-math,date,event\345\257\271\350\261\241.md" @@ -0,0 +1,322 @@ +# JavaScript 内置对象用法总结 + +## 1. Math 对象 + +### 1.1 数学常数 + +```javascript +Math.PI; // 圆周率 π ≈ 3.14159 +Math.E; // 自然常数 e ≈ 2.718 +Math.SQRT2; // 2的平方根 ≈ 1.414 +``` + +### 1.2 取整方法 + +```javascript +Math.round(4.7); // 5 - 四舍五入 +Math.floor(4.7); // 4 - 向下取整 +Math.ceil(4.3); // 5 - 向上取整 +Math.trunc(4.7); // 4 - 去除小数部分 +``` + +### 1.3 随机数生成 + +```javascript +Math.random(); // 0-1之间的随机数 +Math.floor(Math.random() * 100); // 0-99的随机整数 +``` + +### 1.4 最大值最小值 + +```javascript +Math.max(1, 5, 3); // 5 - 返回最大值 +Math.min(1, 5, 3); // 1 - 返回最小值 +``` + +### 1.5 幂和平方根 + +```javascript +Math.pow(2, 3); // 8 - 2的3次方 +Math.sqrt(16); // 4 - 平方根 +Math.cbrt(8); // 2 - 立方根 +``` + +### 1.6 三角函数 + +```javascript +Math.sin(Math.PI / 2); // 1 - 正弦函数 +Math.cos(Math.PI); // -1 - 余弦函数 +Math.tan(Math.PI / 4); // 1 - 正切函数 +``` + +## 2. Date 对象 + +### 2.1 创建日期对象 + +```javascript +new Date(); // 当前时间 +new Date("2024-01-15"); // 指定日期字符串 +new Date(2024, 0, 15); // 指定年月日(月份0-11) +``` + +### 2.2 获取日期时间 + +```javascript +const now = new Date(); +now.getFullYear(); // 2024 - 年份 +now.getMonth(); // 0 - 月份(0-11) +now.getDate(); // 15 - 日期(1-31) +now.getDay(); // 1 - 星期(0-6) +now.getHours(); // 10 - 小时(0-23) +now.getMinutes(); // 30 - 分钟(0-59) +``` + +### 2.3 设置日期时间 + +```javascript +const date = new Date(); +date.setFullYear(2025); // 设置年份 +date.setMonth(5); // 设置月份(0-11) +date.setDate(20); // 设置日期 +date.setHours(15, 30, 0); // 设置小时、分钟、秒 +``` + +### 2.4 日期格式化 + +```javascript +const now = new Date(); +now.toString(); // "Mon Jan 15 2024 10:30:25 GMT+0800" +now.toDateString(); // "Mon Jan 15 2024" +now.toTimeString(); // "10:30:25 GMT+0800" +now.toLocaleString(); // "2024/1/15 10:30:25" +``` + +### 2.5 时间戳 + +```javascript +const now = new Date(); +now.getTime(); // 1705309825123 - 毫秒时间戳 +Date.now(); // 1705309825123 - 当前时间戳 +``` + +### 2.6 日期计算 + +```javascript +const date1 = new Date("2024-01-01"); +const date2 = new Date("2024-01-15"); +const diff = date2 - date1; // 1209600000 - 毫秒差 +const days = diff / (1000 * 60 * 60 * 24); // 14 - 天数差 +``` + +## 3. Event 对象 + +### 3.1 事件监听 + +```javascript +// 添加事件监听 +element.addEventListener("click", function (event) { + console.log("元素被点击了"); +}); + +// 移除事件监听 +function handleClick(event) { + console.log("点击事件"); +} +element.removeEventListener("click", handleClick); +``` + +### 3.2 事件对象属性 + +```javascript +element.addEventListener("click", function (e) { + e.target; // 触发事件的元素 + e.currentTarget; // 绑定事件的元素 + e.type; // "click" - 事件类型 + e.clientX; // 50 - 鼠标X坐标 + e.clientY; // 100 - 鼠标Y坐标 + e.key; // "Enter" - 按键名称 +}); +``` + +### 3.3 阻止默认行为 + +```javascript +// 阻止链接跳转 +link.addEventListener("click", function (e) { + e.preventDefault(); + console.log("阻止了默认跳转行为"); +}); + +// 阻止表单提交 +form.addEventListener("submit", function (e) { + e.preventDefault(); + console.log("阻止了表单提交"); +}); +``` + +### 3.4 阻止事件冒泡 + +```javascript +child.addEventListener("click", function (e) { + e.stopPropagation(); + console.log("子元素点击,阻止冒泡到父元素"); +}); + +parent.addEventListener("click", function () { + console.log("父元素点击"); // 不会执行 +}); +``` + +### 3.5 鼠标事件 + +```javascript +element.addEventListener("click", function (e) { + console.log("单击事件"); +}); + +element.addEventListener("dblclick", function (e) { + console.log("双击事件"); +}); + +element.addEventListener("mouseover", function (e) { + console.log("鼠标移入"); +}); + +element.addEventListener("mouseout", function (e) { + console.log("鼠标移出"); +}); +``` + +### 3.6 键盘事件 + +```javascript +document.addEventListener("keydown", function (e) { + console.log(`按下按键: ${e.key}, 键码: ${e.keyCode}`); +}); + +document.addEventListener("keyup", function (e) { + console.log(`释放按键: ${e.key}`); +}); +``` + +### 3.7 表单事件 + +```javascript +input.addEventListener("focus", function (e) { + console.log("输入框获得焦点"); +}); + +input.addEventListener("blur", function (e) { + console.log("输入框失去焦点"); +}); + +input.addEventListener("input", function (e) { + console.log("输入内容:", e.target.value); +}); + +input.addEventListener("change", function (e) { + console.log("内容改变:", e.target.value); +}); +``` + +### 3.8 事件委托 + +```javascript +// 使用事件委托处理动态元素 +list.addEventListener("click", function (e) { + if (e.target.tagName === "LI") { + console.log("点击了列表项:", e.target.textContent); + } +}); +``` + +## 训练 1~3 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/微信图片_20251123122538_262_54.png) + +## 综合练习 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/微信图片_20251123122603_263_54.png) diff --git "a/\344\270\245\345\201\245\345\256\207/20251121-\346\225\260\347\273\204.md" "b/\344\270\245\345\201\245\345\256\207/20251121-\346\225\260\347\273\204.md" new file mode 100644 index 000000000..3d3e1545a --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251121-\346\225\260\347\273\204.md" @@ -0,0 +1,208 @@ +# JavaScript 数组用法总结 + +## 1. 创建数组 + +### 1.1 字面量创建 +```javascript +const arr = [1, 2, 3, 4, 5] +``` + +### 1.2 构造函数创建 +```javascript +const arr = new Array(1, 2, 3) +``` + +### 1.3 创建空数组 +```javascript +const empty = [] +const withSize = new Array(5) // 创建长度为5的空数组 +``` + +## 2. 访问和修改元素 + +### 2.1 访问元素 +```javascript +const arr = ['a', 'b', 'c'] +console.log(arr[0]) // 'a' - 访问第一个元素 +``` + +### 2.2 修改元素 +```javascript +arr[1] = 'x' // ['a', 'x', 'c'] +``` + +### 2.3 数组长度 +```javascript +console.log(arr.length) // 3 +``` + +## 3. 添加和删除元素 + +### 3.1 末尾添加(push) +```javascript +arr.push('d') // ['a', 'b', 'c', 'd'] +``` + +### 3.2 末尾删除(pop) +```javascript +arr.pop() // ['a', 'b'] - 返回删除的元素 +``` + +### 3.3 开头添加(unshift) +```javascript +arr.unshift('z') // ['z', 'a', 'b', 'c'] +``` + +### 3.4 开头删除(shift) +```javascript +arr.shift() // ['a', 'b', 'c'] - 返回删除的元素 +``` + +## 4. 数组遍历 + +### 4.1 for循环 +```javascript +for (let i = 0; i < arr.length; i++) { + console.log(arr[i]) +} +``` + +### 4.2 forEach方法 +```javascript +arr.forEach(item => console.log(item)) +``` + +### 4.3 for...of循环 +```javascript +for (const item of arr) { + console.log(item) +} +``` + +## 5. 数组转换方法 + +### 5.1 map - 映射新数组 +```javascript +const doubled = [1, 2, 3].map(x => x * 2) // [2, 4, 6] +``` + +### 5.2 filter - 过滤元素 +```javascript +const evens = [1, 2, 3, 4].filter(x => x % 2 === 0) // [2, 4] +``` + +### 5.3 reduce - 累计计算 +```javascript +const sum = [1, 2, 3].reduce((acc, cur) => acc + cur, 0) // 6 +``` + +## 6. 查找和判断 + +### 6.1 find - 查找元素 +```javascript +const found = [1, 2, 3].find(x => x > 1) // 2 +``` + +### 6.2 includes - 包含检查 +```javascript +const hasTwo = [1, 2, 3].includes(2) // true +``` + +### 6.3 indexOf - 查找索引 +```javascript +const index = [1, 2, 3].indexOf(2) // 1 +``` + +## 7. 数组操作 + +### 7.1 slice - 切片 +```javascript +const arr = [1, 2, 3, 4, 5] +const part = arr.slice(1, 3) // [2, 3] - 不改变原数组 +``` + +### 7.2 splice - 删除/添加 +```javascript +arr.splice(1, 2, 'a', 'b') // 从索引1删除2个元素,添加'a','b' +``` + +### 7.3 concat - 合并数组 +```javascript +const newArr = [1, 2].concat([3, 4]) // [1, 2, 3, 4] +``` + +## 8. 排序和反转 + +### 8.1 sort - 排序 +```javascript +const sorted = [3, 1, 2].sort() // [1, 2, 3] +``` + +### 8.2 reverse - 反转 +```javascript +const reversed = [1, 2, 3].reverse() // [3, 2, 1] +``` + +## 9. 数组判断 + +### 9.1 Array.isArray +```javascript +Array.isArray([1, 2, 3]) // true +Array.isArray('hello') // false +``` + +### 9.2 every - 所有元素满足条件 +```javascript +const allPositive = [1, 2, 3].every(x => x > 0) // true +``` + +### 9.3 some - 至少一个元素满足条件 +```javascript +const hasNegative = [1, -2, 3].some(x => x < 0) // true +``` + +## 10. 字符串转换 + +### 10.1 join - 数组转字符串 +```javascript +const str = ['a', 'b', 'c'].join('-') // 'a-b-c' +``` + +### 10.2 split - 字符串转数组 +```javascript +const arr = 'a,b,c'.split(',') // ['a', 'b', 'c'] +``` + +## 11. 其他实用方法 + +### 11.1 fill - 填充数组 +```javascript +const filled = new Array(3).fill(0) // [0, 0, 0] +``` + +### 11.2 flat - 数组扁平化 +```javascript +const flattened = [1, [2, 3]].flat() // [1, 2, 3] +``` + +### 11.3 findIndex - 查找索引 +```javascript +const index = [1, 2, 3].findIndex(x => x > 1) // 1 +``` + +## 12. 数组解构 + +### 12.1 基本解构 +```javascript +const [first, second] = [1, 2, 3] // first=1, second=2 +``` + +### 12.2 跳过元素 +```javascript +const [first, , third] = [1, 2, 3] // first=1, third=3 +``` + +### 12.3 剩余元素 +```javascript +const [first, ...rest] = [1, 2, 3, 4] // first=1, rest=[2,3,4] +``` \ No newline at end of file -- Gitee From 691edc92a0a47b68b65f76c0034bae03254314a3 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 30 Nov 2025 19:15:34 +0800 Subject: [PATCH 4/9] feat:zuoye --- ...0251124-String\345\257\271\350\261\241.md" | 367 +++++++++++++ ...14\350\277\255\344\273\243\345\231\250.md" | 182 +++++++ ...31\350\241\250\350\276\276\345\274\217.md" | 325 +++++++++++ ...13\345\272\217\350\260\203\350\257\225.md" | 495 +++++++++++++++++ ...13\344\273\266\345\244\204\347\220\206.md" | 504 ++++++++++++++++++ 5 files changed, 1873 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251124-String\345\257\271\350\261\241.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251124-\346\225\260\347\273\204\357\274\214\351\233\206\345\220\210\357\274\214\350\277\255\344\273\243\345\231\250.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251127-\345\274\202\345\270\270\345\244\204\347\220\206\344\270\216\347\250\213\345\272\217\350\260\203\350\257\225.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251124-String\345\257\271\350\261\241.md" "b/\344\270\245\345\201\245\345\256\207/20251124-String\345\257\271\350\261\241.md" new file mode 100644 index 000000000..febdaf3cf --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251124-String\345\257\271\350\261\241.md" @@ -0,0 +1,367 @@ +# JavaScript String 对象总结 + +## 字符串创建 + +### 字面量创建 + +```javascript +const str1 = "Hello World"; +const str2 = "Hello World"; +const str3 = `Hello World`; +``` + +### 构造函数创建 + +```javascript +const str = new String("Hello World"); +``` + +## 字符串属性 + +### length - 字符串长度 + +```javascript +const str = "Hello"; +console.log(str.length); // 5 +``` + +## 字符串访问方法 + +### charAt() - 获取指定位置字符 + +```javascript +const str = "Hello"; +console.log(str.charAt(1)); // 'e' +``` + +### charCodeAt() - 获取字符编码 + +```javascript +const str = "Hello"; +console.log(str.charCodeAt(1)); // 101 +``` + +### 方括号索引 + +```javascript +const str = "Hello"; +console.log(str[1]); // 'e' +``` + +## 字符串查找方法 + +### indexOf() - 查找子串位置 + +```javascript +const str = "Hello World"; +console.log(str.indexOf("World")); // 6 +``` + +### lastIndexOf() - 从后往前查找 + +```javascript +const str = "Hello World World"; +console.log(str.lastIndexOf("World")); // 12 +``` + +### includes() - 是否包含子串 + +```javascript +const str = "Hello World"; +console.log(str.includes("World")); // true +``` + +### startsWith() - 是否以指定字符串开头 + +```javascript +const str = "Hello World"; +console.log(str.startsWith("Hello")); // true +``` + +### endsWith() - 是否以指定字符串结尾 + +```javascript +const str = "Hello World"; +console.log(str.endsWith("World")); // true +``` + +## 字符串截取方法 + +### slice() - 截取子串 + +```javascript +const str = "Hello World"; +console.log(str.slice(0, 5)); // 'Hello' +console.log(str.slice(-5)); // 'World' +``` + +### substring() - 截取子串 + +```javascript +const str = "Hello World"; +console.log(str.substring(0, 5)); // 'Hello' +``` + +### substr() - 从指定位置截取指定长度 + +```javascript +const str = "Hello World"; +console.log(str.substr(6, 5)); // 'World' +``` + +## 字符串修改方法 + +### toUpperCase() - 转为大写 + +```javascript +const str = "Hello"; +console.log(str.toUpperCase()); // 'HELLO' +``` + +### toLowerCase() - 转为小写 + +```javascript +const str = "HELLO"; +console.log(str.toLowerCase()); // 'hello' +``` + +### replace() - 替换字符串 + +```javascript +const str = "Hello World"; +console.log(str.replace("World", "JavaScript")); // 'Hello JavaScript' +``` + +### replaceAll() - 替换所有匹配项 + +```javascript +const str = "apple banana apple"; +console.log(str.replaceAll("apple", "orange")); // 'orange banana orange' +``` + +### trim() - 去除两端空格 + +```javascript +const str = " Hello World "; +console.log(str.trim()); // 'Hello World' +``` + +### trimStart() / trimEnd() - 去除首尾空格 + +```javascript +const str = " Hello World "; +console.log(str.trimStart()); // 'Hello World ' +console.log(str.trimEnd()); // ' Hello World' +``` + +## 字符串分割和连接 + +### split() - 分割字符串 + +```javascript +const str = "apple,banana,orange"; +console.log(str.split(",")); // ['apple', 'banana', 'orange'] +``` + +### concat() - 连接字符串 + +```javascript +const str1 = "Hello"; +const str2 = "World"; +console.log(str1.concat(" ", str2)); // 'Hello World' +``` + +## 字符串比较 + +### localeCompare() - 本地化比较 + +```javascript +const str1 = "apple"; +const str2 = "banana"; +console.log(str1.localeCompare(str2)); // -1 (表示str1在str2之前) +``` + +## 字符串重复和填充 + +### repeat() - 重复字符串 + +```javascript +const str = "Hello"; +console.log(str.repeat(3)); // 'HelloHelloHello' +``` + +### padStart() - 头部填充 + +```javascript +const str = "5"; +console.log(str.padStart(3, "0")); // '005' +``` + +### padEnd() - 尾部填充 + +```javascript +const str = "5"; +console.log(str.padEnd(3, "0")); // '500' +``` + +## 模板字符串 + +### 基本用法 + +```javascript +const name = "John"; +const age = 30; +console.log(`My name is ${name} and I'm ${age} years old.`); +// 'My name is John and I'm 30 years old.' +``` + +### 多行字符串 + +```javascript +const multiLine = ` + This is + a multi-line + string +`; +``` + +### 标签模板 + +```javascript +function highlight(strings, ...values) { + return strings.reduce( + (result, str, i) => `${result}${str}${values[i] || ""}`, + "" + ); +} + +const name = "John"; +const age = 30; +console.log(highlight`Hello ${name}, you are ${age} years old.`); +``` + +## 原始字符串 + +### String.raw - 原始字符串 + +```javascript +const path = String.raw`C:\Development\profile\aboutme.html`; +console.log(path); // 'C:\Development\profile\aboutme.html' +``` + +## 字符串迭代 + +### for...of 循环 + +```javascript +const str = "Hello"; +for (const char of str) { + console.log(char); // H, e, l, l, o +} +``` + +### 扩展运算符 + +```javascript +const str = "Hello"; +console.log([...str]); // ['H', 'e', 'l', 'l', 'o'] +``` + +## 训练 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第七章训练.png) + +## 综合 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第七章综合.gif) diff --git "a/\344\270\245\345\201\245\345\256\207/20251124-\346\225\260\347\273\204\357\274\214\351\233\206\345\220\210\357\274\214\350\277\255\344\273\243\345\231\250.md" "b/\344\270\245\345\201\245\345\256\207/20251124-\346\225\260\347\273\204\357\274\214\351\233\206\345\220\210\357\274\214\350\277\255\344\273\243\345\231\250.md" new file mode 100644 index 000000000..06b4a6706 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251124-\346\225\260\347\273\204\357\274\214\351\233\206\345\220\210\357\274\214\350\277\255\344\273\243\345\231\250.md" @@ -0,0 +1,182 @@ +# JavaScript 中数组、Map、Set 和迭代器总结 + +## 数组 (Array) + +### 基本迭代方法 + +```javascript +const arr = [1, 2, 3]; + +// forEach - 遍历每个元素 +arr.forEach((item) => console.log(item)); + +// map - 映射新数组 +const doubled = arr.map((item) => item * 2); // [2, 4, 6] + +// filter - 过滤元素 +const filtered = arr.filter((item) => item > 1); // [2, 3] + +// reduce - 累积计算 +const sum = arr.reduce((acc, cur) => acc + cur, 0); // 6 +``` + +## Map 集合 + +### 基本操作和迭代 + +```javascript +const map = new Map(); +map.set("name", "John"); +map.set("age", 30); + +// 遍历键值对 +for (let [key, value] of map) { + console.log(key, value); +} + +// 获取所有键 +for (let key of map.keys()) { + console.log(key); // 'name', 'age' +} + +// 获取所有值 +for (let value of map.values()) { + console.log(value); // 'John', 30 +} +``` + +## Set 集合 + +### 基本操作和迭代 + +```javascript +const set = new Set([1, 2, 3, 3, 4]); + +// 添加元素 +set.add(5); + +// 遍历集合 +set.forEach((value) => console.log(value)); + +// 使用 for...of 迭代 +for (let item of set) { + console.log(item); // 1, 2, 3, 4, 5 +} + +// 转换为数组 +const arrayFromSet = [...set]; // [1, 2, 3, 4, 5] +``` + +## 迭代器 (Iterator) + +### 自定义迭代器 + +```javascript +const myIterable = { + [Symbol.iterator]: function* () { + yield 1; + yield 2; + yield 3; + }, +}; + +for (let value of myIterable) { + console.log(value); // 1, 2, 3 +} +``` + +### 内置迭代器使用 + +```javascript +const arr = ["a", "b", "c"]; + +// 获取数组迭代器 +const iterator = arr[Symbol.iterator](); + +console.log(iterator.next()); // {value: 'a', done: false} +console.log(iterator.next()); // {value: 'b', done: false} +console.log(iterator.next()); // {value: 'c', done: false} +console.log(iterator.next()); // {value: undefined, done: true} +``` + +### 生成器函数 + +```javascript +function* numberGenerator() { + let num = 1; + while (num <= 3) { + yield num++; + } +} + +const gen = numberGenerator(); +console.log(gen.next().value); // 1 +console.log(gen.next().value); // 2 +console.log(gen.next().value); // 3 +``` + +## 训练 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第六章训练.png) + +## 综合 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第六章综合.png) diff --git "a/\344\270\245\345\201\245\345\256\207/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/\344\270\245\345\201\245\345\256\207/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 000000000..519ce3f7c --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,325 @@ +# JavaScript 正则表达式总结 + +## 正则表达式创建 + +### 字面量创建 + +```javascript +const regex = /pattern/flags; +const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +``` + +### 构造函数创建 + +```javascript +const regex = new RegExp("pattern", "flags"); +const emailRegex = new RegExp("^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$"); +``` + +## 正则表达式标志 + +### 常用标志 + +```javascript +// g - 全局匹配 +const regex1 = /a/g; + +// i - 忽略大小写 +const regex2 = /hello/i; + +// m - 多行匹配 +const regex3 = /^start/m; + +// s - dotAll 模式(点号匹配换行) +const regex4 = /a.b/s; + +// u - Unicode 模式 +const regex5 = /\u{1F600}/u; +``` + +## 正则表达式方法 + +### test() - 测试是否匹配 + +```javascript +const regex = /hello/i; +console.log(regex.test("Hello World")); // true +``` + +### exec() - 执行匹配搜索 + +```javascript +const regex = /hello/i; +const result = regex.exec("Hello World"); +console.log(result[0]); // 'Hello' +``` + +## 字符串的正则方法 + +### match() - 匹配字符串 + +```javascript +const str = "Hello World"; +const result = str.match(/hello/i); +console.log(result[0]); // 'Hello' +``` + +### matchAll() - 匹配所有结果 + +```javascript +const str = "test1 test2 test3"; +const matches = str.matchAll(/test(\d)/g); +for (const match of matches) { + console.log(match[1]); // '1', '2', '3' +} +``` + +### replace() - 替换匹配内容 + +```javascript +const str = "Hello World"; +const newStr = str.replace(/world/i, "JavaScript"); +console.log(newStr); // 'Hello JavaScript' +``` + +### search() - 搜索匹配位置 + +```javascript +const str = "Hello World"; +const position = str.search(/world/i); +console.log(position); // 6 +``` + +### split() - 按正则分割 + +```javascript +const str = "apple,banana;orange"; +const arr = str.split(/[,;]/); +console.log(arr); // ['apple', 'banana', 'orange'] +``` + +## 字符类 + +### 基本字符类 + +```javascript +// \d - 数字 +const digitRegex = /\d/; +console.log(digitRegex.test("123")); // true + +// \w - 单词字符 +const wordRegex = /\w/; +console.log(wordRegex.test("hello")); // true + +// \s - 空白字符 +const spaceRegex = /\s/; +console.log(spaceRegex.test(" ")); // true +``` + +### 否定字符类 + +```javascript +// \D - 非数字 +const nonDigitRegex = /\D/; +console.log(nonDigitRegex.test("abc")); // true + +// \W - 非单词字符 +const nonWordRegex = /\W/; +console.log(nonWordRegex.test("!")); // true + +// \S - 非空白字符 +const nonSpaceRegex = /\S/; +console.log(nonSpaceRegex.test("a")); // true +``` + +### 自定义字符类 + +```javascript +// [abc] - 匹配 a、b 或 c +const customClass = /[abc]/; +console.log(customClass.test("apple")); // true + +// [^abc] - 匹配非 a、b、c 的字符 +const negatedClass = /[^abc]/; +console.log(negatedClass.test("dog")); // true + +// [a-z] - 字符范围 +const rangeClass = /[a-z]/; +console.log(rangeClass.test("hello")); // true +``` + +## 量词 + +### 基本量词 + +```javascript +// * - 0次或多次 +const zeroOrMore = /a*/; +console.log(zeroOrMore.test("")); // true + +// + - 1次或多次 +const oneOrMore = /a+/; +console.log(oneOrMore.test("aaa")); // true + +// ? - 0次或1次 +const zeroOrOne = /a?/; +console.log(zeroOrOne.test("")); // true + +// {n} - 恰好n次 +const exact = /a{3}/; +console.log(exact.test("aaa")); // true + +// {n,} - 至少n次 +const atLeast = /a{2,}/; +console.log(atLeast.test("aaa")); // true + +// {n,m} - n到m次 +const range = /a{2,4}/; +console.log(range.test("aaa")); // true +``` + +## 位置匹配 + +### 锚点字符 + +```javascript +// ^ - 字符串开始 +const start = /^hello/; +console.log(start.test("hello world")); // true + +// $ - 字符串结束 +const end = /world$/; +console.log(end.test("hello world")); // true + +// \b - 单词边界 +const wordBoundary = /\bhello\b/; +console.log(wordBoundary.test("hello world")); // true + +// \B - 非单词边界 +const nonWordBoundary = /\Bhell\B/; +console.log(nonWordBoundary.test("hello")); // true +``` + +## 分组和捕获 + +### 捕获分组 + +```javascript +const regex = /(\d{4})-(\d{2})-(\d{2})/; +const match = regex.exec("2024-01-15"); +console.log(match[1]); // '2024' - 年 +console.log(match[2]); // '01' - 月 +console.log(match[3]); // '15' - 日 +``` + +### 非捕获分组 + +```javascript +const regex = /(?:\d{4})-\d{2}-\d{2}/; +const match = regex.exec("2024-01-15"); +console.log(match[1]); // undefined (非捕获分组) +``` + +### 命名捕获组 + +```javascript +const regex = /(?\d{4})-(?\d{2})-(?\d{2})/; +const match = regex.exec("2024-01-15"); +console.log(match.groups.year); // '2024' +console.log(match.groups.month); // '01' +``` + +## 断言 + +### 前瞻断言 + +```javascript +// 正向前瞻 - 后面跟着特定模式 +const positiveLookahead = /hello(?= world)/; +console.log(positiveLookahead.test("hello world")); // true + +// 负向前瞻 - 后面不跟着特定模式 +const negativeLookahead = /hello(?! world)/; +console.log(negativeLookahead.test("hello javascript")); // true +``` + +### 后瞻断言 + +```javascript +// 正向后瞻 - 前面是特定模式 +const positiveLookbehind = /(?<=say )hello/; +console.log(positiveLookbehind.test("say hello")); // true + +// 负向后瞻 - 前面不是特定模式 +const negativeLookbehind = /(? response.json()) + .then((data) => console.log(data)) + .catch((error) => console.error("请求失败:", error)); +``` + +### async/await 错误处理 + +```javascript +async function fetchData() { + try { + const response = await fetch("/api/data"); + const data = await response.json(); + return data; + } catch (error) { + console.error("获取数据失败:", error); + throw error; // 重新抛出错误 + } +} + +// 调用async函数 +fetchData().catch((error) => { + console.log("外部错误处理:", error); +}); +``` + +### Promise.all 错误处理 + +```javascript +const promises = [ + fetch("/api/users"), + fetch("/api/posts"), + fetch("/api/comments"), +]; + +Promise.all(promises.map((p) => p.catch((e) => e))).then((results) => { + results.forEach((result, index) => { + if (result instanceof Error) { + console.log(`请求 ${index} 失败:`, result.message); + } else { + console.log(`请求 ${index} 成功`); + } + }); +}); +``` + +## 全局错误处理 + +### window.onerror + +```javascript +window.onerror = function (message, source, lineno, colno, error) { + console.log("全局错误:", message); + console.log("错误文件:", source); + console.log("错误位置:", lineno, ":", colno); + return true; // 阻止浏览器默认错误处理 +}; +``` + +### unhandledrejection 事件 + +```javascript +window.addEventListener("unhandledrejection", function (event) { + console.log("未处理的Promise拒绝:", event.reason); + event.preventDefault(); // 阻止浏览器默认错误提示 +}); +``` + +## 性能调试 + +### 性能测量 + +```javascript +// 使用 performance API +performance.mark("start"); + +// 执行需要测量的代码 +for (let i = 0; i < 1000000; i++) {} + +performance.mark("end"); +performance.measure("循环执行时间", "start", "end"); + +const measure = performance.getEntriesByName("循环执行时间")[0]; +console.log(`执行时间: ${measure.duration}ms`); +``` + +### 内存使用检查 + +```javascript +// 检查内存使用情况 +const memory = performance.memory; +console.log("已使用内存:", memory.usedJSHeapSize); +console.log("内存限制:", memory.jsHeapSizeLimit); +console.log("总堆大小:", memory.totalJSHeapSize); +``` + +## 最佳实践 + +### 具体的错误信息 + +```javascript +// 不好的做法 +throw new Error("操作失败"); + +// 好的做法 +throw new Error("用户注册失败: 邮箱已被使用"); +``` + +### 适当的错误层级 + +```javascript +function processUserData(userData) { + try { + validateUserData(userData); + saveToDatabase(userData); + } catch (error) { + if (error instanceof ValidationError) { + // 处理验证错误 + showUserError(error.message); + } else { + // 处理系统错误 + logSystemError(error); + showGenericError(); + } + } +} +``` + +### 错误日志记录 + +```javascript +function logError(error, context = {}) { + const errorLog = { + timestamp: new Date().toISOString(), + message: error.message, + stack: error.stack, + type: error.name, + context: context, + }; + + // 发送到错误监控服务 + sendToErrorService(errorLog); + + // 开发环境下在控制台显示 + if (process.env.NODE_ENV === "development") { + console.error("错误详情:", errorLog); + } +} +``` + +## 训练 + +```html + +``` + +- 效果图 + +![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第九章训练.gif) + +## 综合 + +```html + +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第九章综合.gif) diff --git "a/\344\270\245\345\201\245\345\256\207/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\344\270\245\345\201\245\345\256\207/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 000000000..7d4094b43 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,504 @@ +# JavaScript 时间处理总结 + +## Date 对象创建 + +### 当前时间 + +```javascript +const now = new Date(); +console.log(now); // 当前日期时间 +``` + +### 指定时间创建 + +```javascript +// 指定日期时间 +const date1 = new Date("2024-01-15"); +const date2 = new Date("2024-01-15T10:30:00"); +const date3 = new Date(2024, 0, 15); // 月份从0开始 +const date4 = new Date(2024, 0, 15, 10, 30, 0); +``` + +### 时间戳创建 + +```javascript +// 从时间戳创建 +const timestamp = 1705296600000; +const dateFromTimestamp = new Date(timestamp); + +// 当前时间戳 +const currentTimestamp = Date.now(); +console.log(currentTimestamp); // 毫秒时间戳 +``` + +## 时间获取方法 + +### 获取日期组件 + +```javascript +const date = new Date("2024-01-15T10:30:45"); + +console.log(date.getFullYear()); // 2024 +console.log(date.getMonth()); // 0 (0-11) +console.log(date.getDate()); // 15 +console.log(date.getDay()); // 1 (星期几,0-6) +console.log(date.getHours()); // 10 +console.log(date.getMinutes()); // 30 +console.log(date.getSeconds()); // 45 +console.log(date.getMilliseconds()); // 0 +``` + +### UTC 时间获取 + +```javascript +const date = new Date("2024-01-15T10:30:45Z"); + +console.log(date.getUTCFullYear()); // 2024 +console.log(date.getUTCHours()); // 10 (UTC时间) +``` + +## 时间设置方法 + +### 设置日期时间 + +```javascript +const date = new Date(); + +date.setFullYear(2024); +date.setMonth(0); // 一月 +date.setDate(15); +date.setHours(10); +date.setMinutes(30); +date.setSeconds(45); + +console.log(date); // 2024-01-15T10:30:45 +``` + +### 时间运算 + +```javascript +const date = new Date("2024-01-15"); + +// 增加天数 +date.setDate(date.getDate() + 7); +console.log(date); // 2024-01-22 + +// 减少月份 +date.setMonth(date.getMonth() - 1); +console.log(date); // 2023-12-22 +``` + +## 时间格式化 + +### 转字符串方法 + +```javascript +const date = new Date("2024-01-15T10:30:45"); + +console.log(date.toString()); // "Mon Jan 15 2024 10:30:45 GMT+0800" +console.log(date.toDateString()); // "Mon Jan 15 2024" +console.log(date.toTimeString()); // "10:30:45 GMT+0800" +console.log(date.toISOString()); // "2024-01-15T02:30:45.000Z" +console.log(date.toLocaleDateString()); // "2024/1/15" (根据地区) +console.log(date.toLocaleTimeString()); // "上午10:30:45" (根据地区) +``` + +### 自定义格式化 + +```javascript +function formatDate(date) { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; +} + +console.log(formatDate(new Date())); // "2024-01-15" +``` + +## 时间比较 + +### 直接比较 + +```javascript +const date1 = new Date("2024-01-15"); +const date2 = new Date("2024-01-20"); + +console.log(date1 < date2); // true +console.log(date1 > date2); // false +console.log(date1.getTime() === date2.getTime()); // 比较时间戳 +``` + +### 时间差计算 + +```javascript +const start = new Date("2024-01-15T10:00:00"); +const end = new Date("2024-01-15T11:30:00"); + +const diffMs = end - start; // 毫秒差 +const diffMinutes = Math.floor(diffMs / (1000 * 60)); +const diffHours = diffMs / (1000 * 60 * 60); + +console.log(`相差 ${diffMinutes} 分钟`); // 相差 90 分钟 +console.log(`相差 ${diffHours} 小时`); // 相差 1.5 小时 +``` + +## 相对时间 + +### 相对时间格式化 + +```javascript +function formatRelativeTime(date) { + const now = new Date(); + const diffMs = now - date; + const diffMinutes = Math.floor(diffMs / (1000 * 60)); + const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffMinutes < 1) return "刚刚"; + if (diffMinutes < 60) return `${diffMinutes}分钟前`; + if (diffHours < 24) return `${diffHours}小时前`; + if (diffDays < 7) return `${diffDays}天前`; + + return date.toLocaleDateString(); +} + +console.log(formatRelativeTime(new Date(Date.now() - 300000))); // "5分钟前" +``` + +## 时区处理 + +### 时区转换 + +```javascript +const date = new Date("2024-01-15T10:30:45Z"); + +// 本地时间 +console.log(date.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai" })); +// "2024/1/15 18:30:45" + +// 其他时区 +console.log(date.toLocaleString("en-US", { timeZone: "America/New_York" })); +// "1/15/2024, 5:30:45 AM" +``` + +### 时区偏移 + +```javascript +const date = new Date(); +const timezoneOffset = date.getTimezoneOffset(); // 分钟偏移 +const timezoneHours = -timezoneOffset / 60; + +console.log(`时区偏移: UTC${timezoneHours >= 0 ? "+" : ""}${timezoneHours}`); +// "时区偏移: UTC+8" +``` + +## 日期验证 + +### 有效日期检查 + +```javascript +function isValidDate(date) { + return date instanceof Date && !isNaN(date); +} + +console.log(isValidDate(new Date())); // true +console.log(isValidDate(new Date("invalid"))); // false +``` + +### 日期范围验证 + +```javascript +function isDateInRange(date, start, end) { + return date >= start && date <= end; +} + +const testDate = new Date("2024-01-15"); +const startDate = new Date("2024-01-01"); +const endDate = new Date("2024-01-31"); + +console.log(isDateInRange(testDate, startDate, endDate)); // true +``` + +## 实用工具函数 + +### 日期加减 + +```javascript +function addDays(date, days) { + const result = new Date(date); + result.setDate(result.getDate() + days); + return result; +} + +function addMonths(date, months) { + const result = new Date(date); + result.setMonth(result.getMonth() + months); + return result; +} + +const today = new Date(); +console.log(addDays(today, 7)); // 一周后 +console.log(addMonths(today, 1)); // 一月后 +``` + +### 获取月份第一天和最后一天 + +```javascript +function getFirstDayOfMonth(date) { + return new Date(date.getFullYear(), date.getMonth(), 1); +} + +function getLastDayOfMonth(date) { + return new Date(date.getFullYear(), date.getMonth() + 1, 0); +} + +const date = new Date("2024-01-15"); +console.log(getFirstDayOfMonth(date)); // 2024-01-01 +console.log(getLastDayOfMonth(date)); // 2024-01-31 +``` + +### 计算工作日 + +```javascript +function isWeekend(date) { + const day = date.getDay(); + return day === 0 || day === 6; +} + +function addWorkDays(startDate, days) { + let result = new Date(startDate); + let count = 0; + + while (count < days) { + result.setDate(result.getDate() + 1); + if (!isWeekend(result)) { + count++; + } + } + + return result; +} + +const start = new Date("2024-01-15"); // 周一 +console.log(addWorkDays(start, 3)); // 2024-01-18 (周四) +``` + +## 性能测量 + +### 执行时间测量 + +```javascript +// 方法1: Date对象 +const start = new Date(); +// 执行一些操作 +for (let i = 0; i < 1000000; i++) {} +const end = new Date(); +console.log(`执行时间: ${end - start}ms`); + +// 方法2: performance.now() (更高精度) +const startTime = performance.now(); +// 执行一些操作 +for (let i = 0; i < 1000000; i++) {} +const endTime = performance.now(); +console.log(`高精度执行时间: ${(endTime - startTime).toFixed(2)}ms`); +``` + +## 第三方库推荐 + +### 使用 date-fns (示例) + +```javascript +// 需要先安装: npm install date-fns +import { format, addDays, differenceInDays } from "date-fns"; + +const date = new Date(); +console.log(format(date, "yyyy-MM-dd")); // "2024-01-15" +console.log(addDays(date, 7)); // 一周后的日期 +console.log(differenceInDays(date, new Date("2024-01-01"))); // 14 +``` + +### 使用 Day.js (示例) + +```javascript +// 需要先安装: npm install dayjs +import dayjs from "dayjs"; + +const now = dayjs(); +console.log(now.format("YYYY-MM-DD")); // "2024-01-15" +console.log(now.add(7, "day").format()); // 一周后的日期 +console.log(now.diff("2024-01-01", "day")); // 14 +``` + +## 最佳实践 + +### 使用 ISO 格式存储和传输 + +```javascript +// 存储和传输使用ISO格式 +const date = new Date(); +const isoString = date.toISOString(); +console.log(isoString); // "2024-01-15T02:30:45.000Z" + +// 从ISO格式解析 +const parsedDate = new Date(isoString); +console.log(parsedDate); // 正确的日期对象 +``` + +### 避免时区问题 + +```javascript +// 明确指定时区 +function formatDateForDisplay(date, timezone = "Asia/Shanghai") { + return date.toLocaleString("zh-CN", { + timeZone: timezone, + year: "numeric", + month: "2-digit", + day: "2-digit", + }); +} + +const utcDate = new Date("2024-01-15T10:30:45Z"); +console.log(formatDateForDisplay(utcDate)); // "2024/01/15" +``` + +## 训练 + +```html +

第一题

+
+ +
+ +

第二题

+中国的“国球”是( )
+篮球 +排球 +乒乓球 +羽毛球 + +

第三题

+ + +

欢迎访问本网站当前时间为:

+ + + +

第四题

+ + +

宽度:

+

高度:

+ + + +

第五题

+
+ + + +
+ + +

第六题

+
+ + +

第七题

+
+ 用户名:
+ 密 码:
+
+
+ +``` + +- 效果图 + ![](https://gitee.com/putians-first-life-qing/image-transmission-warehouse/raw/master/第十一章训练.gif) -- Gitee From e40034fdee136683499770123eea63e87e56bfc4 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 7 Dec 2025 17:42:32 +0800 Subject: [PATCH 5/9] feat:zuoye --- ...26\346\224\276\344\272\213\344\273\266.md" | 450 +++++ ...51203-document\345\257\271\350\261\241.md" | 844 +++++++++ ...71\350\261\241\346\250\241\345\236\213.md" | 1205 ++++++++++++ ...0251205-window\345\257\271\350\261\241.md" | 1623 +++++++++++++++++ 4 files changed, 4122 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251201-\345\233\276\345\203\217\346\213\226\346\224\276\344\272\213\344\273\266.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251203-document\345\257\271\350\261\241.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251205-window\345\257\271\350\261\241.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251201-\345\233\276\345\203\217\346\213\226\346\224\276\344\272\213\344\273\266.md" "b/\344\270\245\345\201\245\345\256\207/20251201-\345\233\276\345\203\217\346\213\226\346\224\276\344\272\213\344\273\266.md" new file mode 100644 index 000000000..4f6fb3eba --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251201-\345\233\276\345\203\217\346\213\226\346\224\276\344\272\213\344\273\266.md" @@ -0,0 +1,450 @@ +# JavaScript 对象拖放知识点总结 + +## 📋 目录 + +1. [基础概念](#基础概念) +2. [拖放事件](#拖放事件) +3. [数据传递](#数据传递) +4. [视觉效果](#视觉效果) +5. [完整示例](#完整示例) + +--- + +## 基础概念 + +### 1. 使元素可拖放 + +**知识点**:使用 `draggable="true"` 属性使元素可拖放。 + +```javascript +// 使元素可拖放 +const draggableElement = document.getElementById("draggable"); +draggableElement.setAttribute("draggable", "true"); +``` + +### 2. 拖放事件生命周期 + +**知识点**:拖放操作涉及两个对象的事件:被拖元素(drag source)和目标区域(drop target)。 + +```javascript +// 被拖元素事件 +element.addEventListener("dragstart", handleDragStart); +element.addEventListener("dragend", handleDragEnd); + +// 目标区域事件 +target.addEventListener("dragover", handleDragOver); +target.addEventListener("drop", handleDrop); +``` + +--- + +## 拖放事件 + +### 3. dragstart 事件 + +**知识点**:开始拖动时触发,用于设置拖拽数据。 + +```javascript +function handleDragStart(e) { + e.dataTransfer.setData("text/plain", e.target.id); + e.target.classList.add("dragging"); +} +``` + +### 4. dragend 事件 + +**知识点**:拖放操作结束时触发,无论成功与否。 + +```javascript +function handleDragEnd(e) { + e.target.classList.remove("dragging"); + console.log("拖放操作结束"); +} +``` + +### 5. dragover 事件 + +**知识点**:当元素被拖到有效目标上时持续触发,必须阻止默认行为以允许放置。 + +```javascript +function handleDragOver(e) { + e.preventDefault(); // 必须调用 + e.target.classList.add("drag-over"); +} +``` + +### 6. dragenter 事件 + +**知识点**:被拖元素进入目标区域时触发。 + +```javascript +function handleDragEnter(e) { + e.preventDefault(); + e.target.classList.add("drag-enter"); +} +``` + +### 7. dragleave 事件 + +**知识点**:被拖元素离开目标区域时触发。 + +```javascript +function handleDragLeave(e) { + e.target.classList.remove("drag-enter", "drag-over"); +} +``` + +### 8. drop 事件 + +**知识点**:在目标区域释放被拖元素时触发。 + +```javascript +function handleDrop(e) { + e.preventDefault(); + const id = e.dataTransfer.getData("text/plain"); + const element = document.getElementById(id); + e.target.appendChild(element); + e.target.classList.remove("drag-enter", "drag-over"); +} +``` + +--- + +## 数据传递 + +### 9. 设置拖拽数据 + +**知识点**:使用 `dataTransfer.setData()` 存储拖拽数据。 + +```javascript +function handleDragStart(e) { + // 存储不同类型的数据 + e.dataTransfer.setData("text/plain", e.target.textContent); + e.dataTransfer.setData("text/html", e.target.innerHTML); + e.dataTransfer.setData( + "application/json", + JSON.stringify({ id: e.target.id, type: "element" }) + ); +} +``` + +### 10. 获取拖拽数据 + +**知识点**:使用 `dataTransfer.getData()` 获取存储的数据。 + +```javascript +function handleDrop(e) { + e.preventDefault(); + const text = e.dataTransfer.getData("text/plain"); + const json = e.dataTransfer.getData("application/json"); + + if (json) { + const data = JSON.parse(json); + console.log("拖拽的元素ID:", data.id); + } +} +``` + +### 11. 自定义拖拽类型 + +**知识点**:可以使用自定义 MIME 类型传递特定数据。 + +```javascript +function handleDragStart(e) { + e.dataTransfer.setData( + "application/myapp-item", + JSON.stringify({ id: "item123", name: "示例项目" }) + ); +} +``` + +--- + +## 视觉效果 + +### 12. 设置拖拽图像 + +**知识点**:使用 `setDragImage()` 自定义拖拽时显示的图像。 + +```javascript +function handleDragStart(e) { + const dragIcon = document.createElement("div"); + dragIcon.textContent = "📦"; + dragIcon.style.fontSize = "24px"; + + // 设置自定义拖拽图像(元素,x偏移,y偏移) + e.dataTransfer.setDragImage(dragIcon, 10, 10); +} +``` + +### 13. 拖拽效果 + +**知识点**:使用 `effectAllowed` 和 `dropEffect` 控制拖拽效果。 + +```javascript +function handleDragStart(e) { + // 定义源元素允许的效果 + e.dataTransfer.effectAllowed = "copyMove"; +} + +function handleDragOver(e) { + e.preventDefault(); + // 定义目标区域的显示效果 + e.dataTransfer.dropEffect = "move"; +} +``` + +### 14. 文件拖放 + +**知识点**:处理文件拖放时需要检查 `dataTransfer.files`。 + +```javascript +function handleDrop(e) { + e.preventDefault(); + + if (e.dataTransfer.files.length > 0) { + const files = e.dataTransfer.files; + console.log(`拖放了 ${files.length} 个文件`); + } +} +``` + +--- + +## 完整示例 + +### 15. 简单的拖放实现 + +```javascript +// HTML结构 +//
可拖拽项目
+//
放置区域
+ +const dragItem = document.getElementById("drag-item"); +const dropZone = document.getElementById("drop-zone"); + +// 拖拽开始 +dragItem.addEventListener("dragstart", (e) => { + e.dataTransfer.setData("text/plain", e.target.id); + e.target.style.opacity = "0.5"; +}); + +// 拖拽结束 +dragItem.addEventListener("dragend", (e) => { + e.target.style.opacity = "1"; +}); + +// 拖拽到目标上方 +dropZone.addEventListener("dragover", (e) => { + e.preventDefault(); + e.target.style.border = "2px dashed #4CAF50"; +}); + +// 离开目标 +dropZone.addEventListener("dragleave", (e) => { + e.target.style.border = "2px dashed #ccc"; +}); + +// 放置 +dropZone.addEventListener("drop", (e) => { + e.preventDefault(); + e.target.style.border = "2px solid #4CAF50"; + + const id = e.dataTransfer.getData("text/plain"); + const element = document.getElementById(id); + + if (element) { + e.target.appendChild(element); + element.style.opacity = "1"; + } +}); +``` + +### 16. 多元素拖放排序 + +```javascript +// HTML:
  • 项目1
  • ...
+ +const list = document.getElementById("sortable-list"); + +list.addEventListener("dragstart", (e) => { + if (e.target.tagName === "LI") { + e.dataTransfer.setData("text/plain", e.target.id); + e.dataTransfer.effectAllowed = "move"; + } +}); + +list.addEventListener("dragover", (e) => { + e.preventDefault(); + e.dataTransfer.dropEffect = "move"; + + const afterElement = getDragAfterElement(list, e.clientY); + const draggable = document.querySelector(".dragging"); + + if (afterElement == null) { + list.appendChild(draggable); + } else { + list.insertBefore(draggable, afterElement); + } +}); + +function getDragAfterElement(container, y) { + const draggableElements = [ + ...container.querySelectorAll("li:not(.dragging)"), + ]; + + return draggableElements.reduce( + (closest, child) => { + const box = child.getBoundingClientRect(); + const offset = y - box.top - box.height / 2; + + if (offset < 0 && offset > closest.offset) { + return { offset: offset, element: child }; + } else { + return closest; + } + }, + { offset: Number.NEGATIVE_INFINITY } + ).element; +} +``` + +--- + +## ⚠️ 注意事项 + +1. **浏览器兼容性**:大部分现代浏览器都支持 HTML5 拖放 API,但某些旧版本可能需要前缀 +2. **移动设备**:拖放 API 在移动设备上支持有限 +3. **安全性**:出于安全考虑,某些数据类型(如文件)只能在特定场景下传输 +4. **性能**:频繁的`dragover`事件可能影响性能,建议进行节流处理 + +--- + +## 📚 总结要点 + +| 事件 | 触发元素 | 描述 | +| ----------- | -------- | -------------------------- | +| `dragstart` | 被拖元素 | 开始拖动时触发 | +| `drag` | 被拖元素 | 拖动过程中持续触发 | +| `dragend` | 被拖元素 | 拖动结束时触发 | +| `dragenter` | 目标元素 | 进入目标区域时触发 | +| `dragover` | 目标元素 | 在目标区域上移动时持续触发 | +| `dragleave` | 目标元素 | 离开目标区域时触发 | +| `drop` | 目标元素 | 在目标区域释放时触发 | + +**核心方法**: + +- `dataTransfer.setData()` - 存储拖拽数据 +- `dataTransfer.getData()` - 获取拖拽数据 +- `dataTransfer.setDragImage()` - 设置拖拽图像 +- `event.preventDefault()` - 允许放置(在`dragover`和`drop`中必须调用) + +--- + +# 训练 + +```html + + + + +
+
+
+ +
定义的文本
+ +
+ +``` + +# 实践练习 + +```html + +

第一题

+
+ 欢迎购买明日科技图书 +
+ +

第二题

+ + +

第三题

+ + + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251203-document\345\257\271\350\261\241.md" "b/\344\270\245\345\201\245\345\256\207/20251203-document\345\257\271\350\261\241.md" new file mode 100644 index 000000000..c9cf35ef8 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251203-document\345\257\271\350\261\241.md" @@ -0,0 +1,844 @@ +# JavaScript Document 对象知识点总结 + +## 📋 文档概述 + +Document 对象代表整个 HTML 文档,是 DOM 树的根节点,提供了访问和操作页面内容的接口。 + +--- + +## 🔧 文档属性 + +### 1. 基础文档信息 + +**知识点**:获取文档基本信息如标题、URL、字符集等。 + +```javascript +// 获取文档标题 +console.log(document.title); // "页面标题" + +// 获取文档URL +console.log(document.URL); // "https://example.com" + +// 获取文档字符集 +console.log(document.characterSet); // "UTF-8" + +// 获取文档最后修改时间 +console.log(document.lastModified); +``` + +### 2. 文档结构访问 + +**知识点**:访问文档的根元素和 body 元素。 + +```javascript +// 获取文档根元素(HTML) +console.log(document.documentElement); // 元素 + +// 获取文档头部 +console.log(document.head); // 元素 + +// 获取文档主体 +console.log(document.body); // 元素 + +// 获取所有样式表 +console.log(document.styleSheets); +``` + +### 3. 文档状态 + +**知识点**:检查文档加载状态。 + +```javascript +// 检查文档是否加载完成 +if (document.readyState === "complete") { + console.log("文档已完全加载"); +} + +// 监听文档状态变化 +document.onreadystatechange = function () { + if (document.readyState === "interactive") { + console.log("DOM已加载完成"); + } +}; +``` + +--- + +## 🔍 元素选择 + +### 4. getElementById() + +**知识点**:通过 ID 获取单个元素。 + +```javascript +// 获取ID为"header"的元素 +const header = document.getElementById("header"); +header.style.backgroundColor = "blue"; +``` + +### 5. getElementsByClassName() + +**知识点**:通过类名获取元素集合(HTMLCollection)。 + +```javascript +// 获取所有class包含"item"的元素 +const items = document.getElementsByClassName("item"); +console.log(items.length); // 元素数量 +``` + +### 6. getElementsByTagName() + +**知识点**:通过标签名获取元素集合。 + +```javascript +// 获取所有
元素 +const divs = document.getElementsByTagName("div"); +for (let div of divs) { + console.log(div.tagName); +} +``` + +### 7. querySelector() + +**知识点**:使用 CSS 选择器获取第一个匹配元素。 + +```javascript +// 获取第一个类名为"btn"的按钮 +const button = document.querySelector("button.btn"); +button.addEventListener("click", handleClick); +``` + +### 8. querySelectorAll() + +**知识点**:使用 CSS 选择器获取所有匹配元素(NodeList)。 + +```javascript +// 获取所有类名为"item"的
  • 元素 +const listItems = document.querySelectorAll("li.item"); +listItems.forEach((item) => { + item.style.color = "red"; +}); +``` + +--- + +## ✨ 元素创建与操作 + +### 9. createElement() + +**知识点**:创建新的 HTML 元素。 + +```javascript +// 创建一个新的
    元素 +const newDiv = document.createElement("div"); +newDiv.textContent = "新创建的元素"; +newDiv.className = "custom-div"; +``` + +### 10. createTextNode() + +**知识点**:创建文本节点。 + +```javascript +// 创建文本节点 +const textNode = document.createTextNode("这是一段文本"); +document.body.appendChild(textNode); +``` + +### 11. appendChild() + +**知识点**:将节点添加到父节点的子节点列表末尾。 + +```javascript +// 将新元素添加到body中 +const newElement = document.createElement("p"); +newElement.textContent = "新段落"; +document.body.appendChild(newElement); +``` + +### 12. removeChild() + +**知识点**:从父节点中移除子节点。 + +```javascript +// 移除ID为"old-element"的元素 +const parent = document.getElementById("container"); +const child = document.getElementById("old-element"); +parent.removeChild(child); + +// 现代写法(不需要获取父元素) +// child.remove(); +``` + +### 13. insertBefore() + +**知识点**:在指定节点前插入新节点。 + +```javascript +// 在某个元素前插入新元素 +const newItem = document.createElement("li"); +newItem.textContent = "新项目"; +const list = document.getElementById("my-list"); +const firstItem = list.firstElementChild; +list.insertBefore(newItem, firstItem); +``` + +### 14. cloneNode() + +**知识点**:克隆节点,可选择是否克隆子节点。 + +```javascript +// 克隆元素 +const original = document.getElementById("template"); +const clone = original.cloneNode(true); // true表示深克隆(包括子节点) +clone.id = "template-clone"; +document.body.appendChild(clone); +``` + +--- + +## 📝 内容操作 + +### 15. innerHTML + +**知识点**:获取或设置元素的 HTML 内容。 + +```javascript +// 设置元素HTML内容 +document.getElementById("content").innerHTML = "

    新标题

    新内容

    "; + +// 获取元素HTML内容 +const htmlContent = document.getElementById("content").innerHTML; +console.log(htmlContent); +``` + +### 16. textContent + +**知识点**:获取或设置元素的文本内容(忽略 HTML 标签)。 + +```javascript +// 设置文本内容(安全,不会解析HTML) +document.getElementById("title").textContent = ''; + +// 获取文本内容 +const text = document.getElementById("title").textContent; +``` + +### 17. innerText + +**知识点**:获取或设置元素的可见文本内容。 + +```javascript +// 设置可见文本 +const element = document.getElementById("message"); +element.innerText = "这是一条消息"; + +// innerText与textContent的区别 +// innerText考虑CSS样式(如display:none),textContent不考虑 +``` + +--- + +## 🎯 属性操作 + +### 18. setAttribute() + +**知识点**:设置元素属性。 + +```javascript +// 设置元素属性 +const img = document.querySelector("img"); +img.setAttribute("src", "new-image.jpg"); +img.setAttribute("alt", "新图片描述"); +img.setAttribute("data-custom", "自定义数据"); +``` + +### 19. getAttribute() + +**知识点**:获取元素属性值。 + +```javascript +// 获取元素属性 +const link = document.querySelector("a"); +const href = link.getAttribute("href"); +const target = link.getAttribute("target"); +console.log(`链接地址: ${href}, 打开方式: ${target}`); +``` + +### 20. removeAttribute() + +**知识点**:移除元素属性。 + +```javascript +// 移除元素属性 +const input = document.querySelector("input"); +input.removeAttribute("disabled"); // 启用输入框 +input.removeAttribute("readonly"); // 移除只读属性 +``` + +### 21. dataset + +**知识点**:访问 data-\* 自定义属性。 + +```javascript +// HTML:
    +const userDiv = document.getElementById("user"); +console.log(userDiv.dataset.userId); // "123" +console.log(userDiv.dataset.userRole); // "admin" + +// 设置data属性 +userDiv.dataset.userStatus = "active"; +``` + +--- + +## 🎨 样式操作 + +### 22. style 属性 + +**知识点**:通过 style 属性直接操作内联样式。 + +```javascript +const box = document.getElementById("box"); + +// 设置单个样式 +box.style.backgroundColor = "blue"; +box.style.width = "200px"; +box.style.height = "200px"; + +// 使用cssText设置多个样式 +box.style.cssText = "color: red; font-size: 20px; border: 1px solid black;"; + +// 移除样式 +box.style.backgroundColor = ""; +``` + +### 23. classList + +**知识点**:操作元素的 class 属性。 + +```javascript +const element = document.getElementById("my-element"); + +// 添加类 +element.classList.add("active", "highlight"); + +// 移除类 +element.classList.remove("inactive"); + +// 切换类 +element.classList.toggle("visible"); + +// 检查是否包含类 +if (element.classList.contains("active")) { + console.log("元素处于活跃状态"); +} + +// 替换类 +element.classList.replace("old-class", "new-class"); +``` + +--- + +## 📄 表单操作 + +### 24. 访问表单元素 + +**知识点**:通过 document.forms 访问页面中的表单。 + +```javascript +// 通过索引访问表单 +const firstForm = document.forms[0]; + +// 通过name访问表单 +const loginForm = document.forms["login"]; + +// 获取表单元素 +const emailInput = loginForm.elements["email"]; +const passwordInput = loginForm["password"]; + +// 获取表单值 +console.log(emailInput.value); +``` + +### 25. 表单提交与重置 + +**知识点**:控制表单的提交和重置。 + +```javascript +const form = document.getElementById("my-form"); + +// 提交表单 +form.submit(); + +// 重置表单 +form.reset(); + +// 阻止表单提交 +form.addEventListener("submit", function (event) { + event.preventDefault(); // 阻止默认提交行为 + // 自定义提交逻辑 + console.log("表单数据:", new FormData(form)); +}); +``` + +--- + +## 🎭 事件处理 + +### 26. addEventListener() + +**知识点**:为元素添加事件监听器。 + +```javascript +const button = document.getElementById("my-button"); + +// 添加点击事件监听 +button.addEventListener("click", function (event) { + console.log("按钮被点击了", event.target); + event.stopPropagation(); // 阻止事件冒泡 +}); + +// 添加带选项的事件监听 +button.addEventListener("click", handleClick, { + once: true, // 只执行一次 + capture: false, // 冒泡阶段 + passive: true, // 不会调用preventDefault() +}); +``` + +### 27. removeEventListener() + +**知识点**:移除事件监听器。 + +```javascript +function handleClick(event) { + console.log("点击处理"); +} + +// 添加事件监听 +button.addEventListener("click", handleClick); + +// 移除事件监听 +button.removeEventListener("click", handleClick); +``` + +### 28. 事件委托 + +**知识点**:利用事件冒泡处理动态元素事件。 + +```javascript +// 为父元素添加事件监听,处理动态子元素 +document.getElementById("list").addEventListener("click", function (event) { + // 检查点击的是否是列表项 + if (event.target.tagName === "LI") { + console.log("点击了列表项:", event.target.textContent); + event.target.classList.toggle("selected"); + } +}); +``` + +--- + +## 🔗 文档遍历 + +### 29. 节点关系 + +**知识点**:访问节点的父节点、子节点和兄弟节点。 + +```javascript +const element = document.getElementById("current"); + +// 父节点 +console.log(element.parentNode); + +// 所有子节点(包括文本节点) +console.log(element.childNodes); + +// 元素子节点 +console.log(element.children); + +// 第一个子节点 +console.log(element.firstChild); + +// 最后一个子节点 +console.log(element.lastChild); + +// 前一个兄弟节点 +console.log(element.previousSibling); + +// 后一个兄弟节点 +console.log(element.nextSibling); +``` + +### 30. 元素遍历 + +**知识点**:只关注元素节点的遍历方法。 + +```javascript +const element = document.getElementById("current"); + +// 父元素 +console.log(element.parentElement); + +// 第一个子元素 +console.log(element.firstElementChild); + +// 最后一个子元素 +console.log(element.lastElementChild); + +// 前一个兄弟元素 +console.log(element.previousElementSibling); + +// 后一个兄弟元素 +console.log(element.nextElementSibling); +``` + +--- + +## 🚀 性能优化 + +### 31. 文档片段 + +**知识点**:使用 DocumentFragment 提高批量 DOM 操作性能。 + +```javascript +// 创建文档片段 +const fragment = document.createDocumentFragment(); + +// 向片段中添加多个元素 +for (let i = 0; i < 100; i++) { + const item = document.createElement("li"); + item.textContent = `项目 ${i + 1}`; + fragment.appendChild(item); +} + +// 一次性添加到DOM中 +document.getElementById("list").appendChild(fragment); +``` + +### 32. 批量操作 + +**知识点**:减少 DOM 操作次数以提高性能。 + +```javascript +// 不推荐的写法(多次重排重绘) +const list = document.getElementById("list"); +for (let i = 0; i < 10; i++) { + const item = document.createElement("li"); + item.textContent = `项目 ${i}`; + list.appendChild(item); // 每次添加都触发重排 +} + +// 推荐的写法(一次操作) +const items = []; +for (let i = 0; i < 10; i++) { + const item = document.createElement("li"); + item.textContent = `项目 ${i}`; + items.push(item); +} +list.append(...items); // 一次添加所有元素 +``` + +--- + +## 🛡️ 安全相关 + +### 33. 防止 XSS 攻击 + +**知识点**:安全地操作 DOM 内容。 + +```javascript +// 不安全:可能执行恶意脚本 +element.innerHTML = userInput; // ❌ 危险! + +// 安全方法1:使用textContent +element.textContent = userInput; // ✅ 安全 + +// 安全方法2:使用innerHTML但先转义 +function escapeHTML(text) { + const div = document.createElement("div"); + div.textContent = text; + return div.innerHTML; +} + +element.innerHTML = escapeHTML(userInput); // ✅ 安全 +``` + +--- + +## 📊 完整示例 + +### 34. 动态表格生成 + +```javascript +function createTable(data, containerId) { + const container = document.getElementById(containerId); + const table = document.createElement("table"); + table.className = "data-table"; + + // 创建表头 + const thead = document.createElement("thead"); + const headerRow = document.createElement("tr"); + + Object.keys(data[0]).forEach((key) => { + const th = document.createElement("th"); + th.textContent = key; + headerRow.appendChild(th); + }); + + thead.appendChild(headerRow); + table.appendChild(thead); + + // 创建表格主体 + const tbody = document.createElement("tbody"); + + data.forEach((item) => { + const row = document.createElement("tr"); + + Object.values(item).forEach((value) => { + const td = document.createElement("td"); + td.textContent = value; + row.appendChild(td); + }); + + tbody.appendChild(row); + }); + + table.appendChild(tbody); + container.appendChild(table); +} + +// 使用示例 +const users = [ + { id: 1, name: "张三", email: "zhangsan@example.com" }, + { id: 2, name: "李四", email: "lisi@example.com" }, +]; + +createTable(users, "table-container"); +``` + +### 35. 模态框组件 + +```javascript +class Modal { + constructor(content) { + this.modal = document.createElement("div"); + this.modal.className = "modal"; + this.modal.innerHTML = ` + + `; + + this.setupEvents(); + } + + setupEvents() { + // 关闭按钮事件 + this.modal.querySelector(".close").addEventListener("click", () => { + this.hide(); + }); + + // 点击模态框外部关闭 + this.modal.addEventListener("click", (event) => { + if (event.target === this.modal) { + this.hide(); + } + }); + + // ESC键关闭 + document.addEventListener("keydown", (event) => { + if (event.key === "Escape" && this.isVisible) { + this.hide(); + } + }); + } + + show() { + document.body.appendChild(this.modal); + this.isVisible = true; + } + + hide() { + this.modal.remove(); + this.isVisible = false; + } +} + +// 使用示例 +const modal = new Modal("

    标题

    这是一段内容

    "); +modal.show(); +``` + +--- + +## 📌 实用技巧 + +### 36. 检查元素存在 + +```javascript +// 检查元素是否存在 +if (document.getElementById("element-id")) { + // 元素存在 +} + +// 检查多个元素是否存在 +const elementsExist = document.querySelectorAll(".my-class").length > 0; +``` + +### 37. 获取计算样式 + +```javascript +// 获取元素计算后的样式 +const element = document.getElementById("my-element"); +const computedStyle = window.getComputedStyle(element); +console.log("宽度:", computedStyle.width); +console.log("背景颜色:", computedStyle.backgroundColor); +``` + +### 38. 检查元素可见性 + +```javascript +function isElementVisible(element) { + const rect = element.getBoundingClientRect(); + const windowHeight = + window.innerHeight || document.documentElement.clientHeight; + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= windowHeight && + rect.right <= (window.innerWidth || document.documentElement.clientWidth) + ); +} + +// 使用示例 +const element = document.getElementById("target"); +console.log("元素是否在视口中:", isElementVisible(element)); +``` + +--- + +## 📚 总结要点 + +| 方法/属性 | 描述 | 返回值类型 | +| -------------------- | ------------------------ | ------------------- | +| `getElementById()` | 通过 ID 获取元素 | Element | +| `querySelector()` | CSS 选择器获取第一个元素 | Element | +| `querySelectorAll()` | CSS 选择器获取所有元素 | NodeList | +| `createElement()` | 创建新元素 | Element | +| `appendChild()` | 添加子节点 | Node | +| `removeChild()` | 移除子节点 | Node | +| `addEventListener()` | 添加事件监听 | - | +| `innerHTML` | 获取/设置 HTML 内容 | String | +| `textContent` | 获取/设置文本内容 | String | +| `classList` | 操作 CSS 类 | DOMTokenList | +| `style` | 操作内联样式 | CSSStyleDeclaration | + +--- + +## ⚠️ 注意事项 + +1. **性能**:避免频繁的 DOM 操作,使用文档片段或批量操作 +2. **内存泄漏**:及时移除不再需要的事件监听器 +3. **兼容性**:注意不同浏览器对某些 API 的支持差异 +4. **安全性**:谨慎使用 `innerHTML` 处理用户输入,防止 XSS 攻击 +5. **异步加载**:确保 DOM 完全加载后再执行操作(使用 `DOMContentLoaded` 事件) + +--- + +# 练习 + +```html + + +

    第一题

    + +
    +

    李白《行路难 其一》

    + 金樽清酒斗十千,玉盘珍羞直万钱。
    + 停杯投箸不能食,拔剑四顾心茫然。
    + 欲渡黄河冰塞川,将登太行雪满山。
    + 闲来垂钓碧溪上,忽复乘舟梦日边。
    + 行路难!行路难!多岐路,今安在?
    + 长风破浪会有时,直挂云帆济沧海。
    +
    + +

    第二题

    + + 打开图片对话框 + +
    + 删除 +
    + +

    第三题

    + +
    + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\344\270\245\345\201\245\345\256\207/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 000000000..97a9b8edc --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,1205 @@ +# JavaScript DOM 全面知识点总结 + +## 📋 目录 + +1. [DOM 概述](#dom-概述) +2. [DOM 节点属性](#dom-节点属性) +3. [DOM 节点类型](#dom-节点类型) +4. [获取文档指定元素](#获取文档指定元素) +5. [与 DHTML 对应的 DOM 操作](#与-dhtml-对应的-dom-操作) +6. [DOM 核心方法总结](#dom-核心方法总结) + +--- + +## DOM 概述 + +### 1. 什么是 DOM? + +**知识点**:DOM(Document Object Model)是 HTML 和 XML 文档的编程接口,它将文档表示为节点树,允许程序访问和操作文档的内容、结构和样式。 + +```javascript +// 访问整个文档 +console.log(document); // Document对象 + +// 查看DOM树结构 +console.log(document.documentElement); // 元素 +``` + +### 2. DOM 树结构 + +**知识点**:DOM 将文档表示为树形结构,每个部分(元素、属性、文本)都是树上的节点。 + +```javascript +// 简单的HTML结构示例 +// +// +// 页面标题 +// +// +//

    标题

    +//

    段落

    +// +// + +console.log(document.documentElement); // 根节点 +console.log(document.head); // 节点 +console.log(document.body); // 节点 +``` + +### 3. DOM 标准化 + +**知识点**:DOM 由 W3C 标准化,分为不同级别,现代浏览器支持 DOM Level 3。 + +```javascript +// 检查DOM特性支持 +console.log("DOM Level 1:", !!document.getElementById); +console.log("DOM Level 2:", !!document.addEventListener); +console.log("DOM Level 3:", !!document.createEvent); +``` + +--- + +## DOM 节点属性 + +### 4. 通用节点属性 + +**知识点**:所有 DOM 节点都有的通用属性。 + +```javascript +const element = document.getElementById("myElement"); + +// 节点基本信息 +console.log("节点名称:", element.nodeName); // 标签名(如"DIV") +console.log("节点类型:", element.nodeType); // 1表示元素节点 +console.log("节点值:", element.nodeValue); // 对于元素节点为null + +// 父子关系 +console.log("父节点:", element.parentNode); +console.log("子节点数量:", element.childNodes.length); +console.log("第一个子节点:", element.firstChild); +console.log("最后一个子节点:", element.lastChild); +``` + +### 5. 元素节点属性 + +**知识点**:元素节点特有的属性。 + +```javascript +const div = document.querySelector("div"); + +// 元素标签相关 +console.log("标签名:", div.tagName); // "DIV" +console.log("标签名小写:", div.tagName.toLowerCase()); // "div" + +// 内容相关 +console.log("HTML内容:", div.innerHTML); +console.log("文本内容:", div.textContent); +console.log("内部文本:", div.innerText); // 考虑CSS可见性 + +// 属性相关 +console.log("所有属性:", div.attributes); +console.log("类名:", div.className); +console.log("ID:", div.id); +``` + +### 6. 属性节点属性 + +**知识点**:属性节点的特殊属性。 + +```javascript +const element = document.getElementById("myElement"); +const attr = element.attributes[0]; // 获取第一个属性节点 + +if (attr) { + console.log("属性名称:", attr.name); // 属性名 + console.log("属性值:", attr.value); // 属性值 + console.log("是否指定:", attr.specified); // 是否显式指定 + console.log("节点类型:", attr.nodeType); // 2表示属性节点 +} +``` + +### 7. 文本节点属性 + +**知识点**:文本节点的属性。 + +```javascript +const textNode = document.createTextNode("示例文本"); + +console.log("节点类型:", textNode.nodeType); // 3表示文本节点 +console.log("节点名称:", textNode.nodeName); // "#text" +console.log("节点值:", textNode.nodeValue); // "示例文本" +console.log("文本长度:", textNode.length); // 4(字符数) +``` + +### 8. 样式相关属性 + +**知识点**:与 CSS 样式相关的 DOM 属性。 + +```javascript +const element = document.getElementById("styled-element"); + +// 内联样式 +console.log("内联样式:", element.style); +element.style.color = "red"; +element.style.fontSize = "16px"; + +// 计算样式(最终应用的样式) +const computedStyle = window.getComputedStyle(element); +console.log("计算后的颜色:", computedStyle.color); +console.log("计算后的字体大小:", computedStyle.fontSize); + +// 类名操作 +console.log("类列表:", element.classList); +element.classList.add("active"); +element.classList.remove("inactive"); +``` + +--- + +## DOM 节点类型 + +### 9. 节点类型常量 + +**知识点**:DOM 定义了 12 种节点类型,使用常量值表示。 + +```javascript +// 节点类型常量 +console.log("元素节点:", Node.ELEMENT_NODE); // 1 +console.log("属性节点:", Node.ATTRIBUTE_NODE); // 2 +console.log("文本节点:", Node.TEXT_NODE); // 3 +console.log("CDATA节点:", Node.CDATA_SECTION_NODE); // 4 +console.log("实体引用:", Node.ENTITY_REFERENCE_NODE); // 5 +console.log("实体节点:", Node.ENTITY_NODE); // 6 +console.log("处理指令:", Node.PROCESSING_INSTRUCTION_NODE); // 7 +console.log("注释节点:", Node.COMMENT_NODE); // 8 +console.log("文档节点:", Node.DOCUMENT_NODE); // 9 +console.log("文档类型:", Node.DOCUMENT_TYPE_NODE); // 10 +console.log("文档片段:", Node.DOCUMENT_FRAGMENT_NODE); // 11 +console.log("符号节点:", Node.NOTATION_NODE); // 12 + +// 检查节点类型 +const element = document.createElement("div"); +console.log("元素节点类型:", element.nodeType); // 1 +console.log("类型匹配:", element.nodeType === Node.ELEMENT_NODE); // true +``` + +### 10. 文档节点 + +**知识点**:文档节点是 DOM 树的根节点,表示整个文档。 + +```javascript +console.log("文档节点类型:", document.nodeType); // 9 +console.log("文档节点名称:", document.nodeName); // "#document" +console.log("文档元素:", document.documentElement); // 元素 +console.log("文档头部:", document.head); +console.log("文档主体:", document.body); +``` + +### 11. 元素节点 + +**知识点**:元素节点表示 HTML 标签。 + +```javascript +const div = document.createElement("div"); + +console.log("元素节点类型:", div.nodeType); // 1 +console.log("元素节点名称:", div.nodeName); // "DIV" + +// 创建带属性的元素 +const img = document.createElement("img"); +img.src = "image.jpg"; +img.alt = "图片"; +img.className = "thumbnail"; + +// 创建带文本内容的元素 +const p = document.createElement("p"); +p.textContent = "这是一个段落"; +``` + +### 12. 文本节点 + +**知识点**:文本节点包含元素的文本内容。 + +```javascript +// 创建文本节点 +const textNode = document.createTextNode("Hello World"); + +console.log("文本节点类型:", textNode.nodeType); // 3 +console.log("文本节点名称:", textNode.nodeName); // "#text" +console.log("文本内容:", textNode.nodeValue); // "Hello World" + +// 操作文本内容 +textNode.nodeValue = "修改后的文本"; + +// 拆分文本节点 +const secondPart = textNode.splitText(5); +console.log("第一部分:", textNode.nodeValue); // "Hello" +console.log("第二部分:", secondPart.nodeValue); // " World" +``` + +### 13. 属性节点 + +**知识点**:属性节点表示元素的属性,但现代 API 通常不直接使用属性节点。 + +```javascript +const element = document.createElement("div"); +element.setAttribute("data-id", "123"); + +// 获取属性节点(传统方式) +const attrNode = element.attributes[0]; +console.log("属性节点类型:", attrNode.nodeType); // 2 +console.log("属性名称:", attrNode.name); // "data-id" +console.log("属性值:", attrNode.value); // "123" + +// 现代方式(推荐) +console.log("属性值:", element.getAttribute("data-id")); +``` + +### 14. 注释节点 + +**知识点**:注释节点表示 HTML 注释。 + +```javascript +// 创建注释节点 +const comment = document.createComment("这是一个注释"); + +console.log("注释节点类型:", comment.nodeType); // 8 +console.log("注释节点名称:", comment.nodeName); // "#comment" +console.log("注释内容:", comment.nodeValue); // "这是一个注释" + +// 添加到文档 +document.body.appendChild(comment); +``` + +### 15. 文档片段节点 + +**知识点**:文档片段是轻量级的文档节点,用于批量操作 DOM。 + +```javascript +// 创建文档片段 +const fragment = document.createDocumentFragment(); + +console.log("文档片段类型:", fragment.nodeType); // 11 +console.log("文档片段名称:", fragment.nodeName); // "#document-fragment" + +// 向片段中添加元素 +for (let i = 0; i < 10; i++) { + const li = document.createElement("li"); + li.textContent = `项目 ${i + 1}`; + fragment.appendChild(li); +} + +// 一次性添加到DOM +document.getElementById("list").appendChild(fragment); +``` + +--- + +## 获取文档指定元素 + +### 16. 传统获取方法 + +**知识点**:DOM Level 1 提供的基本获取方法。 + +```javascript +// 通过ID获取 +const byId = document.getElementById("header"); + +// 通过标签名获取(返回HTMLCollection) +const byTag = document.getElementsByTagName("div"); + +// 通过类名获取(返回HTMLCollection) +const byClass = document.getElementsByClassName("item"); + +// 通过name属性获取(返回NodeList) +const byName = document.getElementsByName("username"); +``` + +### 17. querySelector 方法 + +**知识点**:现代的选择器 API,支持 CSS 选择器。 + +```javascript +// 获取第一个匹配元素 +const firstMatch = document.querySelector(".container"); +const firstButton = document.querySelector('button[type="submit"]'); + +// 获取所有匹配元素(返回NodeList) +const allMatches = document.querySelectorAll(".item"); +const allInputs = document.querySelectorAll("input[required]"); + +// 复杂选择器 +const complex = document.querySelector("div.content > p:first-child"); +``` + +### 18. 选择器示例 + +**知识点**:各种 CSS 选择器的 DOM 应用。 + +```javascript +// 基本选择器 +document.querySelector("#id"); // ID选择器 +document.querySelector(".class"); // 类选择器 +document.querySelector("element"); // 元素选择器 + +// 属性选择器 +document.querySelector("[href]"); // 有href属性 +document.querySelector('[href="#"]'); // href="#" +document.querySelector('[href^="https"]'); // href以https开头 +document.querySelector('[href$=".pdf"]'); // href以.pdf结尾 +document.querySelector('[href*="example"]'); // href包含example + +// 伪类选择器 +document.querySelector(":hover"); // 鼠标悬停 +document.querySelector("input:checked"); // 选中的输入框 +document.querySelector("li:nth-child(odd)"); // 奇数子元素 +document.querySelector("tr:nth-of-type(2n)"); // 偶数行 + +// 组合选择器 +document.querySelector("div.warning"); // 同时满足 +document.querySelector("h1, h2, h3"); // 或关系 +document.querySelector("ul > li"); // 直接子元素 +document.querySelector("p + img"); // 相邻兄弟 +document.querySelector("h1 ~ p"); // 后续兄弟 +``` + +### 19. 遍历节点树 + +**知识点**:通过节点关系获取元素。 + +```javascript +const element = document.getElementById("current"); + +// 向上遍历 +console.log("父元素:", element.parentElement); +console.log("父节点:", element.parentNode); + +// 向下遍历 +console.log("所有子节点:", element.childNodes); +console.log("所有子元素:", element.children); +console.log("第一个子节点:", element.firstChild); +console.log("最后一个子节点:", element.lastChild); +console.log("第一个子元素:", element.firstElementChild); +console.log("最后一个子元素:", element.lastElementChild); + +// 水平遍历 +console.log("前一个兄弟节点:", element.previousSibling); +console.log("后一个兄弟节点:", element.nextSibling); +console.log("前一个兄弟元素:", element.previousElementSibling); +console.log("后一个兄弟元素:", element.nextElementSibling); +``` + +### 20. 节点集合类型 + +**知识点**:理解不同返回类型的区别。 + +```javascript +// HTMLCollection - 动态集合 +const htmlCollection = document.getElementsByTagName("div"); +console.log("HTMLCollection长度:", htmlCollection.length); +// 注意:HTMLCollection是实时的,DOM变化会自动更新 + +// NodeList - 可能是静态或动态的 +const nodeListStatic = document.querySelectorAll(".item"); // 静态 +const nodeListDynamic = document.getElementsByName("email"); // 动态 + +// 转换类型 +const arrayFromHTMLCollection = Array.from(htmlCollection); +const arrayFromNodeList = [...nodeListStatic]; + +// 遍历方法 +// NodeList有forEach方法 +nodeListStatic.forEach((item) => console.log(item)); + +// HTMLCollection没有forEach,需要转换 +Array.from(htmlCollection).forEach((item) => console.log(item)); +``` + +--- + +## 与 DHTML 对应的 DOM 操作 + +### 21. DHTML 概念 + +**知识点**:DHTML(Dynamic HTML)是使用 HTML、CSS 和 JavaScript 创建交互式网页的技术。 + +```javascript +// DHTML 三要素 +const html = document.getElementById("content").innerHTML; // HTML +const css = document.styleSheets[0].cssRules; // CSS +const js = document.querySelector("script").textContent; // JavaScript +``` + +### 22. 动态内容修改 + +**知识点**:动态改变 HTML 内容。 + +```javascript +// 传统DHTML方式 +document.getElementById("output").innerHTML = + "动态内容已更新"; + +// 现代DOM方式(更安全) +const output = document.getElementById("output"); +output.textContent = ""; // 清空内容 + +const strong = document.createElement("strong"); +strong.textContent = "动态内容"; +output.appendChild(strong); + +const em = document.createElement("em"); +em.textContent = "已更新"; +output.appendChild(em); +``` + +### 23. 动态样式修改 + +**知识点**:动态改变元素样式。 + +```javascript +const element = document.getElementById("dynamic-style"); + +// DHTML方式(直接设置style属性) +element.style.color = "red"; +element.style.fontSize = "20px"; +element.style.backgroundColor = "yellow"; + +// 现代方式(使用classList) +element.classList.add("highlight", "animated"); +element.classList.remove("hidden"); + +// 切换样式 +element.classList.toggle("active"); + +// 批量修改样式 +element.style.cssText = "color: blue; font-size: 18px; border: 1px solid;"; +``` + +### 24. 动态定位和大小 + +**知识点**:动态改变元素位置和尺寸。 + +```javascript +const box = document.getElementById("movable-box"); + +// 设置位置 +box.style.position = "absolute"; +box.style.left = "100px"; +box.style.top = "50px"; + +// 设置尺寸 +box.style.width = "200px"; +box.style.height = "150px"; + +// 获取元素位置和尺寸 +const rect = box.getBoundingClientRect(); +console.log("位置:", rect.left, rect.top); +console.log("尺寸:", rect.width, rect.height); +console.log("视口相对位置:", rect.x, rect.y); +``` + +### 25. 显示/隐藏元素 + +**知识点**:动态控制元素的可见性。 + +```javascript +const element = document.getElementById("toggle-element"); + +// 显示元素 +element.style.display = "block"; +element.style.visibility = "visible"; +element.classList.remove("hidden"); + +// 隐藏元素 +element.style.display = "none"; // 不占位 +element.style.visibility = "hidden"; // 占位但不可见 +element.classList.add("hidden"); // CSS类控制 + +// 切换显示状态 +function toggleVisibility() { + element.style.display = element.style.display === "none" ? "block" : "none"; +} + +// 检查是否可见 +const isVisible = element.offsetWidth > 0 && element.offsetHeight > 0; +``` + +### 26. 动态创建和插入 + +**知识点**:动态创建和插入元素。 + +```javascript +// 创建新元素 +const newDiv = document.createElement("div"); +newDiv.id = "new-element"; +newDiv.className = "box highlight"; +newDiv.textContent = "动态创建的元素"; + +// 插入到不同位置 +const container = document.getElementById("container"); + +// 添加到末尾 +container.appendChild(newDiv); + +// 添加到开头 +const firstChild = container.firstElementChild; +container.insertBefore(newDiv, firstChild); + +// 替换元素 +const oldElement = document.getElementById("old"); +container.replaceChild(newDiv, oldElement); + +// 插入到指定元素之后 +const reference = document.getElementById("reference"); +reference.parentNode.insertBefore(newDiv, reference.nextSibling); +``` + +### 27. 事件处理 + +**知识点**:DHTML 的事件处理模型。 + +```javascript +const button = document.getElementById("action-button"); + +// 传统DHTML事件处理 +button.onclick = function (event) { + console.log("按钮被点击了"); + alert("传统事件处理"); +}; + +// 现代DOM事件处理 +button.addEventListener("click", function (event) { + console.log("事件类型:", event.type); + console.log("目标元素:", event.target); + console.log("当前元素:", event.currentTarget); + + // 阻止默认行为 + event.preventDefault(); + + // 停止事件传播 + event.stopPropagation(); +}); + +// 事件委托(DHTML常用模式) +document.getElementById("list").onclick = function (event) { + if (event.target.tagName === "LI") { + event.target.classList.toggle("selected"); + } +}; +``` + +### 28. 表单动态操作 + +**知识点**:动态操作表单元素。 + +```javascript +const form = document.forms["user-form"]; + +// 动态修改表单字段 +form.elements["username"].value = "新用户名"; +form.elements["email"].disabled = false; + +// 动态添加选项 +const select = document.getElementById("city-select"); +const newOption = document.createElement("option"); +newOption.value = "beijing"; +newOption.textContent = "北京"; +select.appendChild(newOption); + +// 动态设置单选/复选框 +document.querySelector('input[name="gender"][value="female"]').checked = true; +document.getElementById("subscribe").checked = false; + +// 动态验证 +form.onsubmit = function (event) { + if (!form.elements["username"].value) { + alert("用户名不能为空"); + event.preventDefault(); + return false; + } + return true; +}; +``` + +### 29. 动态表格操作 + +**知识点**:动态创建和操作表格。 + +```javascript +// 创建表格 +const table = document.createElement("table"); +table.className = "data-table"; +table.border = "1"; + +// 创建表头 +const thead = table.createTHead(); +const headerRow = thead.insertRow(); +["ID", "姓名", "年龄"].forEach((text) => { + const th = document.createElement("th"); + th.textContent = text; + headerRow.appendChild(th); +}); + +// 创建表格主体 +const tbody = table.createTBody(); + +// 添加数据行 +const data = [ + { id: 1, name: "张三", age: 25 }, + { id: 2, name: "李四", age: 30 }, +]; + +data.forEach((item) => { + const row = tbody.insertRow(); + row.insertCell().textContent = item.id; + row.insertCell().textContent = item.name; + row.insertCell().textContent = item.age; + + // 添加行点击事件 + row.onclick = function () { + this.classList.toggle("selected"); + }; +}); + +// 添加到页面 +document.getElementById("table-container").appendChild(table); +``` + +### 30. 动态内容过滤和搜索 + +**知识点**:实现 DHTML 常见的过滤和搜索功能。 + +```javascript +// 实时搜索过滤 +function filterList(searchTerm) { + const items = document.querySelectorAll(".list-item"); + const term = searchTerm.toLowerCase(); + + items.forEach((item) => { + const text = item.textContent.toLowerCase(); + const isVisible = text.includes(term); + item.style.display = isVisible ? "block" : "none"; + }); +} + +// 动态排序 +function sortList(sortBy) { + const container = document.getElementById("item-list"); + const items = Array.from(container.children); + + items.sort((a, b) => { + const aValue = a.getAttribute(`data-${sortBy}`); + const bValue = b.getAttribute(`data-${sortBy}`); + return aValue.localeCompare(bValue); + }); + + // 重新添加排序后的元素 + items.forEach((item) => container.appendChild(item)); +} + +// 分页功能 +function showPage(pageNumber, pageSize) { + const allItems = document.querySelectorAll(".data-item"); + const startIndex = (pageNumber - 1) * pageSize; + const endIndex = startIndex + pageSize; + + allItems.forEach((item, index) => { + item.style.display = + index >= startIndex && index < endIndex ? "block" : "none"; + }); +} +``` + +### 31. 动画效果 + +**知识点**:使用 DOM 操作实现动画效果。 + +```javascript +// 简单动画函数 +function animate(element, property, targetValue, duration) { + const startValue = parseFloat(getComputedStyle(element)[property]); + const change = targetValue - startValue; + const startTime = performance.now(); + + function update(currentTime) { + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // 缓动函数 + const easeProgress = + progress < 0.5 + ? 2 * progress * progress + : -1 + (4 - 2 * progress) * progress; + + const currentValue = startValue + change * easeProgress; + element.style[property] = currentValue + "px"; + + if (progress < 1) { + requestAnimationFrame(update); + } + } + + requestAnimationFrame(update); +} + +// 使用动画 +const box = document.getElementById("animated-box"); +animate(box, "left", 300, 1000); // 1秒内移动到300px +``` + +### 32. 拖放功能 + +**知识点**:实现 DHTML 拖放效果。 + +```javascript +// 简单拖放实现 +let draggedElement = null; + +document.addEventListener("mousedown", function (event) { + if (event.target.classList.contains("draggable")) { + draggedElement = event.target; + draggedElement.style.opacity = "0.5"; + } +}); + +document.addEventListener("mousemove", function (event) { + if (draggedElement) { + draggedElement.style.position = "absolute"; + draggedElement.style.left = event.pageX + "px"; + draggedElement.style.top = event.pageY + "px"; + } +}); + +document.addEventListener("mouseup", function (event) { + if (draggedElement) { + draggedElement.style.opacity = "1"; + + // 检查是否拖放到目标区域 + const dropZone = document.elementFromPoint(event.clientX, event.clientY); + if (dropZone.classList.contains("drop-zone")) { + dropZone.appendChild(draggedElement); + } + + draggedElement = null; + } +}); +``` + +--- + +## DOM 核心方法总结 + +### 33. 创建方法 + +```javascript +// 创建元素 +const element = document.createElement("div"); + +// 创建文本节点 +const textNode = document.createTextNode("文本内容"); + +// 创建注释 +const comment = document.createComment("注释"); + +// 创建文档片段 +const fragment = document.createDocumentFragment(); + +// 创建属性节点(不常用) +const attr = document.createAttribute("data-custom"); +``` + +### 34. 查找方法 + +```javascript +// 精确查找 +getElementById(id) // 通过ID +getElementsByName(name) // 通过name属性 +getElementsByClassName(class) // 通过类名 +getElementsByTagName(tag) // 通过标签名 + +// 选择器查找 +querySelector(selector) // 第一个匹配元素 +querySelectorAll(selector) // 所有匹配元素 + +// 遍历查找 +parentNode / parentElement // 父节点/父元素 +childNodes / children // 子节点/子元素 +firstChild / firstElementChild // 第一个子节点/元素 +lastChild / lastElementChild // 最后一个子节点/元素 +previousSibling / previousElementSibling // 前一个兄弟 +nextSibling / nextElementSibling // 后一个兄弟 +``` + +### 35. 操作方法 + +```javascript +// 添加和插入 +appendChild(node); // 添加子节点 +insertBefore(newNode, refNode); // 在指定节点前插入 + +// 移除和替换 +removeChild(node); // 移除子节点 +replaceChild(newNode, oldNode); // 替换子节点 + +// 克隆 +cloneNode(deep); // 克隆节点 + +// 包含检查 +contains(node); // 检查是否包含指定节点 +compareDocumentPosition(node); // 比较节点位置关系 +``` + +### 36. 属性方法 + +```javascript +// 属性操作 +setAttribute(name, value); // 设置属性 +getAttribute(name); // 获取属性值 +removeAttribute(name); // 移除属性 +hasAttribute(name); // 检查是否有属性 + +// 类名操作 +classList.add(className); // 添加类 +classList.remove(className); // 移除类 +classList.toggle(className); // 切换类 +classList.contains(className); // 检查类 +``` + +### 37. 事件方法 + +```javascript +// 事件监听 +addEventListener(type, handler, options) // 添加事件监听 +removeEventListener(type, handler, options) // 移除事件监听 + +// 事件触发 +dispatchEvent(event) // 触发事件 + +// 事件属性 +onclick / onmouseover 等 // 传统事件处理属性 +``` + +### 38. 样式方法 + +```javascript +// 内联样式 +element.style.property = value; // 设置样式 +element.style.cssText; // 批量设置样式 + +// 计算样式 +getComputedStyle(element); // 获取计算后的样式 + +// 类样式 +element.className; // 获取/设置类名 +element.classList; // 类列表操作 +``` + +--- + +## 📌 最佳实践总结 + +### 39. 性能优化 + +```javascript +// 1. 批量操作DOM +const fragment = document.createDocumentFragment(); +for (let i = 0; i < 100; i++) { + const item = document.createElement("div"); + fragment.appendChild(item); +} +container.appendChild(fragment); + +// 2. 缓存DOM查询结果 +const element = document.getElementById("my-element"); +// 多次使用element,而不是重复查询 + +// 3. 使用事件委托 +document.getElementById("list").addEventListener("click", function (event) { + if (event.target.tagName === "LI") { + // 处理列表项点击 + } +}); +``` + +### 40. 兼容性处理 + +```javascript +// 检查方法是否存在 +if (document.addEventListener) { + // 标准方法 + element.addEventListener("click", handler); +} else if (document.attachEvent) { + // IE8及以下 + element.attachEvent("onclick", handler); +} + +// 使用polyfill +if (!Element.prototype.classList) { + // 实现classList的polyfill +} +``` + +--- + +## 🎯 DOM 核心要点速查表 + +| 类别 | 常用方法/属性 | 描述 | +| -------- | ----------------------- | -------------- | +| **创建** | `createElement()` | 创建元素节点 | +| | `createTextNode()` | 创建文本节点 | +| **查找** | `getElementById()` | ID 查找 | +| | `querySelector()` | CSS 选择器查找 | +| **遍历** | `parentNode` | 父节点 | +| | `children` | 子元素集合 | +| **操作** | `appendChild()` | 添加子节点 | +| | `removeChild()` | 移除子节点 | +| **属性** | `setAttribute()` | 设置属性 | +| | `classList` | 类名操作 | +| **样式** | `style` | 内联样式 | +| | `getComputedStyle()` | 计算样式 | +| **事件** | `addEventListener()` | 添加事件监听 | +| | `removeEventListener()` | 移除事件监听 | + +--- + +# 训练 + +```html + + + + +

    训练一

    + + + +
    + +

    训练二

    +
    + 故事的小黄花
    + 从出生那年就飘着
    + 童年的荡秋千
    + 随记忆一直晃到现在
    + Re So So Si Do Si La
    + So La Si Si Si Si La Si La So
    + 吹着前奏望着天空
    + 我想起花瓣试着掉落
    + 为你翘课的那一天
    + 花落的那一天
    + 教室的那一间
    + 我怎么看不见
    + 消失的下雨天
    + 我好想再淋一遍
    +
    + + + +

    第三题

    +

    最新电影资讯

    +
      +
    • 1.《金蝉脱壳》
    • +
    • 2.《阿甘正传》
    • +
    • 3.《爱乐之城》
    • +
    • 4.《头号玩家》
    • +
    + 输入影片资讯编号: + + + +

    第四题

    +
    +
      +
    • 黄瓜
    • +
    • 茄子
    • +
    • 芒果
    • +
    +
      +
    • 西瓜
    • +
    • 蜜橘
    • +
    • 萝卜
    • +
    +
    + + +

    第五题

    +

    在《倚天屠龙记》中,张三丰是_____派的掌门?

    + A.少林 + B.武当 + C.峨眉 + D.昆仑 + + +

    第六题

    + 原超链接文本 + + + +``` + +# 练习 + +```html +
    +

    一生只爱一人

    + 将粗体改为斜体 +
    + + + + + +
    请选择表情:
    + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251205-window\345\257\271\350\261\241.md" "b/\344\270\245\345\201\245\345\256\207/20251205-window\345\257\271\350\261\241.md" new file mode 100644 index 000000000..dcdd31e88 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251205-window\345\257\271\350\261\241.md" @@ -0,0 +1,1623 @@ +# JavaScript Window 对象全面知识点总结 + +## 📋 目录 + +1. [Window 对象简介](#window-对象简介) +2. [对话框方法](#对话框方法) +3. [窗口的打开与关闭](#窗口的打开与关闭) +4. [控制窗口](#控制窗口) +5. [窗口事件](#窗口事件) +6. [窗口导航与历史](#窗口导航与历史) +7. [窗口尺寸与位置](#窗口尺寸与位置) +8. [定时器与动画](#定时器与动画) + +--- + +## Window 对象简介 + +### 1. Window 对象是什么? + +**知识点**:Window 对象代表浏览器窗口,是 JavaScript 的全局对象,包含所有全局变量、函数和对象。 + +```javascript +// Window 对象是全局对象 +console.log(window === this); // 在全局作用域中为 true + +// 全局变量自动成为 window 的属性 +var globalVar = "全局变量"; +console.log(window.globalVar); // "全局变量" + +// 全局函数也是 window 的方法 +function sayHello() { + return "Hello"; +} +console.log(window.sayHello()); // "Hello" +``` + +### 2. Window 对象与其他对象的关系 + +**知识点**:Window 对象包含 document、location、history、navigator 等子对象。 + +```javascript +// Window 的子对象 +console.log(window.document); // Document 对象 +console.log(window.location); // Location 对象 +console.log(window.history); // History 对象 +console.log(window.navigator); // Navigator 对象 +console.log(window.screen); // Screen 对象 +console.log(window.localStorage); // Storage 对象 + +// 访问时可以省略 window 前缀 +console.log(document === window.document); // true +console.log(location === window.location); // true +``` + +### 3. 全局作用域 + +**知识点**:在浏览器中,全局作用域就是 Window 对象。 + +```javascript +// 检查变量是否在全局作用域中 +var x = 10; +let y = 20; // let/const 声明的变量不会成为 window 的属性 +const z = 30; + +console.log(window.x); // 10 +console.log(window.y); // undefined +console.log(window.z); // undefined + +// 在严格模式下,this 在全局作用域中为 undefined +("use strict"); +console.log(this); // undefined (非严格模式下为 window) +``` + +--- + +## 对话框方法 + +### 4. alert() 方法 + +**知识点**:显示一个警告对话框,包含指定的消息和一个"确定"按钮。 + +```javascript +// 基本用法 +alert("这是一个警告信息"); + +// 显示变量值 +let userName = "张三"; +alert(`欢迎, ${userName}!`); + +// 显示对象信息 +let user = { name: "李四", age: 25 }; +alert(JSON.stringify(user, null, 2)); + +// 注意:alert 会阻塞代码执行 +console.log("这行代码在 alert 关闭后执行"); +``` + +### 5. confirm() 方法 + +**知识点**:显示一个确认对话框,包含指定的消息和"确定"/"取消"按钮,返回布尔值。 + +```javascript +// 基本用法 +let result = confirm("您确定要删除此项吗?"); +console.log("用户选择:", result); // true 或 false + +// 根据选择执行不同操作 +if (confirm("是否继续?")) { + console.log("用户选择了继续"); + // 执行继续操作 +} else { + console.log("用户选择了取消"); + // 执行取消操作 +} + +// 使用在三元表达式中 +let action = confirm("启用高级功能?") ? "启用" : "禁用"; +console.log("操作:", action); +``` + +### 6. prompt() 方法 + +**知识点**:显示一个提示对话框,包含输入框和"确定"/"取消"按钮,返回输入值或 null。 + +```javascript +// 基本用法 +let name = prompt("请输入您的姓名:"); +console.log("输入的姓名:", name); + +// 带默认值 +let age = prompt("请输入您的年龄:", "25"); +console.log("输入的年龄:", age); + +// 验证输入 +let input; +do { + input = prompt("请输入一个数字(1-10):"); +} while (input === null || isNaN(input) || input < 1 || input > 10); + +console.log("有效的输入:", input); + +// 处理取消操作 +let email = prompt("请输入邮箱:"); +if (email === null) { + console.log("用户取消了输入"); +} else if (email.trim() === "") { + console.log("用户输入了空字符串"); +} else { + console.log("用户输入:", email); +} +``` + +### 7. 自定义对话框 + +**知识点**:使用 DOM 创建更灵活的自定义对话框。 + +```javascript +// 创建自定义确认对话框 +function customConfirm(message, callback) { + // 创建对话框元素 + const dialog = document.createElement("div"); + dialog.style.cssText = ` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + padding: 20px; + border: 2px solid #333; + border-radius: 5px; + z-index: 1000; + `; + + dialog.innerHTML = ` +

    ${message}

    + + + `; + + document.body.appendChild(dialog); + + // 添加事件处理 + document.getElementById("confirmOk").onclick = function () { + document.body.removeChild(dialog); + callback(true); + }; + + document.getElementById("confirmCancel").onclick = function () { + document.body.removeChild(dialog); + callback(false); + }; +} + +// 使用自定义对话框 +customConfirm("是否确认操作?", function (result) { + console.log("用户选择:", result); +}); +``` + +--- + +## 窗口的打开与关闭 + +### 8. window.open() 方法 + +**知识点**:打开一个新的浏览器窗口或标签页。 + +```javascript +// 基本用法 - 在新标签页中打开 +const newWindow = window.open("https://www.example.com"); + +// 指定窗口名称(可用于 target 属性) +window.open("page.html", "myWindow"); + +// 在新窗口中打开(不是新标签页) +const popup = window.open("popup.html", "popup", "width=400,height=300"); + +// 控制是否显示浏览器控件 +const minimalWindow = window.open( + "minimal.html", + "minimal", + "menubar=no,toolbar=no,location=no,status=no" +); + +// 获取打开的窗口引用 +const myWindow = window.open("", "myWindow"); +if (myWindow) { + myWindow.document.write("

    Hello from opener!

    "); +} +``` + +### 9. 窗口打开参数 + +**知识点**:window.open() 的第三个参数控制窗口特性。 + +```javascript +// 完整的窗口特性参数 +const features = [ + "width=800", // 窗口宽度 + "height=600", // 窗口高度 + "left=100", // 距离屏幕左边缘 + "top=100", // 距离屏幕上边缘 + "resizable=yes", // 是否可调整大小 + "scrollbars=yes", // 是否显示滚动条 + "toolbar=no", // 是否显示工具栏 + "menubar=no", // 是否显示菜单栏 + "location=no", // 是否显示地址栏 + "status=no", // 是否显示状态栏 + "fullscreen=no", // 是否全屏(需要用户交互) +].join(","); + +const configuredWindow = window.open("config.html", "config", features); + +// 检查窗口是否成功打开 +if (!configuredWindow) { + alert("弹出窗口被浏览器阻止了!请允许弹出窗口。"); +} +``` + +### 10. window.close() 方法 + +**知识点**:关闭当前窗口或指定的窗口。 + +```javascript +// 关闭当前窗口 +function closeCurrentWindow() { + if (confirm("确定要关闭窗口吗?")) { + window.close(); + } +} + +// 关闭由 window.open() 打开的窗口 +let openedWindow = null; + +function openAndClose() { + // 打开新窗口 + openedWindow = window.open("", "testWindow", "width=400,height=300"); + + // 在新窗口中写入内容 + openedWindow.document.write("

    这个窗口将在5秒后关闭

    "); + + // 5秒后关闭窗口 + setTimeout(() => { + if (openedWindow && !openedWindow.closed) { + openedWindow.close(); + console.log("窗口已关闭"); + } + }, 5000); +} + +// 检查窗口是否已关闭 +if (openedWindow && openedWindow.closed) { + console.log("窗口已经关闭了"); +} +``` + +### 11. 窗口状态检测 + +**知识点**:检测窗口的打开和关闭状态。 + +```javascript +let childWindow = null; + +// 打开子窗口 +function openChildWindow() { + childWindow = window.open("child.html", "child", "width=400,height=300"); + + // 定期检查子窗口是否关闭 + const checkInterval = setInterval(() => { + if (childWindow.closed) { + console.log("子窗口已关闭"); + clearInterval(checkInterval); + // 执行清理操作 + childWindow = null; + } + }, 1000); +} + +// 与子窗口通信 +function sendMessageToChild() { + if (childWindow && !childWindow.closed) { + // 向子窗口传递数据 + childWindow.postMessage("Hello from parent!", "*"); + + // 调用子窗口的函数(如果同源) + try { + childWindow.someFunction(); + } catch (e) { + console.log("跨域限制或函数不存在"); + } + } else { + console.log("子窗口未打开或已关闭"); + } +} +``` + +--- + +## 控制窗口 + +### 12. 移动窗口 + +**知识点**:移动窗口到指定位置。 + +```javascript +// 移动当前窗口 +function moveWindowTo(x, y) { + // 注意:现代浏览器出于安全考虑,通常不允许脚本移动主窗口 + // 但可以移动由 window.open() 打开的窗口 + + if (window.opener) { + // 如果这是由其他窗口打开的 + window.moveTo(x, y); + } +} + +// 移动由脚本打开的窗口 +let movableWindow = null; + +function createMovableWindow() { + movableWindow = window.open("", "movable", "width=300,height=200"); + + // 添加控制按钮 + movableWindow.document.write(` +

    可移动窗口

    + + + `); +} + +// 相对移动 +function moveWindowRelative(dx, dy) { + if (movableWindow && !movableWindow.closed) { + movableWindow.moveBy(dx, dy); + } +} +``` + +### 13. 调整窗口大小 + +**知识点**:调整窗口的尺寸。 + +```javascript +// 调整当前窗口大小 +function resizeCurrentWindow(width, height) { + // 注意:通常不能调整主窗口大小 + // 但可以调整由 window.open() 打开的窗口 + window.resizeTo(width, height); +} + +// 调整由脚本打开的窗口 +let resizableWindow = null; + +function createResizableWindow() { + resizableWindow = window.open( + "", + "resizable", + "width=400,height=300,resizable=yes" + ); + + // 添加控制按钮 + resizableWindow.document.write(` +

    可调整大小的窗口

    + + + + `); +} + +// 检查窗口是否可以调整大小 +function checkIfResizable() { + if (resizableWindow) { + // 注意:没有直接的方法检查,但可以尝试调整 + try { + resizableWindow.resizeBy(1, 1); + resizableWindow.resizeBy(-1, -1); // 恢复 + console.log("窗口可以调整大小"); + return true; + } catch (e) { + console.log("窗口不能调整大小"); + return false; + } + } + return false; +} +``` + +### 14. 窗口滚动控制 + +**知识点**:控制窗口的滚动位置。 + +```javascript +// 滚动到指定位置 +function scrollToPosition(x, y) { + window.scrollTo(x, y); + + // 或使用选项对象 + window.scrollTo({ + top: y, + left: x, + behavior: "smooth", // 'auto' 或 'smooth' + }); +} + +// 滚动到元素 +function scrollToElement(elementId) { + const element = document.getElementById(elementId); + if (element) { + element.scrollIntoView({ + behavior: "smooth", + block: "start", // 'start', 'center', 'end', 'nearest' + }); + } +} + +// 相对滚动 +function scrollByAmount(dx, dy) { + window.scrollBy(dx, dy); + + // 平滑滚动 + window.scrollBy({ + top: dy, + left: dx, + behavior: "smooth", + }); +} + +// 获取当前滚动位置 +function getScrollPosition() { + return { + x: window.pageXOffset || document.documentElement.scrollLeft, + y: window.pageYOffset || document.documentElement.scrollTop, + }; +} + +// 滚动到页面顶部 +function scrollToTop() { + window.scrollTo({ top: 0, behavior: "smooth" }); +} + +// 滚动到页面底部 +function scrollToBottom() { + window.scrollTo({ + top: document.documentElement.scrollHeight, + behavior: "smooth", + }); +} +``` + +### 15. 窗口焦点控制 + +**知识点**:控制窗口的焦点状态。 + +```javascript +// 将焦点设置到当前窗口 +function focusWindow() { + window.focus(); + console.log("窗口已获得焦点"); +} + +// 使窗口失去焦点 +function blurWindow() { + window.blur(); + console.log("窗口已失去焦点"); +} + +// 检查窗口是否有焦点 +function checkWindowFocus() { + if (document.hasFocus()) { + console.log("当前窗口有焦点"); + return true; + } else { + console.log("当前窗口没有焦点"); + return false; + } +} + +// 焦点变化示例 +let lastFocusTime = Date.now(); + +window.addEventListener("focus", () => { + const now = Date.now(); + const awayTime = now - lastFocusTime; + console.log(`窗口重新获得焦点,离开时间:${awayTime}ms`); +}); + +window.addEventListener("blur", () => { + lastFocusTime = Date.now(); + console.log("窗口失去焦点"); +}); + +// 自动聚焦输入框 +function autoFocusInput() { + const input = document.getElementById("myInput"); + if (input) { + input.focus(); + // 选中文本(可选) + input.select(); + } +} +``` + +--- + +## 窗口事件 + +### 16. load 事件 + +**知识点**:当整个页面及所有依赖资源(如图片、样式表)已完全加载时触发。 + +```javascript +// 使用 addEventListener +window.addEventListener("load", function () { + console.log("所有资源已完全加载"); + // 可以安全地操作DOM和资源 + const images = document.getElementsByTagName("img"); + console.log(`页面包含 ${images.length} 张图片`); +}); + +// 传统方式 +window.onload = function () { + console.log("页面加载完成(传统方式)"); + // 初始化应用 + initApp(); +}; + +// 图片加载完成后执行 +const img = new Image(); +img.src = "large-image.jpg"; +img.onload = function () { + console.log("大图片加载完成"); + document.body.appendChild(img); +}; +``` + +### 17. DOMContentLoaded 事件 + +**知识点**:当初始 HTML 文档完全加载和解析完成(不等待样式表、图片等)时触发。 + +```javascript +// 推荐使用 - 比 load 事件更快 +document.addEventListener("DOMContentLoaded", function () { + console.log("DOM 已完全加载和解析"); + // DOM 已就绪,可以操作元素 + const buttons = document.querySelectorAll("button"); + console.log(`找到 ${buttons.length} 个按钮`); + + // 添加事件监听器等 + buttons.forEach((btn) => { + btn.addEventListener("click", handleClick); + }); +}); + +// 传统方式 +document.onreadystatechange = function () { + if (document.readyState === "interactive") { + console.log("DOM 准备就绪(readystatechange)"); + } +}; +``` + +### 18. beforeunload 事件 + +**知识点**:在窗口、文档即将卸载时触发,可用于提示用户保存更改。 + +```javascript +// 提示用户离开前保存数据 +window.addEventListener("beforeunload", function (event) { + // 如果有未保存的更改 + if (hasUnsavedChanges) { + // 标准方式 + event.preventDefault(); + // Chrome 需要设置 returnValue + event.returnValue = "您有未保存的更改,确定要离开吗?"; + return "您有未保存的更改,确定要离开吗?"; + } +}); + +// 传统方式 +window.onbeforeunload = function () { + if (hasUnsavedChanges) { + return "您有未保存的更改,确定要离开吗?"; + } +}; + +// 清除 beforeunload 处理程序 +function clearBeforeUnload() { + window.onbeforeunload = null; + // 或使用 removeEventListener +} +``` + +### 19. unload 事件 + +**知识点**:当文档或子资源正在被卸载时触发,用于清理操作。 + +```javascript +// 在页面卸载时执行清理 +window.addEventListener("unload", function () { + // 发送统计数据 + if (navigator.sendBeacon) { + const data = new FormData(); + data.append("event", "page_unload"); + data.append("time", Date.now()); + navigator.sendBeacon("/analytics", data); + } + + // 清理资源 + cleanupResources(); + + console.log("页面正在卸载"); +}); + +// 注意:unload 事件中不能使用同步的 alert/confirm/prompt +// 也不能阻止页面卸载 +``` + +### 20. resize 事件 + +**知识点**:当窗口大小改变时触发。 + +```javascript +// 监听窗口大小变化 +let resizeTimeout; +window.addEventListener("resize", function () { + // 防抖处理,避免频繁触发 + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { + console.log("窗口大小已改变"); + console.log("新尺寸:", window.innerWidth, "x", window.innerHeight); + + // 根据窗口大小调整布局 + adjustLayoutForScreenSize(); + }, 250); // 250ms 防抖延迟 +}); + +// 获取窗口尺寸 +function getWindowSize() { + return { + width: window.innerWidth || document.documentElement.clientWidth, + height: window.innerHeight || document.documentElement.clientHeight, + outerWidth: window.outerWidth, + outerHeight: window.outerHeight, + }; +} + +// 响应式设计检查 +function checkResponsiveBreakpoint() { + const width = window.innerWidth; + + if (width >= 1200) { + console.log("超大屏幕"); + } else if (width >= 992) { + console.log("大屏幕"); + } else if (width >= 768) { + console.log("中等屏幕"); + } else if (width >= 576) { + console.log("小屏幕"); + } else { + console.log("超小屏幕"); + } +} +``` + +### 21. scroll 事件 + +**知识点**:当窗口滚动时触发。 + +```javascript +// 监听滚动事件 +let lastScrollTop = 0; +window.addEventListener("scroll", function () { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + + // 检查滚动方向 + if (scrollTop > lastScrollTop) { + console.log("向下滚动"); + } else { + console.log("向上滚动"); + } + + lastScrollTop = scrollTop; + + // 无限滚动示例 + if (isNearBottom()) { + loadMoreContent(); + } + + // 固定导航栏 + toggleFixedNavbar(scrollTop); +}); + +// 检查是否接近底部 +function isNearBottom() { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollHeight = document.documentElement.scrollHeight; + const clientHeight = document.documentElement.clientHeight; + + // 距离底部 200px 时触发 + return scrollTop + clientHeight >= scrollHeight - 200; +} + +// 节流滚动事件(性能优化) +function throttleScroll(callback, delay) { + let isThrottled = false; + + return function () { + if (!isThrottled) { + callback(); + isThrottled = true; + setTimeout(() => { + isThrottled = false; + }, delay); + } + }; +} + +window.addEventListener( + "scroll", + throttleScroll(() => { + console.log("节流后的滚动处理"); + }, 100) +); // 每100ms最多执行一次 +``` + +### 22. focus 和 blur 事件 + +**知识点**:当窗口获得或失去焦点时触发。 + +```javascript +// 窗口获得焦点 +window.addEventListener("focus", function () { + console.log("窗口获得焦点"); + + // 恢复应用状态 + if (isAppPaused) { + resumeApp(); + } + + // 更新页面标题 + document.title = document.title.replace(" [未激活]", ""); +}); + +// 窗口失去焦点 +window.addEventListener("blur", function () { + console.log("窗口失去焦点"); + + // 暂停应用活动 + pauseApp(); + + // 更新页面标题提示 + if (!document.title.includes("[未激活]")) { + document.title += " [未激活]"; + } +}); + +// 检查当前焦点状态 +function checkFocusStatus() { + if (document.hasFocus()) { + console.log("当前窗口处于活动状态"); + return true; + } else { + console.log("当前窗口处于非活动状态"); + return false; + } +} + +// 页面可见性 API(更现代的替代方案) +document.addEventListener("visibilitychange", function () { + if (document.hidden) { + console.log("页面隐藏"); + } else { + console.log("页面可见"); + } +}); +``` + +### 23. hashchange 事件 + +**知识点**:当 URL 的哈希部分(#后面)改变时触发。 + +```javascript +// 监听哈希变化 +window.addEventListener("hashchange", function (event) { + console.log("哈希已改变"); + console.log("旧URL:", event.oldURL); + console.log("新URL:", event.newURL); + console.log("当前哈希:", window.location.hash); + + // 根据哈希更新页面内容 + const hash = window.location.hash.substring(1); // 去掉 # + if (hash) { + loadContent(hash); + } else { + loadDefaultContent(); + } +}); + +// 手动触发哈希变化 +function navigateToSection(sectionId) { + window.location.hash = sectionId; + // 或使用 history.pushState(不触发 hashchange) + // history.pushState(null, '', '#' + sectionId); +} + +// 初始化时检查哈希 +if (window.location.hash) { + const section = window.location.hash.substring(1); + loadContent(section); +} +``` + +### 24. message 事件 + +**知识点**:当窗口收到来自其他窗口的消息时触发(跨文档通信)。 + +```javascript +// 接收来自其他窗口的消息 +window.addEventListener("message", function (event) { + // 安全检查:检查消息来源 + const allowedOrigin = "https://trusted-site.com"; + if (event.origin !== allowedOrigin) { + console.warn("收到来自不受信任来源的消息:", event.origin); + return; + } + + console.log("收到消息:", event.data); + console.log("来源:", event.origin); + console.log("来源窗口:", event.source); + + // 处理消息 + if (event.data.type === "updateData") { + updateData(event.data.payload); + } + + // 可选:发送回复 + event.source.postMessage( + { + type: "acknowledge", + message: "消息已收到", + }, + event.origin + ); +}); + +// 向其他窗口发送消息 +function sendMessageToIframe() { + const iframe = document.getElementById("myIframe"); + if (iframe && iframe.contentWindow) { + iframe.contentWindow.postMessage( + { + type: "command", + action: "refresh", + }, + "https://iframe-origin.com" + ); + } +} + +// 向父窗口发送消息(如果在 iframe 中) +if (window.parent !== window) { + window.parent.postMessage( + { + type: "ready", + content: "iframe 已加载完成", + }, + "*" + ); // 注意:使用 '*' 有安全风险,生产环境应指定具体来源 +} +``` + +### 25. storage 事件 + +**知识点**:当 localStorage 或 sessionStorage 发生变化时触发(仅在同源的其他窗口中)。 + +```javascript +// 监听存储变化 +window.addEventListener("storage", function (event) { + console.log("存储发生变化:"); + console.log("键:", event.key); + console.log("旧值:", event.oldValue); + console.log("新值:", event.newValue); + console.log("URL:", event.url); + console.log("存储区域:", event.storageArea); + + // 更新应用状态 + if (event.key === "userPreferences") { + updatePreferences(JSON.parse(event.newValue)); + } +}); + +// 示例:在一个标签页中设置,在另一个标签页中监听 +function saveUserSettings(settings) { + localStorage.setItem("userPreferences", JSON.stringify(settings)); + console.log("设置已保存"); +} + +// 当前窗口的变化不会触发自己的 storage 事件 +// 只会在同源的其他窗口中触发 +``` + +--- + +## 窗口导航与历史 + +### 26. location 对象 + +**知识点**:window.location 对象包含当前 URL 的信息,并可用于导航。 + +```javascript +// 获取当前URL信息 +console.log("完整URL:", window.location.href); +console.log("协议:", window.location.protocol); // https: +console.log("主机:", window.location.host); // example.com:8080 +console.log("主机名:", window.location.hostname); // example.com +console.log("端口:", window.location.port); // 8080 +console.log("路径:", window.location.pathname); // /path/to/page +console.log("搜索参数:", window.location.search); // ?id=123 +console.log("哈希:", window.location.hash); // #section +console.log("来源:", window.location.origin); // https://example.com:8080 + +// 导航到新页面 +function navigateTo(url) { + window.location.href = url; // 最常用 + // 或 window.location = url; + // 或 window.location.assign(url); +} + +// 重定向到新页面(替换当前历史记录) +function redirectTo(url) { + window.location.replace(url); // 当前页面不会留在历史记录中 +} + +// 重新加载页面 +function reloadPage() { + window.location.reload(); // 重新加载 + // window.location.reload(true); // 强制从服务器重新加载(忽略缓存) +} + +// 获取URL参数 +function getUrlParams() { + const params = new URLSearchParams(window.location.search); + const id = params.get("id"); // 获取id参数 + const name = params.get("name"); // 获取name参数 + + console.log("ID:", id); + console.log("所有参数:", Object.fromEntries(params)); + return { id, name }; +} +``` + +### 27. history 对象 + +**知识点**:window.history 对象允许操作浏览器会话历史记录。 + +```javascript +// 前进和后退 +function goBack() { + window.history.back(); // 等同于点击后退按钮 + // 或 window.history.go(-1); +} + +function goForward() { + window.history.forward(); // 等同于点击前进按钮 + // 或 window.history.go(1); +} + +// 跳转到历史记录中的特定位置 +function goToHistory(index) { + window.history.go(index); // 正数前进,负数后退 +} + +// 添加历史记录(不会加载新页面) +function addHistoryState(state, title, url) { + window.history.pushState(state, title, url); + console.log("历史记录已添加:", url); +} + +// 替换当前历史记录 +function replaceHistoryState(state, title, url) { + window.history.replaceState(state, title, url); + console.log("历史记录已替换:", url); +} + +// 监听历史记录变化 +window.addEventListener("popstate", function (event) { + console.log("位置变化:", window.location.href); + console.log("状态:", event.state); + + // 根据状态更新页面内容 + if (event.state) { + loadContentBasedOnState(event.state); + } +}); + +// 单页应用(SPA)路由示例 +function navigateToPage(page) { + const state = { page: page, timestamp: Date.now() }; + const url = `/${page}`; + + // 添加历史记录 + history.pushState(state, "", url); + + // 加载页面内容(不刷新页面) + loadPageContent(page); +} +``` + +### 28. navigator 对象 + +**知识点**:window.navigator 对象包含有关浏览器的信息。 + +```javascript +// 浏览器信息 +console.log("用户代理:", navigator.userAgent); +console.log("平台:", navigator.platform); +console.log("语言:", navigator.language); +console.log("浏览器语言:", navigator.languages); +console.log("Cookie 启用:", navigator.cookieEnabled); +console.log("在线状态:", navigator.onLine); + +// 检测设备类型 +function detectDevice() { + const ua = navigator.userAgent; + + if (/mobile/i.test(ua)) { + return "mobile"; + } else if (/tablet/i.test(ua)) { + return "tablet"; + } else { + return "desktop"; + } +} + +// 检测浏览器 +function detectBrowser() { + const ua = navigator.userAgent; + + if (/chrome/i.test(ua) && !/edge/i.test(ua)) { + return "Chrome"; + } else if (/firefox/i.test(ua)) { + return "Firefox"; + } else if (/safari/i.test(ua) && !/chrome/i.test(ua)) { + return "Safari"; + } else if (/edge/i.test(ua)) { + return "Edge"; + } else if (/msie/i.test(ua) || /trident/i.test(ua)) { + return "IE"; + } else { + return "Unknown"; + } +} + +// 检查网络状态 +function checkNetworkStatus() { + if (navigator.onLine) { + console.log("设备在线"); + return true; + } else { + console.log("设备离线"); + return false; + } +} + +// 监听网络状态变化 +window.addEventListener("online", () => { + console.log("设备已连接到网络"); + // 重新同步数据 +}); + +window.addEventListener("offline", () => { + console.log("设备已断开网络"); + // 显示离线提示 +}); +``` + +--- + +## 窗口尺寸与位置 + +### 29. 获取窗口尺寸 + +**知识点**:获取窗口和屏幕的尺寸信息。 + +```javascript +// 获取视口尺寸(显示网页的区域) +function getViewportSize() { + return { + width: window.innerWidth, + height: window.innerHeight, + // 兼容性处理 + widthAlt: document.documentElement.clientWidth, + heightAlt: document.documentElement.clientHeight, + }; +} + +// 获取整个窗口尺寸(包括浏览器界面) +function getWindowOuterSize() { + return { + width: window.outerWidth, + height: window.outerHeight, + }; +} + +// 获取屏幕尺寸 +function getScreenSize() { + return { + width: screen.width, + height: screen.height, + availWidth: screen.availWidth, // 可用宽度(不包括任务栏等) + availHeight: screen.availHeight, // 可用高度 + colorDepth: screen.colorDepth, // 颜色深度 + pixelDepth: screen.pixelDepth, // 像素深度 + }; +} + +// 获取文档尺寸(整个页面内容) +function getDocumentSize() { + return { + width: document.documentElement.scrollWidth, + height: document.documentElement.scrollHeight, + }; +} + +// 响应式设计辅助函数 +function getBreakpoint() { + const width = window.innerWidth; + + if (width >= 1400) return "xxl"; + if (width >= 1200) return "xl"; + if (width >= 992) return "lg"; + if (width >= 768) return "md"; + if (width >= 576) return "sm"; + return "xs"; +} + +// 监听窗口尺寸变化 +function watchWindowSize(callback) { + let lastSize = getViewportSize(); + + window.addEventListener("resize", () => { + const newSize = getViewportSize(); + + if ( + newSize.width !== lastSize.width || + newSize.height !== lastSize.height + ) { + callback(newSize, lastSize); + lastSize = newSize; + } + }); +} +``` + +### 30. 获取窗口位置 + +**知识点**:获取窗口在屏幕上的位置。 + +```javascript +// 获取窗口相对于屏幕的位置 +function getWindowPosition() { + return { + screenX: window.screenX, // 窗口左上角X坐标 + screenY: window.screenY, // 窗口左上角Y坐标 + screenLeft: window.screenLeft, // 兼容性别名 + screenTop: window.screenTop, // 兼容性别名 + }; +} + +// 获取滚动位置 +function getScrollPosition() { + return { + x: window.pageXOffset || document.documentElement.scrollLeft, + y: window.pageYOffset || document.documentElement.scrollTop, + }; +} + +// 元素相对于视口的位置 +function getElementViewportPosition(element) { + const rect = element.getBoundingClientRect(); + return { + top: rect.top, + right: rect.right, + bottom: rect.bottom, + left: rect.left, + width: rect.width, + height: rect.height, + }; +} + +// 检查元素是否在视口中 +function isElementInViewport(element) { + const rect = element.getBoundingClientRect(); + const windowHeight = + window.innerHeight || document.documentElement.clientHeight; + const windowWidth = window.innerWidth || document.documentElement.clientWidth; + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= windowHeight && + rect.right <= windowWidth + ); +} + +// 检查元素是否部分可见 +function isElementPartiallyVisible(element) { + const rect = element.getBoundingClientRect(); + const windowHeight = + window.innerHeight || document.documentElement.clientHeight; + const windowWidth = window.innerWidth || document.documentElement.clientWidth; + + const vertInView = rect.top <= windowHeight && rect.bottom >= 0; + const horInView = rect.left <= windowWidth && rect.right >= 0; + + return vertInView && horInView; +} +``` + +--- + +## 定时器与动画 + +### 31. setTimeout() + +**知识点**:在指定的毫秒数后执行一次函数。 + +```javascript +// 基本用法 +setTimeout(() => { + console.log("3秒后执行"); +}, 3000); + +// 带参数的函数 +function greet(name) { + console.log(`Hello, ${name}!`); +} +setTimeout(greet, 2000, "张三"); + +// 清除定时器 +const timeoutId = setTimeout(() => { + console.log("这个不会执行"); +}, 5000); + +// 在2秒后清除定时器 +setTimeout(() => { + clearTimeout(timeoutId); + console.log("定时器已清除"); +}, 2000); + +// 模拟异步操作 +function simulateAsyncTask(duration) { + console.log(`任务开始,需要 ${duration}ms`); + + return new Promise((resolve) => { + setTimeout(() => { + console.log("任务完成"); + resolve("结果"); + }, duration); + }); +} +``` + +### 32. setInterval() + +**知识点**:按照指定的周期(毫秒)重复执行函数。 + +```javascript +// 基本用法 +let counter = 0; +const intervalId = setInterval(() => { + counter++; + console.log(`计数器: ${counter}`); + + if (counter >= 10) { + clearInterval(intervalId); + console.log("定时器已停止"); + } +}, 1000); // 每秒执行一次 + +// 时钟示例 +function startClock() { + const clockElement = document.getElementById("clock"); + + const updateClock = () => { + const now = new Date(); + const timeString = now.toLocaleTimeString(); + clockElement.textContent = timeString; + }; + + // 立即更新一次 + updateClock(); + + // 每秒更新一次 + return setInterval(updateClock, 1000); +} + +// 动画示例(简单实现) +function animateElement(element, duration) { + const start = Date.now(); + const startPosition = 0; + const endPosition = 300; + + const intervalId = setInterval(() => { + const elapsed = Date.now() - start; + const progress = Math.min(elapsed / duration, 1); + + // 线性动画 + const currentPosition = + startPosition + (endPosition - startPosition) * progress; + element.style.left = currentPosition + "px"; + + if (progress >= 1) { + clearInterval(intervalId); + console.log("动画完成"); + } + }, 16); // 约60fps +} + +// 轮询示例 +function pollServer() { + const pollInterval = 5000; // 5秒 + + const poll = () => { + fetch("/api/status") + .then((response) => response.json()) + .then((data) => { + console.log("服务器状态:", data); + // 处理数据 + }) + .catch((error) => { + console.error("轮询错误:", error); + }); + }; + + // 立即执行一次 + poll(); + + // 然后每5秒执行一次 + return setInterval(poll, pollInterval); +} +``` + +### 33. requestAnimationFrame() + +**知识点**:为动画优化的定时器,在浏览器重绘之前执行。 + +```javascript +// 基本用法 +function animate() { + // 动画逻辑 + updateAnimation(); + + // 请求下一帧 + requestAnimationFrame(animate); +} + +// 启动动画 +requestAnimationFrame(animate); + +// 平滑动画示例 +function smoothAnimate(element, property, startValue, endValue, duration) { + const startTime = performance.now(); + + function animateFrame(currentTime) { + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // 使用缓动函数 + const easeProgress = easeInOutCubic(progress); + const currentValue = startValue + (endValue - startValue) * easeProgress; + + element.style[property] = currentValue + "px"; + + if (progress < 1) { + requestAnimationFrame(animateFrame); + } + } + + requestAnimationFrame(animateFrame); +} + +// 缓动函数 +function easeInOutCubic(t) { + return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; +} + +// FPS计数器 +function createFPSCounter() { + let frameCount = 0; + let lastTime = performance.now(); + let fps = 0; + + function countFrame() { + frameCount++; + const currentTime = performance.now(); + + if (currentTime - lastTime >= 1000) { + fps = frameCount; + frameCount = 0; + lastTime = currentTime; + console.log(`FPS: ${fps}`); + } + + requestAnimationFrame(countFrame); + } + + requestAnimationFrame(countFrame); +} + +// 取消动画帧 +let animationFrameId; + +function startCustomAnimation() { + let position = 0; + + function animate() { + position += 1; + element.style.left = position + "px"; + + if (position < 300) { + animationFrameId = requestAnimationFrame(animate); + } + } + + animationFrameId = requestAnimationFrame(animate); +} + +function stopAnimation() { + if (animationFrameId) { + cancelAnimationFrame(animationFrameId); + console.log("动画已停止"); + } +} +``` + +--- + +## 📌 最佳实践总结 + +### 34. 窗口操作安全注意事项 + +```javascript +// 1. 弹出窗口通常会被浏览器阻止 +function safeOpenWindow(url) { + const newWindow = window.open(url); + + if ( + !newWindow || + newWindow.closed || + typeof newWindow.closed === "undefined" + ) { + // 弹出窗口被阻止 + console.warn("弹出窗口被浏览器阻止"); + // 提供备用方案 + window.location.href = url; // 在当前窗口打开 + return null; + } + + return newWindow; +} + +// 2. 用户交互后才能打开弹出窗口 +document.getElementById("openBtn").addEventListener("click", function () { + // 只有响应用户点击事件,弹出窗口才不会被阻止 + window.open("popup.html"); +}); + +// 3. 检查是否支持某些窗口特性 +function checkWindowFeaturesSupport() { + const features = { + localStorage: !!window.localStorage, + sessionStorage: !!window.sessionStorage, + geolocation: !!navigator.geolocation, + notifications: !!window.Notification, + serviceWorker: "serviceWorker" in navigator, + webSocket: "WebSocket" in window, + }; + + console.log("浏览器特性支持:", features); + return features; +} +``` + +### 35. 性能优化建议 + +```javascript +// 1. 防抖和节流窗口事件 +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +// 使用防抖的resize事件 +window.addEventListener( + "resize", + debounce(() => { + console.log("窗口大小已稳定"); + }, 250) +); + +// 2. 使用requestAnimationFrame替代setTimeout做动画 +function smoothAnimation() { + let start = null; + + function step(timestamp) { + if (!start) start = timestamp; + const progress = timestamp - start; + + // 更新动画 + element.style.left = Math.min(progress / 10, 200) + "px"; + + if (progress < 2000) { + requestAnimationFrame(step); + } + } + + requestAnimationFrame(step); +} + +// 3. 清理定时器防止内存泄漏 +class TimerManager { + constructor() { + this.timers = new Set(); + } + + setTimeout(callback, delay, ...args) { + const id = setTimeout( + () => { + this.timers.delete(id); + callback(...args); + }, + delay, + ...args + ); + + this.timers.add(id); + return id; + } + + clearAll() { + this.timers.forEach((id) => clearTimeout(id)); + this.timers.clear(); + } +} +``` + +--- + +## 🎯 Window 对象核心要点速查表 + +| 类别 | 方法/属性/事件 | 描述 | +| ------------ | ------------------------- | -------------- | +| **对话框** | `alert()` | 警告对话框 | +| | `confirm()` | 确认对话框 | +| | `prompt()` | 提示输入对话框 | +| **窗口控制** | `open()` | 打开新窗口 | +| | `close()` | 关闭窗口 | +| | `resizeTo()` | 调整窗口大小 | +| | `moveTo()` | 移动窗口 | +| **事件** | `load` | 页面完全加载 | +| | `DOMContentLoaded` | DOM 加载完成 | +| | `resize` | 窗口大小改变 | +| | `scroll` | 窗口滚动 | +| | `beforeunload` | 页面卸载前 | +| **定时器** | `setTimeout()` | 延迟执行 | +| | `setInterval()` | 间隔执行 | +| | `requestAnimationFrame()` | 动画帧 | +| **导航** | `location` | URL 操作 | +| | `history` | 历史记录 | +| | `navigator` | 浏览器信息 | +| **尺寸** | `innerWidth/Height` | 视口尺寸 | +| | `outerWidth/Height` | 窗口尺寸 | +| | `screen` | 屏幕信息 | + +--- -- Gitee From 03ef08ecf44f2ba274bba8d496dc7a94104989a3 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 14 Dec 2025 17:32:05 +0800 Subject: [PATCH 6/9] feat:zuoye --- ...71\350\261\241\346\250\241\345\236\213.md" | 283 +++++++++ ...20251210-style\345\261\236\346\200\247.md" | 480 +++++++++++++++ .../20251211-Form\345\257\271\350\261\241.md" | 563 ++++++++++++++++++ .../20251212-JSON.md" | 194 ++++++ 4 files changed, 1520 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251210-style\345\261\236\346\200\247.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251211-Form\345\257\271\350\261\241.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251212-JSON.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\344\270\245\345\201\245\345\256\207/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 000000000..7be3f2f20 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,283 @@ +# JavaScript 浏览器对象知识点总结 + +## 📍 location 对象 + +### 知识点 +1. **作用**:包含当前URL的信息,可用于获取和设置URL +2. **属性**: + - `href`:完整的URL + - `protocol`:协议(http:、https:) + - `host`:主机名和端口号 + - `hostname`:主机名 + - `port`:端口号 + - `pathname`:路径部分 + - `search`:查询字符串(?之后的部分) + - `hash`:锚点部分(#之后的部分) + - `origin`:协议+主机名+端口号 +3. **方法**: + - `assign(url)`:加载新文档 + - `replace(url)`:替换当前文档(不产生历史记录) + - `reload(force)`:重新加载当前页面 + - `toString()`:返回完整的URL + +### 示例 +```javascript +// 获取当前URL信息 +console.log('完整URL:', location.href); +console.log('协议:', location.protocol); +console.log('主机:', location.host); +console.log('路径:', location.pathname); +console.log('查询参数:', location.search); +console.log('锚点:', location.hash); +console.log('源:', location.origin); + +// 操作URL +// 1. 跳转到新页面(会产生历史记录) +location.assign('https://www.example.com'); + +// 2. 替换当前页面(不会产生历史记录) +location.replace('https://www.example.com'); + +// 3. 重新加载页面 +location.reload(); // 可能从缓存加载 +location.reload(true); // 强制从服务器重新加载 + +// 4. 修改URL的部分内容 +// 只修改hash,不会重新加载页面 +location.hash = '#section1'; + +// 只修改search,会重新加载页面 +location.search = '?page=2'; + +// 完整URL修改,会跳转到新页面 +location.href = 'https://newdomain.com/path'; +``` + +--- + +## 🧭 navigator 对象 + +### 知识点 +1. **作用**:包含浏览器的信息和状态 +2. **常用属性**: + - `userAgent`:用户代理字符串 + - `platform`:操作系统平台 + - `language`:浏览器主语言 + - `languages`:用户偏好的语言数组 + - `cookieEnabled`:是否启用cookie + - `onLine`:是否联网 + - `geolocation`:地理位置API + - `mediaDevices`:媒体设备API + - `hardwareConcurrency`:CPU核心数 +3. **常用方法**: + - `sendBeacon()`:异步发送数据到服务器 + - `clipboard`:剪贴板API + - `vibrate()`:设备振动(移动端) + +### 示例 +```javascript +// 浏览器信息检测 +console.log('用户代理:', navigator.userAgent); +console.log('操作系统:', navigator.platform); +console.log('主语言:', navigator.language); +console.log('支持语言:', navigator.languages); +console.log('Cookie启用:', navigator.cookieEnabled); +console.log('在线状态:', navigator.onLine); +console.log('CPU核心数:', navigator.hardwareConcurrency); + +// 特性检测(推荐方式) +if ('geolocation' in navigator) { + navigator.geolocation.getCurrentPosition(position => { + console.log('纬度:', position.coords.latitude); + console.log('经度:', position.coords.longitude); + }); +} + +if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { + // 可以访问摄像头/麦克风 +} + +// 发送数据到服务器(适合页面卸载时) +navigator.sendBeacon('/api/log', JSON.stringify({ + event: 'page_unload', + time: Date.now() +})); + +// 剪贴板操作 +if (navigator.clipboard) { + // 写入剪贴板 + navigator.clipboard.writeText('要复制的文本').then(() => { + console.log('复制成功'); + }); + + // 读取剪贴板 + navigator.clipboard.readText().then(text => { + console.log('剪贴板内容:', text); + }); +} + +// 设备振动(移动设备) +if ('vibrate' in navigator) { + // 振动200ms + navigator.vibrate(200); + // 模式:振动200ms,暂停100ms,振动300ms + navigator.vibrate([200, 100, 300]); +} +``` + +--- + +## 🖥️ screen 对象 + +### 知识点 +1. **作用**:包含屏幕/显示器的信息 +2. **属性**: + - `width` / `height`:屏幕的总宽度/高度 + - `availWidth` / `availHeight`:可用宽度/高度(减去任务栏等) + - `colorDepth`:颜色深度(位) + - `pixelDepth`:像素深度(位) + - `orientation`:屏幕方向 + - `availLeft` / `availTop`:可用空间的左边/上边坐标 + +### 示例 +```javascript +// 获取屏幕信息 +console.log('屏幕分辨率:', screen.width + 'x' + screen.height); +console.log('可用区域:', screen.availWidth + 'x' + screen.availHeight); +console.log('可用区域起点:', 'left=' + screen.availLeft + ', top=' + screen.availTop); +console.log('颜色深度:', screen.colorDepth + '位'); +console.log('像素深度:', screen.pixelDepth + '位'); + +// 屏幕方向检测 +if ('orientation' in screen) { + console.log('当前方向:', screen.orientation.type); + console.log('角度:', screen.orientation.angle); + + // 监听方向变化 + screen.orientation.addEventListener('change', () => { + console.log('方向变为:', screen.orientation.type); + }); +} + +// 响应式设计应用 +function checkScreenSize() { + if (screen.width < 768) { + console.log('小屏幕设备(手机)'); + } else if (screen.width < 1024) { + console.log('中等屏幕设备(平板)'); + } else { + console.log('大屏幕设备(桌面)'); + } +} + +// 检测是否高DPI屏幕(Retina) +const isRetina = window.devicePixelRatio > 1; +console.log('设备像素比:', window.devicePixelRatio); +console.log('是否高DPI:', isRetina); +``` + +--- + +## 📜 history 对象 + +### 知识点 +1. **作用**:操作浏览器会话历史 +2. **属性**: + - `length`:历史记录栈中的URL数量 + - `state`:当前历史记录状态对象 +3. **方法**: + - `back()`:后退到上一个页面 + - `forward()`:前进到下一个页面 + - `go(n)`:前进或后退n个页面 + - `pushState(state, title, url)`:添加历史记录 + - `replaceState(state, title, url)`:替换当前历史记录 + +### 示例 +```javascript +// 获取历史记录信息 +console.log('历史记录数量:', history.length); +console.log('当前状态:', history.state); + +// 基本导航 +// 后退一页(等价于点击后退按钮) +history.back(); + +// 前进一页(等价于点击前进按钮) +history.forward(); + +// 前进/后退多页 +history.go(-2); // 后退2页 +history.go(1); // 前进1页 +history.go(0); // 刷新当前页 + +// HTML5 History API +// 1. pushState - 添加新历史记录(不会加载页面) +const state1 = { page: 'home', data: { title: '首页' } }; +history.pushState(state1, '首页', '/home'); + +const state2 = { page: 'about', data: { title: '关于我们' } }; +history.pushState(state2, '关于我们', '/about'); + +// 2. replaceState - 替换当前历史记录 +const state3 = { page: 'contact', data: { title: '联系我们' } }; +history.replaceState(state3, '联系我们', '/contact'); + +// 监听popstate事件(用户点击前进/后退按钮时触发) +window.addEventListener('popstate', (event) => { + console.log('位置变化:', event.state); + console.log('当前URL:', location.href); + + // 根据state更新页面内容 + if (event.state) { + updateContent(event.state); + } +}); + +// 监听hashchange事件(hash变化时) +window.addEventListener('hashchange', () => { + console.log('Hash变为:', location.hash); +}); + +// 单页应用(SPA)路由示例 +function navigateTo(page, stateData) { + const state = { page, data: stateData }; + const title = stateData?.title || page; + const url = `/${page}`; + + history.pushState(state, title, url); + renderPage(page, stateData); +} + +function updateContent(state) { + switch(state.page) { + case 'home': + document.title = '首页 - 我的网站'; + document.getElementById('content').innerHTML = '

    欢迎来到首页

    '; + break; + case 'about': + document.title = '关于我们 - 我的网站'; + document.getElementById('content').innerHTML = '

    关于我们

    公司简介...

    '; + break; + case 'contact': + document.title = '联系我们 - 我的网站'; + document.getElementById('content').innerHTML = '

    联系我们

    联系方式...

    '; + break; + } +} + +// 初始化:处理直接访问或刷新 +window.addEventListener('load', () => { + const path = location.pathname.replace(/^\//, '') || 'home'; + navigateTo(path, { title: path === 'home' ? '首页' : path }); +}); +``` + +--- + +## 📌 注意事项 + +1. **兼容性**:部分API需要检查浏览器支持 +2. **隐私**:某些信息(如地理位置)需要用户授权 +3. **安全**:跨域访问有限制 +4. **SPA路由**:使用History API时需配置服务器支持 +5. **移动端**:注意移动设备的特性和限制 \ No newline at end of file diff --git "a/\344\270\245\345\201\245\345\256\207/20251210-style\345\261\236\346\200\247.md" "b/\344\270\245\345\201\245\345\256\207/20251210-style\345\261\236\346\200\247.md" new file mode 100644 index 000000000..7c988f552 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251210-style\345\261\236\346\200\247.md" @@ -0,0 +1,480 @@ +# JavaScript Style 对象知识点总结 + +## 🎨 style 对象简介 + +### 知识点 + +1. **作用**:用于操作 HTML 元素的样式 +2. **访问方式**: + - `element.style`:访问元素的**内联样式** + - 注意:只能获取和设置内联样式,不能获取 CSS 样式表中的样式 +3. **命名规则转换**: + - CSS 属性名:`background-color` + - JavaScript 属性名:`backgroundColor`(驼峰命名法) +4. **读取和设置**: + - 读取:`element.style.propertyName` + - 设置:`element.style.propertyName = value` + +### 示例 + +```javascript +// 获取元素 +const div = document.getElementById("myDiv"); + +// 设置单个样式属性 +div.style.backgroundColor = "red"; +div.style.fontSize = "16px"; + +// 读取样式(仅限内联样式) +console.log("背景色:", div.style.backgroundColor); +console.log("字体大小:", div.style.fontSize); + +// CSS属性名到JS属性名的转换示例 +const cssToJs = { + "background-color": "backgroundColor", + "font-size": "fontSize", + "border-radius": "borderRadius", + "z-index": "zIndex", + "margin-top": "marginTop", +}; + +// 批量设置样式的辅助函数 +function setStyles(element, styles) { + for (const [cssProp, value] of Object.entries(styles)) { + // 将CSS属性名转换为JS属性名 + const jsProp = cssProp.replace(/-([a-z])/g, (match, letter) => + letter.toUpperCase() + ); + element.style[jsProp] = value; + } +} + +// 使用辅助函数 +setStyles(div, { + "background-color": "blue", + "font-size": "20px", + "border-radius": "5px", +}); +``` + +--- + +## 🏷️ 样式标签属性和样式属性 + +### 知识点 + +1. **style 属性与 class 属性的区别**: + - `style`属性:直接设置内联样式 + - `class`属性:引用 CSS 类选择器 +2. **获取计算样式**: + - `window.getComputedStyle(element)`:获取元素最终应用的所有样式(包括 CSS 表和内联样式) + - `element.currentStyle`:IE8 及以下(已废弃) +3. **获取样式的方法对比**: + - `element.style.property`:仅内联样式 + - `window.getComputedStyle(element).property`:所有计算后的样式 + - `element.className`:获取 class 属性 + - `element.classList`:操作 class 列表的现代 API + +### 示例 + +```html + + + + + + +
    + Hello World +
    + + +``` + +```javascript +const element = document.getElementById("myElement"); + +// 1. 通过style属性获取(仅内联样式) +console.log("内联margin:", element.style.margin); // "20px" +console.log("内联color:", element.style.color); // ""(空,因为color来自CSS) + +// 2. 通过getComputedStyle获取(所有计算后的样式) +const computedStyle = window.getComputedStyle(element); +console.log("计算后的color:", computedStyle.color); // "rgb(0, 0, 255)" 或 "blue" +console.log("计算后的font-size:", computedStyle.fontSize); // "18px" +console.log("计算后的margin:", computedStyle.margin); // "20px" + +// 3. 操作class属性 +console.log("className:", element.className); // "highlight" + +// 添加类 +element.className += " extra-class"; + +// 更好的方式:使用classList +element.classList.add("new-class"); // 添加类 +element.classList.remove("highlight"); // 删除类 +element.classList.toggle("active"); // 切换类 +element.classList.contains("highlight"); // 检查是否包含类 + +// 4. 批量设置样式(使用cssText) +element.style.cssText = "color: red; font-size: 24px; padding: 15px;"; + +// 或在原有基础上添加 +element.style.cssText += " margin-bottom: 10px;"; + +// 5. 获取所有内联样式 +console.log("所有内联样式:", element.style.cssText); + +// 6. 移除单个样式 +element.style.margin = ""; // 设置为空字符串 + +// 7. 移除所有内联样式 +element.style.cssText = ""; +``` + +--- + +## 🔧 常用样式属性操作 + +### 知识点 + +1. **常用样式分类**: + + - 尺寸相关:width, height, margin, padding + - 位置相关:position, top, left, z-index + - 颜色背景:color, backgroundColor, backgroundImage + - 字体文本:fontSize, fontFamily, textAlign + - 边框轮廓:border, borderRadius, boxShadow + - 显示隐藏:display, visibility, opacity + - 变换动画:transform, transition + +2. **重要方法**: + - `style.setProperty(property, value, priority)`:设置 CSS 属性 + - `style.getPropertyValue(property)`:获取 CSS 属性值 + - `style.removeProperty(property)`:移除 CSS 属性 + +### 示例 + +```javascript +const box = document.getElementById("box"); + +// ============ 尺寸相关操作 ============ +box.style.width = "200px"; +box.style.height = "150px"; +box.style.margin = "20px auto"; +box.style.padding = "10px 15px"; + +// 使用setProperty方法(支持CSS原始属性名) +box.style.setProperty("width", "300px"); +box.style.setProperty("height", "200px"); + +// ============ 位置相关操作 ============ +box.style.position = "relative"; +box.style.top = "50px"; +box.style.left = "100px"; +box.style.zIndex = "10"; + +// ============ 颜色背景操作 ============ +box.style.backgroundColor = "#f0f0f0"; +box.style.color = "#333"; +box.style.backgroundImage = "linear-gradient(to right, #ff7e5f, #feb47b)"; + +// 透明度和渐变动画 +box.style.opacity = "0.8"; +box.style.transition = "all 0.3s ease"; + +// ============ 字体文本操作 ============ +box.style.fontSize = "16px"; +box.style.fontFamily = "Arial, sans-serif"; +box.style.fontWeight = "bold"; +box.style.textAlign = "center"; +box.style.lineHeight = "1.5"; + +// ============ 边框轮廓操作 ============ +box.style.border = "2px solid #ccc"; +box.style.borderRadius = "8px"; +box.style.boxShadow = "2px 2px 10px rgba(0,0,0,0.1)"; +box.style.outline = "none"; // 移除焦点轮廓 + +// ============ 显示隐藏操作 ============ +// 方法1: display(完全从文档流中移除) +box.style.display = "none"; // 隐藏 +box.style.display = "block"; // 显示(块级元素) + +// 方法2: visibility(保留位置) +box.style.visibility = "hidden"; // 隐藏但保留空间 +box.style.visibility = "visible"; // 显示 + +// 方法3: opacity(渐变隐藏) +box.style.opacity = "0"; // 完全透明 +box.style.opacity = "0.5"; // 半透明 +box.style.opacity = "1"; // 完全不透明 + +// ============ 变换动画操作 ============ +box.style.transform = "translateX(100px) rotate(45deg) scale(1.2)"; +box.style.transition = "transform 0.5s ease, opacity 0.3s ease"; + +// 动态添加动画 +setTimeout(() => { + box.style.transform = "translateX(0) rotate(0) scale(1)"; +}, 1000); + +// ============ 使用getPropertyValue ============ +console.log("获取宽度:", box.style.getPropertyValue("width")); +console.log("获取背景色:", box.style.getPropertyValue("background-color")); + +// ============ 使用removeProperty ============ +box.style.removeProperty("border"); // 移除边框 +box.style.removeProperty("box-shadow"); // 移除阴影 + +// ============ 响应式样式操作 ============ +function updateStylesForScreenSize() { + const width = window.innerWidth; + + if (width < 768) { + // 移动端样式 + box.style.width = "100%"; + box.style.padding = "10px"; + box.style.fontSize = "14px"; + } else if (width < 1024) { + // 平板端样式 + box.style.width = "80%"; + box.style.padding = "15px"; + box.style.fontSize = "16px"; + } else { + // 桌面端样式 + box.style.width = "60%"; + box.style.padding = "20px"; + box.style.fontSize = "18px"; + } +} + +// 监听窗口变化 +window.addEventListener("resize", updateStylesForScreenSize); + +// ============ 批量样式操作函数 ============ +function applyStyles(element, styles) { + for (const [property, value] of Object.entries(styles)) { + if (value === null || value === undefined) { + element.style.removeProperty(property); + } else { + element.style.setProperty(property, value); + } + } +} + +// 使用批量操作函数 +applyStyles(box, { + "--custom-property": "red", // CSS自定义属性 + width: "250px", + height: null, // 移除高度 + "background-color": "#e3f2fd", + border: "1px solid #90caf9", +}); + +// ============ CSS自定义变量操作 ============ +// 设置CSS变量 +box.style.setProperty("--primary-color", "#1976d2"); +box.style.setProperty("--border-radius", "10px"); + +// 使用CSS变量 +box.style.backgroundColor = "var(--primary-color)"; +box.style.borderRadius = "var(--border-radius)"; + +// ============ 动态样式类切换 ============ +// 根据条件应用不同的样式类 +function toggleTheme(isDarkMode) { + if (isDarkMode) { + box.classList.remove("light-theme"); + box.classList.add("dark-theme"); + } else { + box.classList.remove("dark-theme"); + box.classList.add("light-theme"); + } +} + +// ============ 性能优化建议 ============ +// 不好的做法:频繁修改单个样式 +for (let i = 0; i < 10; i++) { + box.style.left = `${i * 10}px`; // 触发10次重排 +} + +// 好的做法:批量修改,使用cssText或class +box.style.cssText = ` + left: 100px; + top: 50px; + transform: scale(1.5); +`; + +// 或使用requestAnimationFrame进行动画 +function animateElement() { + let position = 0; + + function step() { + position += 1; + box.style.transform = `translateX(${position}px)`; + + if (position < 100) { + requestAnimationFrame(step); + } + } + + requestAnimationFrame(step); +} +``` + +--- + +## 📌 注意事项 + +1. **性能优化**: + + - 避免频繁修改 style 属性(会引起重排和重绘) + - 批量修改使用 cssText 或 class 切换 + - 动画使用 transform 和 opacity(触发合成层) + +2. **兼容性**: + + - 旧版 IE 支持 currentStyle 而不是 getComputedStyle + - 某些 CSS 属性需要浏览器前缀(-webkit-, -moz-等) + +3. **最佳实践**: + + - 尽量使用 class 而不是直接修改 style + - 使用 getComputedStyle 获取计算后的样式 + - 使用 CSS 变量实现主题切换 + - 优先使用 CSS 动画而非 JavaScript 动画 + +4. **单位注意**: + + - 设置数值时需要包含单位(px, %, em 等) + - 获取值时是带单位的字符串 + +5. **只读属性**: + - 某些计算样式是只读的,不能通过 style 设置 + - 如:offsetWidth, offsetHeight, scrollTop 等 + +## 训练 + +```html +

    第一题

    +
    定义一行文本,每次变大2px,改变颜色
    + + +

    第二题

    + + +``` + +## 综合训练 + +```html + + + + +

    第一题

    +
    HTML/CSS讨论区
    +
    JavaScript讨论区
    +
    C语言讨论区
    + +

    第二题

    +
    + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251211-Form\345\257\271\350\261\241.md" "b/\344\270\245\345\201\245\345\256\207/20251211-Form\345\257\271\350\261\241.md" new file mode 100644 index 000000000..4eb60db56 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251211-Form\345\257\271\350\261\241.md" @@ -0,0 +1,563 @@ +# JavaScript Form 对象知识点总结 + +## 🔍 访问表单与表单元素的方法 + +### 知识点 + +1. **访问 Form 对象**: + + - `document.forms`:获取页面所有表单 + - `document.forms[index]`:按索引获取 + - `document.forms['formName']`:按 name 获取 + - `document.getElementById('formId')`:按 id 获取 + +2. **访问表单元素**: + - `form.elements`:获取表单所有元素 + - `form.elements['elementName']`:按 name 获取 + - `form.elements[index]`:按索引获取 + - `form.elementName`:直接通过 name 访问 + +### 示例 + +```html +
    + + + + +
    +``` + +```javascript +// 1. 访问Form对象 +const forms = document.forms; // 所有表单的集合 +const form1 = document.forms[0]; // 第一个表单 +const form2 = document.forms["userForm"]; // 按name +const form3 = document.getElementById("myForm"); // 按id + +// 2. 访问表单元素 +const form = document.getElementById("myForm"); + +// 方法1:elements集合 +const elements = form.elements; +console.log("元素数量:", elements.length); + +// 方法2:按name访问 +const usernameInput = form.elements["username"]; +const emailInput = form.elements.email; // 点语法也可以 + +// 方法3:直接通过form对象访问 +console.log(form.username); // 等价于 form.elements['username'] +console.log(form.country); // select元素 + +// 方法4:通过id访问(如果元素有id) +const emailById = document.getElementById("email"); + +// 3. 遍历表单元素 +for (let i = 0; i < form.elements.length; i++) { + const element = form.elements[i]; + console.log(`${i}: ${element.name} - ${element.type}`); +} +``` + +--- + +## 📋 Form 对象的属性 + +### 知识点 + +1. **基础属性**: + - `elements`:表单中所有控件的集合 + - `length`:表单中控件的数量 + - `name`:表单名称 + - `id`:表单 ID + - `className`:CSS 类名 + - `action`:表单提交的 URL + - `method`:HTTP 方法(GET/POST) + - `enctype`:编码类型 + - `target`:提交后的目标窗口 + - `acceptCharset`:字符集 + +### 示例 + +```javascript +const form = document.forms[0]; + +// 访问属性 +console.log("表单名称:", form.name); +console.log("表单ID:", form.id); +console.log("元素数量:", form.length); +console.log("提交地址:", form.action); +console.log("提交方法:", form.method); +console.log("编码类型:", form.enctype); +console.log("目标窗口:", form.target); + +// 修改属性 +form.action = "/api/submit"; +form.method = "POST"; +form.enctype = "multipart/form-data"; // 文件上传 +form.target = "_blank"; // 新窗口打开 +``` + +--- + +## ⚙️ Form 对象的方法 + +### 知识点 + +1. **提交相关**: + + - `submit()`:提交表单 + - `reset()`:重置表单 + +2. **验证相关**: + - `checkValidity()`:检查表单是否有效 + - `reportValidity()`:显示验证信息 + +### 示例 + +```javascript +const form = document.getElementById("myForm"); + +// 1. 提交表单 +form.submit(); // 触发提交 + +// 拦截默认提交 +form.addEventListener("submit", function (event) { + event.preventDefault(); // 阻止默认提交 + // 自定义处理逻辑 + if (validateForm()) { + this.submit(); // 手动提交 + } +}); + +// 2. 重置表单 +form.reset(); // 重置所有字段为默认值 + +// 3. 表单验证 +if (form.checkValidity()) { + console.log("表单验证通过"); +} else { + form.reportValidity(); // 显示验证错误信息 +} + +// 4. 自定义验证函数 +function validateForm() { + const email = form.email.value; + if (!email.includes("@")) { + alert("请输入有效的邮箱地址"); + return false; + } + return true; +} +``` + +--- + +## 🎯 Form 对象的事件 + +### 知识点 + +1. **主要事件**: + - `submit`:表单提交时触发 + - `reset`:表单重置时触发 + - `input`:输入框内容变化时触发 + - `change`:表单元素值改变时触发 + - `focus`:获得焦点时触发 + - `blur`:失去焦点时触发 + +### 示例 + +```javascript +const form = document.getElementById("myForm"); + +// 1. submit事件 - 表单提交 +form.addEventListener("submit", function (event) { + console.log("表单即将提交"); + // 可以在这里进行数据验证 +}); + +// 2. reset事件 - 表单重置 +form.addEventListener("reset", function (event) { + console.log("表单已重置"); +}); + +// 3. 表单元素事件 +const username = form.username; + +username.addEventListener("focus", function () { + console.log("用户名输入框获得焦点"); +}); + +username.addEventListener("blur", function () { + console.log("用户名输入框失去焦点"); +}); + +username.addEventListener("input", function () { + console.log("输入内容:", this.value); +}); + +username.addEventListener("change", function () { + console.log("内容已改变:", this.value); +}); + +// 4. 事件委托 - 监听所有输入框 +form.addEventListener("input", function (event) { + if (event.target.tagName === "INPUT") { + console.log(`${event.target.name}: ${event.target.value}`); + } +}); +``` + +--- + +## 💡 Form 对象的应用 + +### 知识点 + +1. **表单数据获取**: + + - 逐个获取元素值 + - 使用 FormData 对象 + - 序列化为查询字符串 + +2. **表单验证**: + + - HTML5 内置验证 + - 自定义 JavaScript 验证 + - 实时验证反馈 + +3. **动态表单操作**: + - 添加/删除表单元素 + - 表单字段联动 + - 条件显示/隐藏字段 + +### 示例 + +```javascript +// 1. 获取表单数据 +function getFormData(form) { + // 方法1:逐个获取 + const data = { + username: form.username.value, + email: form.email.value, + country: form.country.value, + }; + + // 方法2:使用FormData(支持文件) + const formData = new FormData(form); + console.log("FormData:", formData.get("username")); + + // 方法3:转换为对象 + const dataObj = Object.fromEntries(formData); + console.log("数据对象:", dataObj); + + // 方法4:转换为URL查询字符串 + const params = new URLSearchParams(formData); + console.log("查询字符串:", params.toString()); + + return data; +} + +// 2. 表单验证示例 +function validateUserForm() { + const form = document.forms["userForm"]; + let isValid = true; + + // 验证用户名 + if (!form.username.value.trim()) { + showError("username", "用户名不能为空"); + isValid = false; + } + + // 验证邮箱 + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(form.email.value)) { + showError("email", "邮箱格式不正确"); + isValid = false; + } + + return isValid; +} + +function showError(fieldName, message) { + const field = document.getElementsByName(fieldName)[0]; + field.style.borderColor = "red"; + + // 显示错误信息 + let errorDiv = field.nextElementSibling; + if (!errorDiv || !errorDiv.classList.contains("error")) { + errorDiv = document.createElement("div"); + errorDiv.className = "error"; + field.parentNode.insertBefore(errorDiv, field.nextSibling); + } + errorDiv.textContent = message; +} + +// 3. 动态表单操作 +function addFormField() { + const form = document.getElementById("myForm"); + const newInput = document.createElement("input"); + newInput.type = "text"; + newInput.name = "extraField"; + newInput.placeholder = "附加字段"; + form.insertBefore(newInput, form.lastElementChild); +} + +// 4. 表单字段联动 +const countrySelect = document.querySelector('select[name="country"]'); +const citySelect = document.querySelector('select[name="city"]'); + +countrySelect.addEventListener("change", function () { + const country = this.value; + citySelect.innerHTML = ""; // 清空城市选项 + + if (country === "CN") { + addOption(citySelect, "beijing", "北京"); + addOption(citySelect, "shanghai", "上海"); + } else if (country === "US") { + addOption(citySelect, "newyork", "纽约"); + addOption(citySelect, "losangeles", "洛杉矶"); + } +}); + +function addOption(select, value, text) { + const option = document.createElement("option"); + option.value = value; + option.textContent = text; + select.appendChild(option); +} + +// 5. Ajax表单提交 +form.addEventListener("submit", async function (event) { + event.preventDefault(); + + const formData = new FormData(this); + + try { + const response = await fetch(this.action, { + method: this.method, + body: formData, + }); + + if (response.ok) { + const result = await response.json(); + console.log("提交成功:", result); + } else { + console.error("提交失败"); + } + } catch (error) { + console.error("网络错误:", error); + } +}); +``` + +--- + +## 📌 注意事项 + +1. **表单元素类型**: + + - 单选框:同一 name 为一组,使用`form.elements['name']`获取集合 + - 复选框:可以多个同 name,需要单独处理每个 + - 下拉框:select.value 获取选中值 + +2. **性能考虑**: + + - 避免频繁访问 DOM + - 使用事件委托减少事件处理器 + - 合理使用防抖/节流 + +3. **兼容性**: + + - FormData 在 IE10+支持 + - HTML5 验证在老浏览器可能需要 polyfill + +4. **安全**: + + - 始终在服务端验证数据 + - 防止 XSS 攻击,转义用户输入 + - 使用 CSRF 令牌 + +5. **用户体验**: + - 提供清晰的错误提示 + - 实时验证反馈 + - 合理的表单布局和引导 + +## 训练 + +```html +

    第一题

    +
    + + +
    + +

    第二题

    +
    + +
    + + +
    + +

    第三题

    +
    +

    请选择课程

    + 阅读 + 运动 + 烹饪 + 绘画 + 旅行 + 听音乐 + 摄影
    + 写作 + 跳舞 + 游戏 + 养花 + 手工 + 养宠物 + 摸鱼 +
    + +
    +``` + +## 练习 + +```html +

    第一题

    +
    + 答案 + 不是答案 + +
    + +

    第二题

    +
    + 摸鱼 + 追剧 + 听歌 + 逛街 + 发呆 + 撸猫 + 喝茶 + 爬山 + 下棋 + 练字
    + + + +
    + +

    第三题

    +
    + 选择城市: + +
    + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251212-JSON.md" "b/\344\270\245\345\201\245\345\256\207/20251212-JSON.md" new file mode 100644 index 000000000..35d530ef1 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251212-JSON.md" @@ -0,0 +1,194 @@ +# JavaScript 中的 JSON + +## 基本概念 + +### 什么是 JSON + +- **JSON**(JavaScript Object Notation)是一种轻量级数据交换格式 +- 基于 JavaScript 对象语法,但独立于语言 +- 使用文本格式存储和传输数据 + +## 核心方法 + +### 1. JSON.parse() + +将 JSON 字符串转换为 JavaScript 对象 + +```javascript +// 解析 JSON 字符串 +const jsonStr = '{"name": "张三", "age": 25}'; +const obj = JSON.parse(jsonStr); +console.log(obj.name); // "张三" +``` + +### 2. JSON.stringify() + +将 JavaScript 对象转换为 JSON 字符串 + +```javascript +// 转换为 JSON 字符串 +const obj = { name: "张三", age: 25 }; +const jsonStr = JSON.stringify(obj); +console.log(jsonStr); // '{"name":"张三","age":25}' +``` + +## JSON 语法规则 + +### 数据类型支持 + +- 字符串(必须双引号) +- 数字 +- 布尔值(true/false) +- 数组 +- 对象 +- null + +### 示例 + +```javascript +// 有效的 JSON 示例 +{ + "name": "张三", + "age": 25, + "isStudent": false, + "hobbies": ["阅读", "游泳"], + "address": { + "city": "北京", + "street": "长安街" + }, + "score": null +} +``` + +## 常见应用场景 + +### 1. 解析 API 响应 + +```javascript +// 从 API 获取数据 +fetch("https://api.example.com/data") + .then((response) => response.json()) // 转换为对象 + .then((data) => console.log(data)); +``` + +### 2. 本地存储数据 + +```javascript +// 存储到 localStorage +const user = { id: 1, name: "李四" }; +localStorage.setItem("user", JSON.stringify(user)); + +// 从 localStorage 读取 +const storedUser = JSON.parse(localStorage.getItem("user")); +``` + +### 3. 对象深拷贝 + +```javascript +// 通过 JSON 实现简单深拷贝 +const original = { a: 1, b: { c: 2 } }; +const copy = JSON.parse(JSON.stringify(original)); +``` + +## 注意事项 + +### 1. JSON 字符串必须用双引号 + +```javascript +// ❌ 错误 +'{name: "张三"}'; + +// ✅ 正确 +'{"name": "张三"}'; +``` + +### 2. 不支持的数据类型 + +```javascript +// 以下类型会被忽略或转换 +const obj = { + date: new Date(), // 转换为字符串 + func: function () {}, // 被忽略 + undefined: undefined, // 被忽略 + infinity: Infinity, // 转换为 null + nan: NaN, // 转换为 null +}; +JSON.stringify(obj); // '{"date":"2023-10-01T...","infinity":null,"nan":null}' +``` + +### 3. 解析错误处理 + +```javascript +// 使用 try-catch 处理解析错误 +try { + const obj = JSON.parse("无效的 JSON"); +} catch (error) { + console.error("JSON 解析错误:", error.message); +} +``` + +## 高级用法 + +### 1. 格式化输出 + +```javascript +const obj = { name: "张三", age: 25 }; +const formatted = JSON.stringify(obj, null, 2); // 缩进2空格 +console.log(formatted); +``` + +### 2. 自定义序列化 + +```javascript +// 使用 replacer 函数过滤属性 +const user = { name: "张三", age: 25, password: "123456" }; +const safeUser = JSON.stringify(user, (key, value) => { + return key === "password" ? undefined : value; +}); +// 结果: '{"name":"张三","age":25}' +``` + +### 3. 自定义解析 + +```javascript +// 使用 reviver 函数转换值 +const jsonStr = '{"name": "张三", "birthDate": "1998-05-20"}'; +const obj = JSON.parse(jsonStr, (key, value) => { + if (key === "birthDate") return new Date(value); + return value; +}); +``` + +## 最佳实践 + +1. **始终验证**:解析前验证 JSON 字符串格式 +2. **错误处理**:使用 try-catch 包裹 JSON.parse() +3. **避免循环引用**:JSON.stringify() 不支持循环引用 +4. **性能注意**:大对象序列化/反序列化可能影响性能 + +## 快速参考 + +| 操作 | 方法 | 示例 | +| ------------- | ------------------ | ------------------------------ | +| 字符串 → 对象 | `JSON.parse()` | `JSON.parse('{"x":1}')` | +| 对象 → 字符串 | `JSON.stringify()` | `JSON.stringify({x:1})` | +| 格式化输出 | 第三个参数 | `JSON.stringify(obj,null,2)` | +| 过滤属性 | 第二个参数 | `JSON.stringify(obj,replacer)` | + +## 常用工具函数 + +```javascript +// 安全解析 JSON +function safeParse(jsonStr, defaultValue = null) { + try { + return JSON.parse(jsonStr); + } catch { + return defaultValue; + } +} + +// 深度比较两个对象(通过 JSON) +function isEqual(obj1, obj2) { + return JSON.stringify(obj1) === JSON.stringify(obj2); +} +``` -- Gitee From 93afcd3a8afe0dcbfa9c23f28630dd46db2058be Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 21 Dec 2025 16:14:14 +0800 Subject: [PATCH 7/9] feat:zuoye --- .../20251215-jQuery.md" | 850 ++++++++++++++++++ ...13\344\273\266\345\244\204\347\220\206.md" | 50 ++ ...00\351\242\230\346\225\260\347\273\204.md" | 49 + ...\346\225\260(\351\207\215\347\202\271).md" | 64 ++ 4 files changed, 1013 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251215-jQuery.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251217-JSON\344\272\213\344\273\266\345\244\204\347\220\206.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251218-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251219-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204\351\253\230\351\230\266\345\207\275\346\225\260(\351\207\215\347\202\271).md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251215-jQuery.md" "b/\344\270\245\345\201\245\345\256\207/20251215-jQuery.md" new file mode 100644 index 000000000..31a4723ca --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251215-jQuery.md" @@ -0,0 +1,850 @@ +# jQuery 学习笔记 + +## 一、简介 + +jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画和 Ajax 交互。 + +### 特点: + +- 链式操作 +- 隐式迭代 +- 丰富的插件生态 +- 浏览器兼容性好 + +## 二、基本使用 + +### 1. 引入 jQuery + +```html + + + + + +``` + +### 2. 文档就绪事件 + +```javascript +// 标准写法 +$(document).ready(function () { + // 代码在这里执行 +}); + +// 简写 +$(function () { + // 代码在这里执行 +}); +``` + +## 三、选择器 + +### 1. 基本选择器 + +```javascript +// ID选择器 +$("#myId"); + +// 类选择器 +$(".myClass"); + +// 元素选择器 +$("div"); + +// 通配符选择器 +$("*"); + +// 并集选择器 +$("div, p, .class"); + +// 交集选择器 +$("div.className"); +``` + +### 2. 层级选择器 + +```javascript +// 后代选择器 +$("ul li"); + +// 子元素选择器 +$("ul > li"); + +// 相邻兄弟选择器 +$("h2 + p"); + +// 通用兄弟选择器 +$("h2 ~ p"); +``` + +### 3. 过滤选择器 + +```javascript +// :first +$("li:first"); + +// :last +$("li:last"); + +// :even 偶数 +$("tr:even"); + +// :odd 奇数 +$("tr:odd"); + +// :eq(index) +$("li:eq(2)"); + +// :gt(index) +$("li:gt(2)"); + +// :lt(index) +$("li:lt(2)"); + +// :not(selector) +$("input:not(:checked)"); + +// :contains(text) +$("div:contains('hello')"); +``` + +### 4. 表单选择器 + +```javascript +// :input +$(":input"); + +// :text +$(":text"); + +// :password +$(":password"); + +// :radio +$(":radio"); + +// :checkbox +$(":checkbox"); + +// :submit +$(":submit"); + +// :checked +$(":checked"); + +// :selected +$(":selected"); + +// :disabled +$(":disabled"); + +// :enabled +$(":enabled"); +``` + +### 5. 属性选择器 + +```javascript +// [attribute] +$("div[id]"); + +// [attribute=value] +$("input[name='username']"); + +// [attribute!=value] +$("input[name!='username']"); + +// [attribute^=value] +$("a[href^='https']"); + +// [attribute$=value] +$("img[src$='.jpg']"); + +// [attribute*=value] +$("a[href*='google']"); +``` + +## 四、DOM 操作 + +### 1. 创建元素 + +```javascript +// 创建元素 +var $div = $("
    "); +var $p = $("

    Hello World

    "); +``` + +### 2. 添加元素 + +```javascript +// 内部添加 +$("ul").append("
  • 新项目
  • "); // 末尾添加 +$("ul").prepend("
  • 新项目
  • "); // 开头添加 + +// 外部添加 +$("div").after("

    新段落

    "); // 之后添加 +$("div").before("

    新段落

    "); // 之前添加 +``` + +### 3. 删除元素 + +```javascript +// 删除元素 +$("div").remove(); // 删除元素本身 +$("div").empty(); // 清空元素内容 +$("div").detach(); // 删除但保留数据 +``` + +### 4. 修改元素 + +```javascript +// 替换元素 +$("p").replaceWith("
    新内容
    "); + +// 包裹元素 +$("span").wrap("
    "); // 单独包裹 +$("span").wrapAll("
    "); // 整体包裹 +$("span").wrapInner(""); // 包裹内容 +``` + +### 5. 遍历元素 + +```javascript +// 父级元素 +$("li").parent(); +$("li").parents(); +$("li").parentsUntil("div"); + +// 子级元素 +$("ul").children(); +$("ul").find("li"); + +// 兄弟元素 +$("li").siblings(); +$("li").next(); +$("li").prev(); +$("li").nextAll(); +$("li").prevAll(); +``` + +## 五、CSS 操作 + +### 1. 获取和设置 CSS + +```javascript +// 获取CSS +var color = $("div").css("color"); + +// 设置单个CSS +$("div").css("color", "red"); + +// 设置多个CSS +$("div").css({ + color: "red", + "font-size": "16px", + "background-color": "#f0f0f0", +}); +``` + +### 2. 类操作 + +```javascript +// 添加类 +$("div").addClass("active"); + +// 删除类 +$("div").removeClass("active"); + +// 切换类 +$("div").toggleClass("active"); + +// 检查类 +if ($("div").hasClass("active")) { + // 执行操作 +} + +// 替换类 +$("div").removeClass("oldClass").addClass("newClass"); +``` + +### 3. 尺寸和位置 + +```javascript +// 尺寸 +$("div").width(); // 内容宽度 +$("div").innerWidth(); // 包含内边距 +$("div").outerWidth(); // 包含边框 +$("div").outerWidth(true); // 包含外边距 + +// 位置 +$("div").offset(); // 相对于文档 +$("div").position(); // 相对于父元素 +$("div").scrollTop(); // 滚动条位置 +$("div").scrollLeft(); +``` + +## 六、属性操作 + +### 1. 通用属性 + +```javascript +// 获取属性 +var href = $("a").attr("href"); + +// 设置属性 +$("a").attr("href", "http://example.com"); + +// 设置多个属性 +$("img").attr({ + src: "image.jpg", + alt: "描述", + title: "标题", +}); + +// 删除属性 +$("img").removeAttr("alt"); +``` + +### 2. 表单属性 + +```javascript +// 获取值 +var value = $("input").val(); + +// 设置值 +$("input").val("新值"); + +// 获取选中状态 +var isChecked = $("checkbox").prop("checked"); + +// 设置选中状态 +$("checkbox").prop("checked", true); + +// 获取HTML内容 +var html = $("div").html(); + +// 设置HTML内容 +$("div").html("

    新内容

    "); + +// 获取文本内容 +var text = $("div").text(); + +// 设置文本内容 +$("div").text("新文本"); +``` + +## 七、事件处理 + +### 1. 事件绑定 + +```javascript +// 直接绑定 +$("button").click(function () { + alert("按钮被点击"); +}); + +// on()方法 +$("button").on("click", function () { + // 处理点击 +}); + +// 绑定多个事件 +$("input").on({ + focus: function () { + /* 聚焦处理 */ + }, + blur: function () { + /* 失焦处理 */ + }, + keyup: function () { + /* 按键处理 */ + }, +}); + +// 事件委托 +$("ul").on("click", "li", function () { + // 处理li点击 +}); +``` + +### 2. 常用事件 + +```javascript +// 鼠标事件 +.click() +.dblclick() +.mouseenter() +.mouseleave() +.mousedown() +.mouseup() +.mousemove() + +// 键盘事件 +.keydown() +.keypress() +.keyup() + +// 表单事件 +.focus() +.blur() +.change() +.submit() +.select() + +// 窗口事件 +.resize() +.scroll() +.load() +.unload() +``` + +### 3. 事件对象 + +```javascript +$("a").click(function (event) { + event.preventDefault(); // 阻止默认行为 + event.stopPropagation(); // 阻止事件冒泡 + + var target = event.target; // 触发元素 + var type = event.type; // 事件类型 + var pageX = event.pageX; // 鼠标X坐标 + var pageY = event.pageY; // 鼠标Y坐标 + var which = event.which; // 按键代码 +}); +``` + +### 4. 其他事件方法 + +```javascript +// 解除绑定 +$("button").off("click"); + +// 触发事件 +$("button").trigger("click"); + +// 一次性事件 +$("button").one("click", function () { + // 只执行一次 +}); + +// hover方法 +$("div").hover( + function () { + /* 鼠标进入 */ + }, + function () { + /* 鼠标离开 */ + } +); +``` + +## 八、动画效果 + +### 1. 显示和隐藏 + +```javascript +// 基本显示隐藏 +$("div").show(); +$("div").hide(); +$("div").toggle(); + +// 带效果的显示隐藏 +$("div").show(1000); // 1秒显示 +$("div").hide("slow"); // 慢速隐藏 +$("div").toggle("fast", function () { + // 动画完成回调 +}); + +// 淡入淡出 +$("div").fadeIn(1000); // 淡入 +$("div").fadeOut(500); // 淡出 +$("div").fadeToggle(); // 切换 +$("div").fadeTo(1000, 0.5); // 淡入到指定透明度 +``` + +### 2. 滑动效果 + +```javascript +$("div").slideDown(1000); // 滑下 +$("div").slideUp(500); // 滑上 +$("div").slideToggle(); // 切换滑动 +``` + +### 3. 自定义动画 + +```javascript +// 简单动画 +$("div").animate( + { + left: "+=50", + opacity: 0.5, + }, + 1000 +); + +// 带回调的动画 +$("div").animate( + { + width: "300px", + height: "300px", + }, + { + duration: 1000, + complete: function () { + alert("动画完成"); + }, + step: function (now, fx) { + // 每一步执行 + }, + } +); + +// 停止动画 +$("div").stop(); // 停止当前动画 +$("div").stop(true); // 清除队列 +$("div").stop(true, true); // 立即完成 +$("div").finish(); // 完成所有动画 +``` + +## 九、Ajax + +### 1. 基本方法 + +```javascript +// $.ajax()方法 +$.ajax({ + url: "data.php", + type: "POST", + data: { name: "John", age: 30 }, + dataType: "json", + success: function (response) { + // 成功处理 + }, + error: function (xhr, status, error) { + // 错误处理 + }, + complete: function () { + // 完成处理 + }, +}); + +// 简写方法 +$.get( + "data.php", + { id: 1 }, + function (data) { + // 处理数据 + }, + "json" +); + +$.post("data.php", { name: "John" }, function (data) { + // 处理数据 +}); + +$.getJSON("data.json", function (data) { + // 处理JSON数据 +}); + +$.getScript("script.js", function () { + // 脚本加载完成 +}); +``` + +### 2. 全局 Ajax 事件 + +```javascript +// 全局事件处理 +$(document).ajaxStart(function () { + // 显示加载提示 +}); + +$(document).ajaxStop(function () { + // 隐藏加载提示 +}); + +$(document).ajaxError(function (event, xhr, settings, error) { + // 全局错误处理 +}); + +$(document).ajaxSuccess(function (event, xhr, settings) { + // 全局成功处理 +}); +``` + +### 3. 加载 HTML + +```javascript +// 加载HTML片段 +$("#content").load("fragment.html"); + +// 加载HTML片段的部分内容 +$("#content").load("page.html #section"); + +// 带回调的加载 +$("#content").load("data.html", function (response, status, xhr) { + if (status == "error") { + // 错误处理 + } +}); +``` + +## 十、工具方法 + +### 1. 数组操作 + +```javascript +// 遍历数组 +$.each(array, function (index, value) { + console.log(index + ": " + value); +}); + +// 过滤数组 +var filtered = $.grep(array, function (value, index) { + return value > 10; +}); + +// 映射数组 +var mapped = $.map(array, function (value, index) { + return value * 2; +}); + +// 检查数组是否包含 +var exists = $.inArray(value, array); +``` + +### 2. 对象操作 + +```javascript +// 合并对象 +var obj = $.extend({}, obj1, obj2); + +// 深度合并 +var obj = $.extend(true, {}, obj1, obj2); + +// 遍历对象 +$.each(object, function (key, value) { + console.log(key + ": " + value); +}); +``` + +### 3. 其他工具 + +```javascript +// 类型判断 +$.isArray(obj); +$.isFunction(obj); +$.isNumeric(value); +$.isEmptyObject(obj); +$.isPlainObject(obj); + +// 字符串修剪 +var str = $.trim(" hello "); + +// 解析JSON +var obj = $.parseJSON(jsonString); + +// 解析XML +var xml = $.parseXML(xmlString); + +// 延迟对象 +var deferred = $.Deferred(); +``` + +## 十一、插件开发 + +### 1. 基本插件结构 + +```javascript +(function ($) { + $.fn.myPlugin = function (options) { + // 默认配置 + var settings = $.extend( + { + color: "red", + fontSize: "14px", + }, + options + ); + + // 遍历每个匹配的元素 + return this.each(function () { + var $this = $(this); + + // 插件逻辑 + $this.css({ + color: settings.color, + fontSize: settings.fontSize, + }); + }); + }; +})(jQuery); + +// 使用插件 +$("div").myPlugin({ + color: "blue", + fontSize: "16px", +}); +``` + +### 2. 链式调用支持 + +```javascript +(function ($) { + $.fn.chainablePlugin = function () { + return this.each(function () { + // 插件逻辑 + }); + }; +})(jQuery); + +// 链式调用 +$("div").chainablePlugin().addClass("active").fadeIn(); +``` + +## 十二、最佳实践 + +### 1. 性能优化 + +```javascript +// 缓存jQuery对象 +var $div = $("#myDiv"); + +// 使用ID选择器最快 +$("#id"); + +// 减少DOM操作 +var html = ""; +for (var i = 0; i < 100; i++) { + html += "
  • 项目" + i + "
  • "; +} +$("ul").append(html); + +// 事件委托优于直接绑定 +$("ul").on("click", "li", function () { + // 处理点击 +}); +``` + +### 2. 代码组织 + +```javascript +// 使用命名空间 +var MyApp = { + init: function () { + // 初始化 + }, + + events: { + // 事件处理 + }, + + utils: { + // 工具方法 + }, +}; + +// 页面加载后初始化 +$(document).ready(function () { + MyApp.init(); +}); +``` + +## 十三、与原生 JS 互操作 + +### 1. jQuery 对象转 DOM 对象 + +```javascript +// jQuery对象转DOM对象 +var $div = $("#myDiv"); +var div = $div[0]; // 方法一 +var div = $div.get(0); // 方法二 + +// 遍历转换 +$("div").each(function (index) { + var domElement = this; // this是DOM元素 + var $element = $(this); // 转回jQuery对象 +}); +``` + +### 2. DOM 对象转 jQuery 对象 + +```javascript +// DOM对象转jQuery对象 +var div = document.getElementById("myDiv"); +var $div = $(div); +``` + +--- + +## 练习 + +```html +
    演示对象
    +
    内容
    +

    项目1

    +

    项目2

    +

    项目3

    +
      +
    • 项1
    • +
    • 项2
    • +
    • 项3
    • +
    • 项4
    • +
    +
    +

    段落 文本1

    +

    段落 文本2

    +
    + + + + + + + + + + + + + +
    第1行
    第2行
    第3行
    第4行
    +
    +
    +
    + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251217-JSON\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\344\270\245\345\201\245\345\256\207/20251217-JSON\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 000000000..1645c4b01 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251217-JSON\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,50 @@ +```html +

    原标题

    + +
    悬停我
    +
      +
    • 项目1
    • +
    + +
    + + +
    + + + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251218-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204.md" "b/\344\270\245\345\201\245\345\256\207/20251218-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204.md" new file mode 100644 index 000000000..105f6bb3f --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251218-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204.md" @@ -0,0 +1,49 @@ +```javascript +// 数组; +// 第一题; +let arr = [1, 2, 3, 4]; +let a = 0; +for (let i = 0; i < arr.length; i++) { + a = a + arr[i]; +} +console.log(a); +// 第二题; +let arr1 = [1, 2, 3, 4]; +let arr2 = ["a", "b", "c", 1]; +let arr3 = arr1.concat(arr2); +console.log(arr3); +// 第三题; +let arr = [1, 2, 4, 4, 3, 4, 3]; +function a(sum, num) { + return arr.reduce((a, b) => { + return a + (b === num ? 1 : 0); + }, 0); +} +console.log(a(arr, 4)); +// 第四题; +let arr = [1, 2, 4, 4, 3, 3, 1, 5, 3]; +function a(b) { + return arr.reduce((result, item, index) => { + if (arr.indexOf(item) !== index && !result.includes(item)) { + result.push(item); + } + return result; + }, []); +} +console.log(a(arr)); +// 第五题; +let t = [1, 2, 3, 4, 2, 5]; +function removeItem(arr, item) { + return arr.filter((value) => value !== item); +} +console.log(removeItem(t, 2)); +// 第六题; +let con = [ + { name: "小明", score: 85 }, + { name: "小红", score: 55 }, + { name: "小刚", score: 90 }, +]; +let a = con.filter((item) => item.score >= 60); +let b = a.map((item) => item.name); +console.log(b); +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251219-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204\351\253\230\351\230\266\345\207\275\346\225\260(\351\207\215\347\202\271).md" "b/\344\270\245\345\201\245\345\256\207/20251219-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204\351\253\230\351\230\266\345\207\275\346\225\260(\351\207\215\347\202\271).md" new file mode 100644 index 000000000..58535e680 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251219-\347\273\203\344\271\240200\351\242\230\346\225\260\347\273\204\351\253\230\351\230\266\345\207\275\346\225\260(\351\207\215\347\202\271).md" @@ -0,0 +1,64 @@ +```javascript +//数组高阶函数(重点) +//第七题 +let arr = [1, 2, 3, 4, 5]; +let a = arr.map((num) => num * 2); +console.log(a); +//第八题 +let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; +let x = arr.filter((item) => item % 2 !== 0); +console.log(x); +//第九题 +let arr = [10, 20, 30, 40, 50]; +function a(b) { + return b.reduce((sum, value) => { + return sum + value; + }, 0); +} +console.log(a(arr)); +//第十题 +let arr = [3, 7, 2, 9, 1, 5]; +let c = 0; +function a(b) { + return b.reduce((sum, item) => { + if (c < item) { + return (c = item); + } + }, 0); +} +a(arr); +console.log(c); +//第十一题 +let arr = [2, 5, 8, 12, 15, 7]; +let a = arr.find((item) => item > 10); +console.log(a); +//第十二题 +let arr = [1, 5, 3, -2, 8, -5]; +let a = arr.findIndex((item) => item < 0); +console.log(a); +//第十三题 +let arr = [1, 3, 5, 7, 8]; +let a = arr.some((item) => item % 2 == 0); +console.log(a); +//第十四题 +let arr = [1, 2, 3, 4, 5]; +let a = arr.every((item) => item > 0); +console.log(a); +//第十五题 +let arr = [40, 100, 1, 5, 25, 10]; +let a = arr.sort((a, b) => a - b); +console.log(a); +//第十六题 +let arr = [ + { name: "小明", age: 20 }, + { name: "小红", age: 18 }, + { name: "小刚", age: 22 }, +]; +arr.sort((a, b) => a.age - b.age); +console.log(arr); +//第十七题 +let arr = ["apple", "banana", "orange"]; +arr.forEach((a, b) => { + console.log(`索引${b}:${a}`); +}); +``` -- Gitee From d7fbb88e4ccafb6cd530585c32a2ff7cb9f9521f Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 28 Dec 2025 19:33:36 +0800 Subject: [PATCH 8/9] feat:zuoye --- .../20251222-API\350\260\203\347\224\2501.md" | 184 ++++++++++++++++++ .../20251224-API\350\260\203\347\224\2502.md" | 153 +++++++++++++++ ...1\347\253\231\351\205\215\347\275\2561.md" | 145 ++++++++++++++ ...1\347\253\231\351\205\215\347\275\2562.md" | 105 ++++++++++ 4 files changed, 587 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20251222-API\350\260\203\347\224\2501.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251224-API\350\260\203\347\224\2502.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251225-\347\275\221\347\253\231\351\205\215\347\275\2561.md" create mode 100644 "\344\270\245\345\201\245\345\256\207/20251226-\347\275\221\347\253\231\351\205\215\347\275\2562.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20251222-API\350\260\203\347\224\2501.md" "b/\344\270\245\345\201\245\345\256\207/20251222-API\350\260\203\347\224\2501.md" new file mode 100644 index 000000000..f7a3b3eb4 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251222-API\350\260\203\347\224\2501.md" @@ -0,0 +1,184 @@ +## 笔记 + +### 200+练习 + +方法一: +![alt text](image.png) + +方法二: +![alt text](image-1.png) + +### 增删改查 API + +![alt text](image-2.png) +![alt text](image-3.png) + +4. 完成如下任务 + +- 题目描述: + 声明三个变量分别存储一个学生的姓名(字符串)、年龄(数字)、是否及格(布尔值),然后分别输出这三个变量的值和类型 +- 输出示例: + 姓名: "李四", 类型: string + 年龄: 19, 类型: number + 及格: true, 类型: boolean + +```html + +``` + +5. 完成如下任务 + +- 题目描述: + 理解 null 和 undefined 的区别,分别创建这两种类型的变量并输出 +- 输出示例: + undefined 变量: undefined, 类型: undefined + null 变量: null, 类型: object + +```html + +``` + +6. 完成如下任务 + +- 题目描述: + 理解变量的作用域,演示块级作用域(let、const)和函数作用域(var)的区别 +- 输出示例: + let 和 const 有块级作用域 + var 只有函数作用域 + +```html + +``` + +7. 完成如下任务 + +- 题目描述: + 理解变量提升(Hoisting),对比 var、let、const 的行为 +- 输出示例: + var 声明会提升,但值为 undefined + let 和 const 存在暂时性死区 + +```html + +``` + +8. 完成如下任务 + +- 题目描述: + 使用模板字符串拼接变量和表达式 +- 输入示例: + name = "张三", age = 20, score = 85 +- 输出示例: + `${name}今年${age}岁,考了${score}分,${score >= 60 ? '及格' : '不及格'}` + +```html + +``` + +. 完成如下任务 + +- 题目描述: + 计算两个数字 a 和 b 的加、减、乘、除、取余结果,并返回一个包含这些结果的对象 +- 输入示例: + 10, 3 +- 输出示例: + { 加: 13, 减: 7, 乘: 30, 除: 3.33, 余: 1 } + +```html + +``` + +2. 完成如下任务 + +- 题目描述: + 将字符串 "123" 转换为数字类型,将数字 456 转换为字符串类型,并分别返回它们的值和类型 +- 输出示例: + 转换后的数字: 123, 类型: number + 转换后的字符串: "456", 类型: string + +```html + +``` + +3. 完成如下任务 + +- 题目描述: + 比较两个变量 a 和 b,返回 a 是否大于 b、是否等于 b、是否不等于 b 的布尔值结果 +- 输入示例: + 5, 3 +- 输出示例: + { 大于: true, 等于: false, 不等于: true } + +```html + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251224-API\350\260\203\347\224\2502.md" "b/\344\270\245\345\201\245\345\256\207/20251224-API\350\260\203\347\224\2502.md" new file mode 100644 index 000000000..47e12043f --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251224-API\350\260\203\347\224\2502.md" @@ -0,0 +1,153 @@ +## 笔记 + +![alt text](image.png) +![alt text](image-1.png) + +1. 完成如下任务 + +- 题目描述: + 给定一个分数 score,判断成绩等级:90 分以上为"优秀",80-89 分为"良好",60-79 分为"及格",60 分以下为"不及格" +- 输入示例: + 85 +- 输出示例: + "良好" + +2. 完成如下任务 + +- 题目描述: + 使用 for 循环计算 1 到 n 的累加和 +- 输入示例: + 100 +- 输出示例: + 5050 + +```html + +``` + +3. 完成如下任务 + +- 题目描述: + 遍历数组 arr,输出所有偶数 +- 输入示例: + [1, 2, 3, 4, 5, 6, 7, 8] +- 输出示例: + [2, 4, 6, 8] + +```html + +``` + +4. 完成如下任务 + +- 题目描述: + 判断给定数字 num 是否为质数(只能被 1 和自身整除的大于 1 的自然数) +- 输入示例: + 17 +- 输出示例: + true + +```html + +``` + +5. 完成如下任务 + +- 题目描述: + 使用 while 循环找出小于 n 的所有 3 的倍数 +- 输入示例: + 20 +- 输出示例: + [3, 6, 9, 12, 15, 18] + +```html + +``` + +6. 完成如下任务 + +- 题目描述: + 使用 switch 语句根据星期几输出不同的信息 +- 输入示例: + dayOfWeek = 1 (周一) +- 输出示例: + "今天是工作日,要上班" + +```html + +``` + +7. 完成如下任务 + +- 题目描述: + 使用 for...of 循环遍历数组 +- 输入示例: + ['苹果', '香蕉', '橙子'] +- 输出示例: + 依次输出每个水果名称 + +```html + +``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251225-\347\275\221\347\253\231\351\205\215\347\275\2561.md" "b/\344\270\245\345\201\245\345\256\207/20251225-\347\275\221\347\253\231\351\205\215\347\275\2561.md" new file mode 100644 index 000000000..da411ecd0 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251225-\347\275\221\347\253\231\351\205\215\347\275\2561.md" @@ -0,0 +1,145 @@ +## 笔记 + +![alt text](image.png) +![alt text](image-1.png) + +1. 使用公网 IP`添加记录` +2. 使用`ping`查看网站连接 +3. 登录服务器 +4. 创建文件 + - touch xxx 创建一个新的空文件 + - vim xxx.txt 打开/创建一个文件 +5. 创建文件夹 + - mkdir +6. 切换目录 + - cd +7. 列出目录清单 + - ls 列出指定目录下的内容(如果未指定则指列出当前目录) +8. 安装软件 + - apt install nginx -y +9. 更新软件 + +10. 完成如下任务 + +- 题目描述: + 使用 for...in 循环遍历对象的属性 +- 输入示例: + { name: "张三", age: 20, city: "北京" } +- 输出示例: + name: 张三 + age: 20 + city: 北京 + +```html + +``` + +9. 完成如下任务 + +- 题目描述: + 使用 break 和 continue 控制循环流程 +- 输入示例: + 查找数组中第一个大于 50 的数,跳过所有负数 +- 输出示例: + 演示 break(跳出循环)和 continue(跳过本次循环)的使用 + +```html + +``` + +10. 完成如下任务 + +- 题目描述: + 使用嵌套循环打印九九乘法表 +- 输出示例: + 1*1=1 + 1*2=2 2*2=4 + 1*3=3 2*3=6 3*3=9 + ... + +```html + +``` + +11. 完成如下任务 + +- 题目描述: + 使用条件运算符和 if-else 对比,实现同样的逻辑 + +- 输入示例: + age = 18 + +- 输出示例: + const status = age >= 18 ? '成年' : '未成年'; (三元运算符) + if (age >= 18) { status = '成年'; } else { status = '未成年'; } + + ```html + + ``` + +12. 完成如下任务 + +- 题目描述: + 实现一个简单的猜数字游戏,使用循环和条件判断 + +- 输出示例: + 生成 1-100 随机数,用户猜测,给出"太大"、"太小"或"猜对了"的提示 + + ```html + + ``` diff --git "a/\344\270\245\345\201\245\345\256\207/20251226-\347\275\221\347\253\231\351\205\215\347\275\2562.md" "b/\344\270\245\345\201\245\345\256\207/20251226-\347\275\221\347\253\231\351\205\215\347\275\2562.md" new file mode 100644 index 000000000..68fae158b --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20251226-\347\275\221\347\253\231\351\205\215\347\275\2562.md" @@ -0,0 +1,105 @@ +1. 完成如下任务 + +- 题目描述: + 计算并返回给定数组 arr 中所有元素的总和 +- 输入示例: + [ 1, 2, 3, 4 ] +- 输出示例: + 10 + +```html + +``` + +2. 完成如下任务 + +- 题目描述: + 合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组 +- 输入示例: + [1, 2, 3, 4], ['a', 'b', 'c', 1] +- 输出示例: + [1, 2, 3, 4, 'a', 'b', 'c', 1] + +```html + +``` + +3. 完成如下任务 + +- 题目描述: + 统计数组 arr 中值等于 item 的元素出现的次数 + +- 输入示例: + [1, 2, 4, 4, 3, 4, 3], 4 + +- 输出示例: + 3 + +```html + +``` + +4. 完成如下任务 + +- 题目描述(15 分): + 找出数组 arr 中重复出现过的元素(不用考虑返回顺序) + +- 输入示例: + [1, 2, 4, 4, 3, 3, 1, 5, 3] + +- 输出示例: + [1, 3, 4] + +```html + +``` + +5. 完成如下任务 + +- 题目描述: + 删除数组 arr 中的指定元素 item,返回新数组(不修改原数组) +- 输入示例: + [1, 2, 3, 4, 2, 5], 2 +- 输出示例: + [1, 3, 4, 5] + +```html + +``` -- Gitee From a50022624a3bbd6b9dde4bdcf745f38add0e0235 Mon Sep 17 00:00:00 2001 From: yanjianyu <906881781@qq.com> Date: Sun, 11 Jan 2026 21:32:04 +0800 Subject: [PATCH 9/9] =?UTF-8?q?feat:=E7=AC=94=E8=AE=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../20260105-\345\244\215\344\271\240.md" | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 "\344\270\245\345\201\245\345\256\207/20260105-\345\244\215\344\271\240.md" diff --git "a/\344\270\245\345\201\245\345\256\207/20260105-\345\244\215\344\271\240.md" "b/\344\270\245\345\201\245\345\256\207/20260105-\345\244\215\344\271\240.md" new file mode 100644 index 000000000..58535e680 --- /dev/null +++ "b/\344\270\245\345\201\245\345\256\207/20260105-\345\244\215\344\271\240.md" @@ -0,0 +1,64 @@ +```javascript +//数组高阶函数(重点) +//第七题 +let arr = [1, 2, 3, 4, 5]; +let a = arr.map((num) => num * 2); +console.log(a); +//第八题 +let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; +let x = arr.filter((item) => item % 2 !== 0); +console.log(x); +//第九题 +let arr = [10, 20, 30, 40, 50]; +function a(b) { + return b.reduce((sum, value) => { + return sum + value; + }, 0); +} +console.log(a(arr)); +//第十题 +let arr = [3, 7, 2, 9, 1, 5]; +let c = 0; +function a(b) { + return b.reduce((sum, item) => { + if (c < item) { + return (c = item); + } + }, 0); +} +a(arr); +console.log(c); +//第十一题 +let arr = [2, 5, 8, 12, 15, 7]; +let a = arr.find((item) => item > 10); +console.log(a); +//第十二题 +let arr = [1, 5, 3, -2, 8, -5]; +let a = arr.findIndex((item) => item < 0); +console.log(a); +//第十三题 +let arr = [1, 3, 5, 7, 8]; +let a = arr.some((item) => item % 2 == 0); +console.log(a); +//第十四题 +let arr = [1, 2, 3, 4, 5]; +let a = arr.every((item) => item > 0); +console.log(a); +//第十五题 +let arr = [40, 100, 1, 5, 25, 10]; +let a = arr.sort((a, b) => a - b); +console.log(a); +//第十六题 +let arr = [ + { name: "小明", age: 20 }, + { name: "小红", age: 18 }, + { name: "小刚", age: 22 }, +]; +arr.sort((a, b) => a.age - b.age); +console.log(arr); +//第十七题 +let arr = ["apple", "banana", "orange"]; +arr.forEach((a, b) => { + console.log(`索引${b}:${a}`); +}); +``` -- Gitee