diff --git "a/\347\275\227\347\232\223\346\231\250/20251110-js\345\255\246\344\271\240\345\274\225\345\205\245\346\226\271\345\274\217.md" "b/\347\275\227\347\232\223\346\231\250/20251110-js\345\255\246\344\271\240\345\274\225\345\205\245\346\226\271\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..c0c994354687975ba3b6ce11a7047d69e9001592 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251110-js\345\255\246\344\271\240\345\274\225\345\205\245\346\226\271\345\274\217.md" @@ -0,0 +1,73 @@ +## 笔记 + +### JavaScript 主要引入方式详解 + +#### 1. 行内引入(嵌入式) + +- 核心形式:将 JS 代码直接嵌入 HTML 标签的属性中,依赖事件触发或特定前缀执行。 + - 事件属性:如 `onclick`、`onmouseover` 等,例如 + + ```html + + ``` + +- **本质**:JS 代码与 HTML 标签完全耦合,属于最原始的引入方式 +- **特点**:仅适合单元素的极简交互,代码无法复用,维护性极差,仅临时测试或极端简单场景使用 + +#### 2. 内部引入(内嵌式) + +- 核心形式:通过` + ``` + +- **特点**:代码与 HTML 分离但同文件,无需额外请求,适合中小型单页应用的独立逻辑,复用性较低 + +- **注意**:内部引入需将` + ``` + +- **特点**:代码与 HTML 完全分离,可复用性极强,支持按需加载和模块化,是大型项目的标准引入方式 + +## 作业 + +### 第一题 + +#### 关键代码 + +```html + +

+ + +``` + +#### 效果展示 + +![](./Image/20251110_Image/show01.png) + +### 第二题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251110_Image/show02.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251112-js\345\237\272\347\241\200.md" "b/\347\275\227\347\232\223\346\231\250/20251112-js\345\237\272\347\241\200.md" new file mode 100644 index 0000000000000000000000000000000000000000..e9ac89e67d6604e06b30f72aaf34d3a05e95d146 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251112-js\345\237\272\347\241\200.md" @@ -0,0 +1,111 @@ +## 笔记 + +### 数据类型 +#### 基本类型 + +| 类型 | 说明及典型示例 | 关键特点 | +| --------- | ------------------------------------ | ----------------------------------------------------- | +| Number | 整数 (10)、浮点数 (3.14)、NaN | NaN 表示非数字,`isNaN()`判断;Infinity 表示无穷大 | +| String | 单 / 双引号 ("hi")、反引号 (`a${b}`) | 反引号支持模板字符串和换行 | +| Boolean | true(真)、false(假) | 0、""、null、undefined 会被转为 false | +| Null | let a = null | 表示 “空”,主动赋值;typeof 检测为 object(历史问题) | +| Undefined | let b;(声明未赋值) | 表示 “未定义”,变量默认初始值 | + +### 常量和变量 + +| 类型 | 声明方式 | 作用域范围 | 核心规则 | +| ---- | -------- | ------------------------ | -------------------------------------------------------- | +| 变量 | let | 块级({} 内,如 if/for) | 可重新赋值,同一作用域不可重复声明 | +| 变量 | var | 函数级(函数内) | 可重复声明,存在 “变量提升”(声明提前到顶部) | +| 常量 | const | 块级 | 必须初始化,不可重新赋值;引用类型内部可改(如对象属性) | + +### 运算符 + +| 类型 | 常用运算符 | 关键说明 | +| ---------- | ----------------------- | ------------------------------------------------------------ | +| 算术运算符 | `+`、`-`、`*`、`/`、`%`(取余) | `+` 可拼接字符串(如 '2' + 3 → '23') | +| 赋值运算符 | `=`、`+=`(a+=b 即 a=a+b) | 简化赋值操作 | +| 比较运算符 | `==`(宽松)、`===`(严格) | `==` 会自动类型转换(0 == false → true);`===` 需类型和值都相同 | +| 逻辑运算符 | `&&`(与)、`\|\|` (或)、`!`(非) | 短路逻辑:`&& `遇 `false `返回该值,`\|\|` 遇 `true` 返回该值,`!`取反 | +| 自增自减 | `++`、`--` | 前置(`++a`:先加后用);后置(`a++`:先用后加) | +| 三元运算符 | 条件?结果 1 : 结果 2 | 简化简单 if 判断(如 age>18?' 成年 ':' 未成年 ') | + +## 作业 + +### 第一部分一至七题 + +#### 关键代码 + +```html +
+

+
+
+

+

+

+
+ +``` + +#### 效果展示 + +![](./Image/20251112_Image/show01.png) + +### 第二部分一、二、三题 + +#### 关键代码 + +```html +

+ +``` + +#### 效果展示 + +![](./Image/20251112_Image/show02.png) + +![](./Image/20251112_Image/show03.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251113-jsDOM\344\273\213\347\273\215.md" "b/\347\275\227\347\232\223\346\231\250/20251113-jsDOM\344\273\213\347\273\215.md" new file mode 100644 index 0000000000000000000000000000000000000000..c302a4023cf297f0cbf87f12343948ebbe66038d --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251113-jsDOM\344\273\213\347\273\215.md" @@ -0,0 +1,191 @@ +## 笔记 + +### DOM 核心概念 + +DOM 全称 **Document Object Model(文档对象模型)**,一句话说透核心:**把 HTML 页面变成 JS 能识别、能操作的 “树状对象体系”,是 JS 与 HTML 交互的唯一桥梁**。 + +### DOM 到底是什么? + +- 本质是 **“结构化的节点对象集合”**: + 1. 先按 HTML 嵌套关系,形成 “树状结构”(父子、兄弟节点层级); + 2. 再把 HTML 里的标签、文字、属性等,都变成 “DOM 节点对象”; + 3. 自带一套操作 API(比如 `getElementById`),让 JS 能 “抓节点、改节点”。 +- 通俗类比:HTML 是 “建筑图纸”(只能看),DOM 是 “可交互的建筑模型”(能拆改、能调整)—— 没有 DOM,JS 就 “看不见” 页面元素,更没法操作。 + +### 核心结构:DOM 树 + +HTML 标签的嵌套关系,在 DOM 里会变成 “树状结构”,每个组成部分都是 “节点”,关键分 3 类: + +| 节点类型 | 作用 | 示例 | +| ---------------- | ------------------------------------ | --------------------------- | +| Document(树根) | 代表整个 HTML 文档,所有操作的起点 | JS 里的 `document` 对象 | +| 元素节点(树枝) | 对应 HTML 标签,是最常操作的对象 | `
`、` + + + + +``` + +##### 对应的 DOM 树(直观层级) + +```plaintext +Document(树根) +└── html(根标签节点) + ├── head(元素节点) + │ └── title(元素节点) + │ └── "我的页面"(文本节点) + └── body(元素节点) + ├── h1(元素节点) + │ └── "标题"(文本节点) + └── select(元素节点,id="mySelect-year") + └── option(元素节点) + └── "1949年"(文本节点) +``` + +### 为什么需要 DOM? + +1. 结构化呈现:把杂乱的 HTML 标签,按层级整理成 “树”,JS 能顺着树快速找节点; +2. 可操作性:让 JS 能修改页面内容、样式、属性(比如改文字、换颜色、加标签); +3. 互动基础:支持监听点击、输入等事件(比如点击按钮弹出内容),是所有页面交互的核心。 + +### 总结 + +**DOM 是包含各类节点(文档节点、元素节点、文本节点等)的树状模型,`getElementBy`等 API 的作用是从 DOM 树中查找并返回「匹配的元素节点」,若找到则返回该元素节点对象,没找到则返回 `null`,然后对其进行对应操作。** + +## 作业 + +### 第一部分一、二、三题 + +#### 关键代码 + +```html +
+
+
+
+
+ 年份: + 月份: +
+
+ +
+
+ +``` + +#### 效果展示 + +![](./Image/20251113_Image/show01.png) + +### 第二部分 + +#### 关键代码 + +```html +
+
+
+ +``` + +#### 效果展示 + +![](./Image/20251113_Image/show02.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251114-js\346\265\201\347\250\213\346\216\247\345\210\266\350\257\255\345\217\245.md" "b/\347\275\227\347\232\223\346\231\250/20251114-js\346\265\201\347\250\213\346\216\247\345\210\266\350\257\255\345\217\245.md" new file mode 100644 index 0000000000000000000000000000000000000000..5f792bbab85d4940673273e199a645fdc685037b --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251114-js\346\265\201\347\250\213\346\216\247\345\210\266\350\257\255\345\217\245.md" @@ -0,0 +1,190 @@ +## 笔记 + +### 分支结构(根据条件执行不同代码) + +#### if 语句 + +- 作用:满足条件则执行对应代码块,否则跳过 +- 三种形式: + - 单条件:`if (条件) { 满足时执行 }` + - 双条件:`if (条件) { 满足时执行 } else { 不满足时执行 }` + - 多条件:`if (条件1) { 满足1执行 } else if (条件2) { 满足2执行 } else { 都不满足执行 }` +- 关键:条件为布尔值(true 执行,false 跳过),非布尔值会自动隐式转换(如 0→false、非 0 数字→true、空字符串→false) + +#### switch 语句 + +- 作用:根据一个变量 / 表达式的多个可能值,执行对应代码块 +- 核心规则: + - 匹配原则:`===` 严格匹配,`case`必须为一个固定值,不能为条件 + - 必须加 `break`:否则会穿透到下一个 `case` 执行 + - `default`:所有 `case` 都不匹配时执行(可选) + +### 循环结构 + +#### for 循环(已知循环次数) + +- 语法:`for (初始化变量; 循环条件; 变量更新) { 循环体 }` +- 适用场景:数组遍历、固定次数的重复操作(如循环 10 次) +- 关键:循环条件为 true 时继续执行,false 时退出;避免死循环(如条件永远为 true) + +#### while 循环(未知循环次数,先判断后执行) + +- 语法:`while (循环条件) { 循环体; 变量更新 }` +- 特点:先判断条件,不满足则一次都不执行 +- 注意:必须在循环体内更新变量,否则会陷入死循环 + +#### do...while 循环(未知循环次数,先执行后判断) + +- 语法:`do { 循环体; 变量更新 } while (循环条件)` +- 特点:至少执行一次循环体,再判断条件 +- 适用场景:需要确保代码块至少运行一次的场景(如表单验证重试) + +### 循环控制语句(调整循环执行) + +#### break + +- 作用:立即退出当前循环(或 switch 语句),后续代码不再执行 +- 场景:找到目标值后终止循环、满足特定条件时退出 + +#### continue + +- 作用:跳过当前循环的剩余代码,直接进入下一次循环判断 +- 注意:仅跳过当前次,不终止整个循环 + +### 关键注意点 + +1. 代码块 {}:单条语句可省略,但建议始终添加(提高可读性、避免语法错误) +2. 条件判断:优先使用 === 严格相等,避免 == 隐式转换导致的意外结果 +3. 死循环:循环条件必须有终止可能(如 i++、i--),否则会导致页面卡死 +4. 嵌套控制:多层循环 / 分支中,break/continue 仅作用于当前所在层级 + +## 作业 + +### 第一、二、三题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251114_Image/show01.png) + +### 第四、五题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251114_Image/show02.png) + +### 第六、七题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251114_Image/show03.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251117-js\345\207\275\346\225\260.md" "b/\347\275\227\347\232\223\346\231\250/20251117-js\345\207\275\346\225\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..72917d1b9f85e39b3d8fae5fc77fe0a8b3d94847 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251117-js\345\207\275\346\225\260.md" @@ -0,0 +1,133 @@ +## 笔记 + +### 函数 + +函数是 JavaScript 中封装代码、实现复用的核心机制,通过 `function` 关键字定义,可接收参数、执行逻辑并返回结果。 + +### 形参和实参 + +- **形参(形式参数)**:函数定义时括号内声明的变量,用于接收调用时传入的值,仅在函数内部有效。 + +- **实参(实际参数)**:函数调用时括号内传入的具体值,会传递给对应的形参。 + +- 补充: + + - 无形参函数传入实参时,实参存储在 `arguments` 对象(传统函数)或通过剩余参数(`...args`)获取(箭头函数)。 + - 有形参函数不传入实参时,形参值为`undefined`。 + + 为避免出错,建议按照强类型语言的语法书写函数,js特性多以了解为主。 + +### 函数的定义方式 + +#### 函数声明 + +使用 `function` 关键字开头,声明函数名,可在声明前后调用(函数提升)。 + +```javascript +function add(a, b) { + return a + b; +} +``` + +#### 函数表达式 + +将函数赋值给变量,需先定义再调用,可匿名也可命名。 + +```javascript +// 匿名函数表达式 +const subtract = function(a, b) { + return a - b; +}; +// 命名函数表达式 +const multiply = function mul(a, b) { + return a * b; +}; +``` + +#### 箭头函数 + +简洁语法,无自己的 `this`、`arguments`,不能作为构造函数。单形参时可以省略括号,无参和多参时不能省略。 + +```javascript +const divide = (a, b) => a / b; // 单表达式可省略大括号和 return +// 多语句需加括号和 return +const calculate = (a, b) => { + const sum = a + b; + return sum * 2; +}; +``` + +注意:函数表达式和箭头函数不具备函数提升特性,提前调用会报错。 + +### 直接调用 + +通过函数名 + 括号调用,是最常用的方式。 + +```javascript +const result = add(2, 3); // 5 +``` + +### 函数的返回值 + +- 函数通过 `return` 语句返回结果,执行到 `return` 后立即终止函数执行,后续代码不再运行。 + +```javascript +function test() { + return '结果'; + console.log('这句话不会执行'); +} +``` + +- 若函数无 `return` 语句或 `return` 后无值,默认返回 `undefined`。 + +```javascript +function noReturn() {} +console.log(noReturn()); // undefined +``` + +- 一个函数只能有一个返回值,若需返回多个值,可通过数组或对象包裹。 + +```javascript +// 数组形式返回多个值 +function getNumbers() { + return [1, 2, 3]; +} +const [a, b, c] = getNumbers(); + +// 对象形式返回多个值 +function getUser() { + return { name: 'Alice', age: 20 }; +} +const { name, age } = getUser(); +``` + +## 作业 + +### 第一、二题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251117_Image/show01.png) diff --git "a/\347\275\227\347\232\223\346\231\250/20251119-js\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251119-js\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..9d18471cbf984248f460e0c8bd63376a86f047d0 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251119-js\345\257\271\350\261\241.md" @@ -0,0 +1,479 @@ +## 笔记 + +### 对象的创建 + +对象是**键值对的集合**(键为字符串 / Symbol,值为任意类型:基本类型、函数、对象等),用于存储和组织相关数据与功能,最常用的创建语法如下: + +```js +// 基础语法:对象字面量 +let 对象名 = { 键1: 值1, 键2: 值2, ... }; + +// 示例1:基础用法 +let person = { + name: "张三", + age: 25, + isStudent: false, + sayHi: function() { + console.log("你好!"); + } +}; + +// 示例2:ES6+ 简写(属性名与变量名一致、方法简写) +let name = "李四"; +let age = 30; +let user = { + name, // 简写:等同于 name: name + age, + sayHi() { // 方法简写:等同于 sayHi: function() {} + console.log(`我是${this.name}`); + } +}; +``` + +### 对象操作 + +#### 增 + +直接通过**点语法 / 方括号语法**赋值即可(属性不存在时自动添加,[]内为字符串): + +```js +let obj = { name: "赵六" }; + +// 1. 添加普通属性 +obj.age = 32; // 点语法添加 +obj["gender"] = "男"; // 方括号语法添加 + +// 2. 添加方法 +obj.sayHello = function() { + console.log(`你好,我是${this.name}`); +}; + +// 3. 添加动态属性(ES6+) +let attrName = "hobbies"; +obj[attrName] = ["读书", "旅行"]; + +console.log(obj); +// 输出:{ name: "赵六", age: 32, gender: "男", sayHello: [Function], hobbies: ["读书", "旅行"] } +``` + +#### 删 + +通过 `delete` 运算符删除对象的**自身属性**(不影响原型链上的属性): + +```js +let obj = { name: "钱八", age: 35, gender: "男" }; + +// 删除自身属性 +delete obj.age; // 点语法指定属性 +delete obj["gender"]; // 方括号语法指定属性 + +console.log(obj); // 输出:{ name: "钱八" }(age 和 gender 已删除) + +// 特性说明: +// 1. 删除不存在的属性:返回 true(无报错) +delete obj.hobbies; // 输出:true + +// 2. 无法删除原型链上的属性 +let parent = { name: "父对象" }; +let child = Object.create(parent); // child 的原型是 parent +child.age = 20; +delete child.name; // 尝试删除原型上的 name,失败 +console.log(child.name); // 输出:父对象(仍能访问原型属性) + +// 3. 无法删除通过 var/let/const 声明的全局变量(非对象属性) +let globalVar = 10; +delete globalVar; // 输出:false(删除失败) +``` + +#### 改 + +若属性已存在,通过**点语法 / 方括号语法**重新赋值即可覆盖原有值: + +```js +let obj = { name: "孙七", age: 27 }; + +// 修改现有属性 +obj.name = "孙七修改后"; // 点语法修改 +obj["age"] = 28; // 方括号语法修改 + +console.log(obj); // 输出:{ name: "孙七修改后", age: 28 } + +// 注意:不可写属性无法修改(需通过属性描述符定义) +let obj2 = Object.defineProperty({}, "age", { + value: 30, + writable: false // 设为不可写 +}); +obj2.age = 35; // 失败(严格模式下报错) +console.log(obj2.age); // 输出:30(值未改变) +```` +#### 查 + +两种核心方式,根据属性名特点选择: + +- **点语法**:简洁直观,适合属性名为合法标识符(无特殊字符、非关键字) +- **方括号语法**:支持动态属性名、特殊字符属性名(如连字符、数字开头) + +```js +let obj = { + name: "王五", + "user-age": 28, // 特殊字符属性名(必须用引号包裹) + hobbies: ["篮球", "游戏"] +}; + +// 点语法访问 +console.log(obj.name); // 输出:王五 +console.log(obj.hobbies[0]); // 输出:篮球(访问对象中的数组元素) + +// 方括号语法访问 +console.log(obj["user-age"]); // 输出:28(特殊字符属性名必须用方括号) +let key = "name"; +console.log(obj[key]); // 输出:王五(动态属性名,变量key对应属性名) +console.log(obj[`hobbies`][1]); // 输出:游戏(模板字符串作为属性名) + +// 访问不存在的属性:返回 undefined +console.log(obj.gender); // 输出:undefined +``` + + +#### 添加方法 + +对象定义时直接添加: + +```javascript +const person = { + name: "张三", + age: 25, + // 方法定义 + sayHello: function() { + console.log(`你好,我是${this.name}。`); + }, + // ES6+ 方法简写(更推荐) + introduce() { + console.log(`我今年${this.age}岁。`); + } +}; + +person.sayHello(); // 输出:你好,我是张三。 +person.introduce(); // 输出:我今年25岁。 +``` + +动态添加方法:在对象创建之后,通过点语法或方括号语法给它添加新方法。 + +```javascript +const person = { + name: "李四" +}; + +// 使用点语法 +person.sayHi = function() { + console.log("Hi!"); +}; + +// 使用方括号语法 +person["sayGoodbye"] = function() { + console.log("Goodbye!"); +}; + +person.sayHi(); // 输出:Hi! +person.sayGoodbye(); // 输出:Goodbye! +``` + +#### 遍历对象 + +遍历对象主要是为了获取对象中所有的**键(key)和值(value)**。 + +##### `for...in` 循环(最常用) + +`for...in` 循环用于遍历对象自身的和继承的**可枚举属性**(不包括 `Symbol` 属性)。 + +**语法:** + +```javascript +for (const key in 对象) { + // 执行代码 +} +``` + +**示例:** + +```javascript +const person = { + name: "张三", + age: 25, + city: "北京" +}; + +for (const key in person) { + // hasOwnProperty 用于判断属性是否是对象自身的(不包括继承的) + if (person.hasOwnProperty(key)) { + console.log(key + ": " + person[key]); + } +} +// 输出: +// name: 张三 +// age: 25 +// city: 北京 +``` + +**注意事项:** + +- `for...in` 会遍历对象原型链上的属性,所以通常需要配合 `hasOwnProperty()` 来过滤掉继承的属性。 +- 遍历顺序不一定是插入顺序,对于数字键会按升序排列,字符串键按插入顺序。 + +##### `Object.keys()` 方法 + +`Object.keys()` 方法返回一个包含对象自身所有**可枚举属性**(不包括 `Symbol` 属性)的字符串数组。 + +**语法:** + +```javascript +Object.keys(对象) +``` + +**示例:** + +```javascript +const person = { + name: "张三", + age: 25, + city: "北京" +}; + +const keys = Object.keys(person); +console.log(keys); // 输出:["name", "age", "city"] + +keys.forEach(key => { + console.log(key + ": " + person[key]); +}); +// 输出: +// name: 张三 +// age: 25 +// city: 北京 +``` + +**注意事项:** + +- `Object.keys()` 只返回对象自身的属性,不包括继承的属性。 +- 返回的是一个数组,所以可以使用数组的方法(如 `forEach`、`map` 等)进行遍历。 + +##### `Object.values()` 方法 + +`Object.values()` 方法返回一个包含对象自身所有**可枚举属性**(不包括 `Symbol` 属性)的值的数组。 + +**语法:** + +```javascript +Object.values(对象) +``` + +**示例:** + +```javascript +const person = { + name: "张三", + age: 25, + city: "北京" +}; + +const values = Object.values(person); +console.log(values); // 输出:["张三", 25, "北京"] + +values.forEach(value => { + console.log(value); +}); +// 输出: +// 张三 +// 25 +// 北京 +``` + +##### `Object.entries()` 方法 + +`Object.entries()` 方法返回一个包含对象自身所有**可枚举属性**(不包括 `Symbol` 属性)的键值对数组。 + +**语法:** + +```javascript +Object.entries(对象) +``` + +**示例:** + +```javascript +const person = { + name: "张三", + age: 25, + city: "北京" +}; + +const entries = Object.entries(person); +console.log(entries); +// 输出:[["name", "张三"], ["age", 25], ["city", "北京"]] + +entries.forEach(([key, value]) => { + console.log(key + ": " + value); +}); +// 输出: +// name: 张三 +// age: 25 +// city: 北京 +``` + +**总结:** + +- 如果需要遍历键和值,推荐使用 `Object.entries()`。 +- 如果只需要键,使用 `Object.keys()`。 +- 如果只需要值,使用 `Object.values()`。 +- `for...in` 由于会遍历原型链,现在已经不推荐用于遍历对象的自身属性。 + +#### + +## 作业 + +### 第一部分第三至八题 + +#### 关键代码 + +```js + +``` + +#### 效果展示 + +![](./Image/20251119_Image/show01.png) + +### 第二部分一、二、三题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251119_Image/show02.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251120-js\345\206\205\351\203\250\345\257\271\350\261\241Math&Date.md" "b/\347\275\227\347\232\223\346\231\250/20251120-js\345\206\205\351\203\250\345\257\271\350\261\241Math&Date.md" new file mode 100644 index 0000000000000000000000000000000000000000..8470598e38da7162141cefaf4378e0408e2a0990 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251120-js\345\206\205\351\203\250\345\257\271\350\261\241Math&Date.md" @@ -0,0 +1,113 @@ +## 笔记 + +### Math常用方法 + +| 方法 | 描述 | 示例 | 结果 | +| --------------- | --------------------------------------------- | ----------------- | ---- | +| `Math.floor(x)` | **向下取整**(返回小于或等于 `x` 的最大整数) | `Math.floor(3.9)` | `3` | +| `Math.ceil(x)` | **向上取整**(返回大于或等于 `x` 的最小整数) | `Math.ceil(3.1)` | `4` | +| `Math.round(x)` | **四舍五入**到最接近的整数 | `Math.round(3.5)` | `4` | +| `Math.trunc(x)` | **去除小数部分**(直接截掉小数点后的数字) | `Math.trunc(3.9)` | `3` | +| `Math.max(a, b, ...)` | 返回所有参数中的**最大值** | `Math.max(1, 3, 2)` | `3` | +| `Math.min(a, b, ...)` | 返回所有参数中的**最小值** | `Math.min(1, 3, 2)` | `1` | +| `Math.abs(x)` | 返回 `x` 的**绝对值** | `Math.abs(-5)` | `5` | +| `Math.pow(x,y)` | 返回一个`x`的`y`**次方** | `Math.pow(3,3)` | `27` | +| `Math.random()` | 返回一个 `0`(包含)到 `1`(不包含)之间的伪随机数 | `Math.random()` | `[0, 1)` | + +### Date 常用方法 + +#### 创建 Date 对象 + +| 方法 | 描述 | 示例 | +| ------------------------------------------------------------ | --------------------------------------------------------- | ----------------------------------- | +| `new Date()` | 创建一个表示**当前日期和时间**的 Date 对象 | `const now = new Date();` | +| `new Date(dateString)` | 通过一个日期字符串创建 Date 对象 | `new Date("2023-10-27");` | +| `new Date(year, month, day, [hours, [minutes, [seconds, [ms]]]])` | 通过指定的年、月、日等创建 Date 对象(**月份从 0 开始**) | `new Date(2023, 9, 27, 14, 30, 0);` | + +#### Date常用方法 + +| 方法 | 描述 | 示例(假设日期为 2023-10-27) | +| --------------- | ------------------------------------------------------------ | ----------------------------- | +| `getFullYear()` | 返回**年份**(4 位数) | `2023` | +| `getMonth()` | 返回**月份**(0-11,0 表示一月) | `9` (表示十月) | +| `getDate()` | 返回一个月中的**某一天**(1-31) | `27` | +| `getDay()` | 返回一周中的**某一天**(0-6,0 表示星期日) | `5` (表示星期五) | +| `getHours()` | 返回**小时**(0-23) | `14` | +| `getMinutes()` | 返回**分钟**(0-59) | `30` | +| `getSeconds()` | 返回**秒**(0-59) | `45` | +| `getTime()` | 返回从 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)到该日期的**毫秒数**(时间戳) | `1672502400000` | +| `toString()` | 将 Date 对象转换为一个人类可读的字符串 | `"Fri Oct 27 2023 14:30:45 GMT+0800 (中国标准时间)"` | +| `toLocaleString()` | 将 Date 对象转换为一个**本地格式**的日期和时间字符串 | `"2023/10/27 14:30:45"` | +| `toLocaleDateString()` | 将 Date 对象转换为一个**本地格式**的日期字符串 | `"2023/10/27"` | +| `toLocaleTimeString()` | 将 Date 对象转换为一个**本地格式**的时间字符串 | `"14:30:45"` | +| `toISOString()` | 将 Date 对象转换为一个符合 **ISO 格式**的字符串(UTC 时间) | `"2023-10-27T06:3` | + +## 作业 + +### 第一部分第一、二、三题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251120_Image/show01.png) + + + +### 第二部分第一、二题 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251120_Image/show02.png) diff --git "a/\347\275\227\347\232\223\346\231\250/20251121-js\345\206\205\351\203\250\345\257\271\350\261\241Event&\346\225\260\347\273\204.md" "b/\347\275\227\347\232\223\346\231\250/20251121-js\345\206\205\351\203\250\345\257\271\350\261\241Event&\346\225\260\347\273\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..7f9047db48635266ddfceadfadff9c61ff49440f --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251121-js\345\206\205\351\203\250\345\257\271\350\261\241Event&\346\225\260\347\273\204.md" @@ -0,0 +1,147 @@ +## 笔记 + +### 事件与Event + +#### 事件的核心概念 + +- **事件**:用户操作(如点击、输入)或浏览器行为(如页面加载完成)触发的行为。 +- **事件流**:事件触发后在 DOM 树中的传播顺序,分为 **冒泡阶段**(从触发元素向上传播)和 **捕获阶段**(从顶层元素向下传播)。 +- **事件处理程序**:响应事件的函数(如点击按钮后执行的逻辑)。 + +#### Event常用方法 + +| 事件类型 | 触发场景 | 示例 | +| ----------- | --------------------------------- | ---------------------- | +| `click` | 鼠标左键点击元素 | 按钮点击、链接跳转 | +| `dblclick` | 鼠标左键双击元素 | 双击编辑文本 | +| `mouseover` | 鼠标移入元素(含子元素) | hover 提示框 | +| `mouseout` | 鼠标移出元素(含子元素) | hover 提示框消失 | +| `mousemove` | 鼠标在元素内移动 | 拖拽功能、鼠标轨迹 | +| `keydown` | 键盘按下(按住时连续触发) | 输入框快捷键、游戏控制 | +| `keyup` | 键盘松开 | 输入完成验证 | +| `input` | 输入框内容变化(实时触发) | 搜索框联想、实时校验 | +| `change` | 输入框内容确认变化(失焦 / 回车) | 下拉框选择、文件上传 | +| `focus` | 元素获得焦点(如点击输入框) | 输入框激活样式 | +| `blur` | 元素失去焦点(如点击输入框外) | 输入框失活、内容保存 | +| `submit` | 表单提交(点击提交按钮 / 回车) | 登录表单、搜索表单 | +| `load` | 页面 / 资源(图片、脚本)加载完成 | 页面初始化逻辑 | +| `resize` | 浏览器窗口大小改变 | 响应式布局调整 | +| `scroll` | 页面 / 元素滚动 | 滚动加载、回到顶部 | + +#### 事件绑定 + +##### HTML 属性绑定(不推荐,耦合度高) + +直接在 HTML 标签中通过 `on事件名` 属性指定处理函数,仅适用于简单场景。 + +```html + + + + +``` + +**缺点**:HTML 与 JS 耦合,无法绑定多个同类型事件。 + +##### DOM 属性绑定(简单场景可用) + +通过 JS 获取 DOM 元素后,直接给 `on事件名` 属性赋值(函数引用或匿名函数)。 + +```html + + + +``` + +**缺点**:同一事件只能绑定一个处理函数(后续绑定会覆盖前一个)。 + +##### `addEventListener`(推荐,功能最强) + +DOM 标准方法,支持绑定多个同类型事件、控制事件流(冒泡 / 捕获)、移除事件。 + +**语法:** + +```javascript +元素.addEventListener(事件名, 处理函数, [捕获阶段标志]); +// 第三个参数:true=捕获阶段触发,false=冒泡阶段触发(默认false) +``` + +**示例:** + +```html + + + +``` + +**优点**: + +- 支持多个同类型事件(按绑定顺序触发); +- 可控制事件流(捕获 / 冒泡); +- 可通过 `removeEventListener` 移除事件(避免内存泄漏)。 + +### 数组 + +#### 数组的创建 + +**创建方式:** + +```javascript +// 1. 字面量创建(最常用) +let arr1 = []; // 空数组 +let arr2 = [1, "hello", true, { name: "张三" }]; // 包含多种类型元素 + +// 2. 构造函数创建 +let arr3 = new Array(); // 空数组 +let arr4 = new Array(5); // 创建长度为5的空数组(元素为undefined) +let arr5 = new Array(1, 2, 3); // 创建包含指定元素的数组 +``` + +------ + +#### 数组操作 + +详见 **20251219-js数组高级方法** 笔记 + diff --git "a/\347\275\227\347\232\223\346\231\250/20251124-jsString\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251124-jsString\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..dd4f64eb2d9ae45a441e36e0219a6d5c073771f8 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251124-jsString\345\257\271\350\261\241.md" @@ -0,0 +1,122 @@ +## 笔记 + +### String常用方法 + +| 方法名 | 描述 | 示例 | +| --------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `charAt(index)` | 返回指定位置的字符 | `let str = 'hello'; console.log(str.charAt(1)); // 输出 'e'` | +| `concat(str1, str2, ...)` | 连接一个或多个字符串,并返回新的字符串 | `let str1 = 'hello'; let str2 = 'world'; console.log(str1.concat(', ', str2)); // 输出 'hello, world'` | +| `endsWith(searchString[, length])` | 判断字符串是否以指定的字符串结尾 | `let str = 'hello world'; console.log(str.endsWith('world')); // 输出 true` | +| `indexOf(searchValue[, fromIndex])` | 返回指定字符串在原字符串中第一次出现的位置,如果没有找到则返回 -1 | `let str = 'hello world'; console.log(str.indexOf('l')); // 输出 2` | +| `lastIndexOf(searchValue[, fromIndex])` | 返回指定字符串在原字符串中最后一次出现的位置,如果没有找到则返回 -1 | `let str = 'hello world'; console.log(str.lastIndexOf('l')); // 输出 9` | +| `length` | 返回字符串的长度 | `let str = 'hello'; console.log(str.length); // 输出 5` | +| `replace(searchValue, replaceValue)` | 在字符串中用一些字符替换另一些字符,返回替换后的新字符串。`searchValue` 可以是字符串或正则表达式 | `let str = 'hello world'; console.log(str.replace('world', 'javascript')); // 输出 'hello javascript'` | +| `slice(start[, end])` | 提取字符串的某个部分,并以新的字符串返回被提取的部分 | `let str = 'hello world'; console.log(str.slice(0, 5)); // 输出 'hello'` | +| `split([separator[, limit]])` | 将字符串分割成子字符串数组 | `let str = 'hello,world'; console.log(str.split(',')); // 输出 ['hello', 'world']` | +| `startsWith(searchString[, position])` | 判断字符串是否以指定的字符串开头 | `let str = 'hello world'; console.log(str.startsWith('hello')); // 输出 true` | +| `substring(start[, end])` | 返回字符串中指定的两个索引之间的字符 | `let str = 'hello world'; console.log(str.substring(0, 5)); // 输出 'hello'` | +| `toLowerCase()` | 将字符串转换为小写形式 | `let str = 'HELLO'; console.log(str.toLowerCase()); // 输出 'hello'` | +| `toUpperCase()` | 将字符串转换为大写形式 | `let str = 'hello'; console.log(str.toUpperCase()); // 输出 'HELLO'` | +| `trim()` | 删除字符串两端的空白字符 | `let str =' hello '; console.log(str.trim()); // 输出 'hello'` | + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251124_Image/show01.png) + +### 第二部分 + +#### 关键代码 + +```html + +``` + +#### 效果展示 + +![](./Image/20251124_Image/show02.png) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251126-js\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/\347\275\227\347\232\223\346\231\250/20251126-js\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..7bbb02e461558522b5db82e95b851f8425e6f713 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251126-js\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,10 @@ +## 笔记 + +| 方法名 | 所属对象 | 描述 | 语法 | 返回值 | 示例 | +| --------- | -------- | -------------------------------------------- | --------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `test` | `RegExp` | 检查字符串是否匹配正则表达式 | `regexObj.test(str)` | `boolean`,匹配返回 `true`,否则返回 `false` | `const regex = /abc/; const str = 'abcdef'; console.log(regex.test(str)); // true` | +| `exec` | `RegExp` | 在字符串中执行搜索匹配 | `regexObj.exec(str)` | 匹配成功返回包含匹配信息的数组,否则返回 `null`。数组的第一个元素是完整匹配项,后续元素是捕获组(如果有) | `const regex = /(\d+)/; const str = 'There are 12 items'; const result = regex.exec(str); if (result) { console.log(result[0]); // '12',完整匹配项 console.log(result[1]); // '12',第一个捕获组 }` | +| `match` | `String` | 使用正则表达式对字符串进行匹配,返回匹配结果 | `str.match(regex)` | 若未使用全局标志 `g`,返回包含第一个匹配项及捕获组(如果有)的数组,否则返回 `null`;若使用全局标志 `g`,返回包含所有匹配项的数组 | `const str = 'apple, banana, cherry'; const regex = /banana/; const result1 = str.match(regex); console.log(result1); // ['banana'] const regexGlobal = /\w+/g; const result2 = str.match(regexGlobal); console.log(result2); // ['apple', 'banana', 'cherry']` | +| `search` | `String` | 搜索字符串中匹配正则表达式的位置 | `str.search(regex)` | 若匹配成功,返回第一个匹配项的起始位置;否则返回 `-1` | `const str = 'Find the word here'; const regex = /word/; console.log(str.search(regex)); // 10` | +| `replace` | `String` | 用替换字符串替换匹配正则表达式的子字符串 | `str.replace(regex, replacement)` | 返回替换后的新字符串 | `const str = 'Hello, world'; const regex = /world/; const newStr = str.replace(regex, 'JavaScript'); console.log(newStr); // 'Hello, JavaScript'` | +| `split` | `String` | 根据正则表达式分割字符串 | `str.split(regex[, limit])` | 返回分割后的字符串数组。`limit` 可指定数组的最大长度 | `const str = 'a,b,c,d'; const regex = /,/; const arr = str.split(regex); console.log(arr); // ['a', 'b', 'c', 'd'] const arrLimited = str.split(regex, 2); console.log(arrLimited); // ['a', 'b']` | \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251127-js\345\274\202\345\270\270\345\244\204\347\220\206&\344\272\213\344\273\266\347\233\221\345\220\25401.md" "b/\347\275\227\347\232\223\346\231\250/20251127-js\345\274\202\345\270\270\345\244\204\347\220\206&\344\272\213\344\273\266\347\233\221\345\220\25401.md" new file mode 100644 index 0000000000000000000000000000000000000000..c46be4dfb6198cc1304f7c9ea4d849d1ddb34893 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251127-js\345\274\202\345\270\270\345\244\204\347\220\206&\344\272\213\344\273\266\347\233\221\345\220\25401.md" @@ -0,0 +1,153 @@ +## 笔记 + +### try...catch...finally 语句 + +```javascript +try { + // 可能抛出异常的代码 +} catch (error) { + // 捕获异常并处理 +} finally { + // 无论是否有异常都执行 +} +``` + +#### try 块 + +包含可能出错的代码。一旦其中代码抛出异常,程序立即跳转到 `catch` 块,`try` 块后续代码不再执行。 + +#### 3. catch 块 + +捕获 `try` 块抛出的异常。`catch` 的参数(常为 `error`)包含异常详细信息,如 `error.message` 为错误信息,`error.name` 是错误类型。 + +#### 4. finally 块 + +无论 `try` 块是否抛出异常,都会执行。常用于资源清理,如关闭数据库连接。 + +### throw 语句 + +- **作用**:手动抛出异常。当程序遇到不符合预期的条件时,可使用 `throw` 中断正常流程并抛出异常。 + +```javascript +function checkAge(age) { + if (age < 0) { + throw new Error('年龄不能为负数'); + } + return `年龄是 ${age}`; +} + +try { + let result = checkAge(-5); + console.log(result); +} catch (error) { + console.log('捕获到异常:', error.message); +} +``` + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html +
+
+ 用户名:
+ 密 码:
+ + +``` + +#### 效果展示 + +![](./Image/20251127_Image/show01.gif) + +### 第二部分 + +#### 关键代码 + +```html +
+

联系方式

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+ +``` + +#### 效果展示 + +![](./Image/20251127_Image/show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251128-js\344\272\213\344\273\266\347\233\221\345\220\25402.md" "b/\347\275\227\347\232\223\346\231\250/20251128-js\344\272\213\344\273\266\347\233\221\345\220\25402.md" new file mode 100644 index 0000000000000000000000000000000000000000..d79a757fc27cbbe320ea679e07e6443eb184c6b8 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251128-js\344\272\213\344\273\266\347\233\221\345\220\25402.md" @@ -0,0 +1,363 @@ +## 笔记 + +# 事件对象(event/e)笔记 + +## 一、通用属性与方法 + +| 类别 | 属性 / 方法 | 白话解释 | 返回值 | +| ------------ | ------------------- | ------------------------------------------------------------ | -------------------------------------------------------------- | +| 找触发元素 | `target` | 实际触发事件的 DOM 元素。例如,点击列表中的 `li`,`target` 就是该 `li` 元素。 | 触发事件的 DOM 元素对象 | +| 认事件类型 | `type` | 事件的名称,以字符串形式呈现,如 `focus`、`click`、`keydown` 等。 | 表示事件类型的字符串 | +| 阻止默认行为 | `preventDefault()` | 用于取消浏览器的默认动作,比如回车刷新页面、链接跳转、右键菜单弹出等。 | 无返回值。该方法用于阻止浏览器的默认行为。 | +| 阻止事件冒泡 | `stopPropagation()` | 防止事件向上冒泡到父元素,避免嵌套元素间的事件冲突。 | 无返回值。该方法用于阻止事件在 DOM 树中向上冒泡。 | + +### 找触发元素示例 +```javascript +// 输入框获焦时添加红色边框 +const inputs = document.querySelectorAll('.txt'); +inputs.forEach(item => { + item.addEventListener('focus', (e) => { + e.target.style.border = '5px solid red'; + }); +}); +``` + +### 认事件类型示例 +```javascript +// 一个函数处理多种事件 +function handleInput(e) { + if (e.type === 'focus') { + e.target.style.border = 'red'; + } else if (e.type === 'blur') { + e.target.style.border = 'gray'; + } +} +inputs.forEach(item => { + item.addEventListener('focus', handleInput); + item.addEventListener('blur', handleInput); +}); +``` + +### 阻止默认行为示例 +```javascript +// 输入框按回车不刷新页面,并打印内容 +inputs[0].addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); // 阻止默认回车行为 + console.log('输入内容:', e.target.value); + } +}); +// 禁用页面右键菜单 +document.addEventListener('contextmenu', (e) => { + e.preventDefault(); + alert('禁止右键'); +}); +``` + +### 阻止事件冒泡示例 +```javascript +// 点击输入框不触发父元素的 click 事件 +const child = document.querySelector('.txt'); +const parent = document.getElementById('txtBorder'); +child.addEventListener('click', (e) => { + e.stopPropagation(); // 阻止冒泡 + console.log('输入框被点击'); +}); +parent.addEventListener('click', () => { + console.log('父元素被点击'); // 点击输入框时此代码不会执行 +}); +``` + +## 二、专属属性 + +### 键盘事件(keydown / keyup / keypress) + +| 属性 | 白话解释 | 返回值 | +| ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------------- | +| `key` | 按键的「语义名称」,区分大小写,功能键也包含其中,`a`、`A`、`Enter`、`Backspace` 等。 | 表示按键语义名称的字符串 | +| `code` | 按键的「物理位置名称」,不区分大小写,如 `KeyA`、`ArrowLeft`、`Space` 等。 | 表示按键物理位置名称的字符串 | +| `ctrlKey`/`shiftKey`/`altKey` | 表示是否按住 `ctrl`/`shift`/`alt` 键,返回布尔值。 | `true` 或 `false`,表示是否按住 `ctrl`/`shift`/`alt`键 | + +### 键盘事件示例 +```javascript +// 检测回车、删除、Ctrl + S 操作 +inputs[0].addEventListener('keydown', (e) => { + // 按回车提交 + if (e.key === 'Enter') { + e.preventDefault(); + console.log('提交:', e.target.value); + } + // 按删除提示 + if (e.key === 'Backspace') { + console.log('正在删除内容'); + } + // Ctrl + S 保存 + if (e.ctrlKey && e.key ==='s') { + e.preventDefault(); + console.log('执行保存操作'); + } +}); +// 检测方向键 +inputs[0].addEventListener('keydown', (e) => { + if (e.code === 'ArrowLeft') console.log('按了左箭头'); + if (e.code === 'Space') console.log('按了空格键'); +}); +// 检测 Shift + A(大写 A) +if (e.shiftKey && e.key === 'A') console.log('按了大写 A'); +// Mac 下 Command + C +if (e.metaKey && e.key === 'c') console.log('Mac 复制'); +``` + +### 鼠标事件(click / mousedown / mousemove / mouseover) + +| 属性 | 白话解释 | 返回值 | +| --------------- | ------------------------------------------------------------ | -------------------------------------------------------------- | +| `clientX/Y` | 鼠标相对于「可视窗口」的坐标,不包含滚动条的偏移量。 | 表示鼠标相对于可视窗口的水平(`clientX`)或垂直(`clientY`)坐标的数字 | +| `pageX/Y` | 鼠标相对于「整个文档」的坐标,包含滚动条的偏移量。 | 表示鼠标相对于整个文档的水平(`pageX`)或垂直(`pageY`)坐标的数字 | +| `button` | 按下的鼠标按键,`0` 代表左键,`1` 代表滚轮,`2` 代表右键。 | `0`(左键)、`1`(滚轮)、`2`(右键)中的一个数字 | +| `relatedTarget` | 鼠标移入或移出时的「关联元素」。例如在 `mouseover` 事件中,它表示从哪个元素移过来的。 | 鼠标移入或移出时的关联 DOM 元素对象 | + +### 鼠标事件示例 +```javascript +// 点击页面显示鼠标相对于可视窗口的位置 +document.addEventListener('click', (e) => { + console.log('相对于窗口:', e.clientX, e.clientY); +}); +// 滚动后仍能获取鼠标相对于整个文档的准确位置 +document.addEventListener('click', (e) => { + console.log('相对于文档:', e.pageX, e.pageY); +}); +// 区分左键、右键点击 +document.addEventListener('mousedown', (e) => { + if (e.button === 0) console.log('左键点击'); + if (e.button === 2) { + e.preventDefault(); + console.log('右键点击'); + } +}); +// 鼠标移入输入框时,显示从哪个元素移过来的 +inputs[0].addEventListener('mouseover', (e) => { + console.log('从', e.relatedTarget.tagName, '移过来'); +}); +``` + +### 焦点事件(focus / blur / focusin / focusout) + +| 属性 | 白话解释 | 返回值 | +| --------------- | ------------------------------------------------------------ | -------------------------------------------------------------- | +| `relatedTarget` | 在焦点切换时的关联元素。在 `focus` 事件中,它是失去焦点的元素;在 `blur` 事件中,它是获得焦点的元素。 | 焦点切换时的关联 DOM 元素对象 | + +### 焦点事件示例 +```javascript +// 焦点切换时提示焦点来源或目标 +inputs.forEach(item => { + item.addEventListener('focus', (e) => { + console.log('焦点从', e.relatedTarget?.placeholder, '移到当前输入框'); + }); + item.addEventListener('blur', (e) => { + console.log('焦点从当前输入框移到', e.relatedTarget?.placeholder); + }); +}); +``` + +### 表单事件(change / input / submit) + +| 属性 / 操作 | 白话解释 | 返回值 | +| ------------------ | ------------------------------------------------------------ | -------------------------------------------------------------- | +| `e.target.value` | 表单元素的当前值,需通过 `target` 获取,并非 `event` 直接属性。 | 表单元素的当前值,具体类型取决于表单元素类型(如输入框为字符串) | +| `e.target.checked` | 复选框或单选框是否被选中,返回布尔值。 | `true` 或 `false`,表示复选框或单选框是否被选中 | +| `submit`阻止 | 阻止表单的默认提交行为,避免页面刷新。 | 无返回值。该方法用于阻止表单的默认提交行为。 | + +### 表单事件示例 +```javascript +// 实时监听输入框内容变化 +inputs[0].addEventListener('input', (e) => { + console.log('实时输入:', e.target.value); +}); +// 监听单选框选中状态 +const radio = document.querySelector('input[type="radio"]'); +radio.addEventListener('change', (e) => { + console.log('是否选中:', e.target.checked); +}); +// 表单提交时验证,不刷新页面 +const form = document.querySelector('form'); +form.addEventListener('submit', (e) => { + e.preventDefault(); + console.log('表单提交,内容:', new FormData(form)); +}); +``` + +## 总结 + +掌握以下 3 步,可解决 90% 的事件处理场景: + +1. **找元素**:利用 `e.target` 获取触发事件的 DOM 元素。 +2. **拿信息**:依据事件类型获取相关上下文信息,如键盘事件用 `key`,鼠标事件用 `clientX`,焦点事件用 `relatedTarget` 等。 +3. **做操作**:根据需求使用 `preventDefault()` 阻止默认行为,或用 `stopPropagation()` 阻止事件冒泡。 + +## 作业 +### 第一部分 +#### 关键代码 +```html +
+ +
+
+ 中国的“国球”是什么(   +

A.篮球B.排球C.乒乓球D.羽毛球

+
+
+
+ + + +
+
+
+
+ 用户名:
+ 密 码:
+
+
+ +``` +#### 效果展示 +![](./Image/20251128_Image/show01.gif) +### 第二部分 +#### 关键代码 +```html + +``` +#### 效果展示 +![](./Image/20251128_Image/show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251201-js\344\272\213\344\273\266\347\233\221\345\220\25403.md" "b/\347\275\227\347\232\223\346\231\250/20251201-js\344\272\213\344\273\266\347\233\221\345\220\25403.md" new file mode 100644 index 0000000000000000000000000000000000000000..0517431f707f0b362b1fbb87900c9f14eb25e88c --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251201-js\344\272\213\344\273\266\347\233\221\345\220\25403.md" @@ -0,0 +1,107 @@ +## 笔记 + +### 文本编辑事件 + +#### 核心事件(文本 / 内容操作) + +- `copy`:复制操作时触发(快捷键、右键菜单复制) +- `cut`:剪切操作时触发(快捷键、右键菜单剪切) +- `paste`:粘贴操作时触发(快捷键、右键菜单粘贴) +- `select`:文本框(input/textarea)或可编辑元素(contenteditable)中文本被选中时触发 + +#### 关键操作(Clipboard API) + +- 获取剪贴板内容:`event.clipboardData.getData('text')`(paste 事件中使用) +- 设置剪贴板内容:`event.clipboardData.setData('text', 内容)`(copy/cut 事件中,需先阻止默认行为) +- 阻止默认操作:`event.preventDefault()`(拦截复制 / 粘贴,自定义处理逻辑) + +### 二、拖放对象与放置目标事件 + +#### 拖放前提 + +- 拖拽元素需设置 `draggable="true"`(图片、链接默认可拖拽) + +#### 拖拽对象事件(源元素) + +- `dragstart`:开始拖拽时触发(可设置拖拽数据 `event.dataTransfer.setData()`) +- `drag`:拖拽过程中持续触发 +- `dragend`:拖拽结束(无论成功与否)触发 + +#### 放置目标事件(目标元素) + +- `dragenter`:拖拽元素进入目标时触发(需阻止默认行为,否则无法成为放置目标) +- `dragover`:拖拽元素在目标上移动时触发(必须阻止默认行为,否则 `drop` 不触发) +- `dragleave`:拖拽元素离开目标时触发 +- `drop`:在目标上释放拖拽元素时触发(完成放置,通过 `event.dataTransfer.getData()` 获取拖拽数据) + +#### 数据传递(DataTransfer API) + +- 设置拖拽数据:`event.dataTransfer.setData('text', 数据)`(dragstart 事件中) +- 获取拖拽数据:`event.dataTransfer.getData('text')`(drop 事件中) +- 设置拖拽效果:`event.dataTransfer.effectAllowed = 'copy/move/link'`(限制拖拽行为) + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html + +
+ 拖拽我到下方区域 +
+
+ 请将上方文本拖放到这里 +
+ + +``` + +#### 效果展示 +![20251201Show01](https://qiniu.lhchen.asia//20251201Show01.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251203-jsDOM\345\257\271\350\261\241\345\217\212\345\205\266\345\270\270\347\224\250\346\226\271\346\263\225.md" "b/\347\275\227\347\232\223\346\231\250/20251203-jsDOM\345\257\271\350\261\241\345\217\212\345\205\266\345\270\270\347\224\250\346\226\271\346\263\225.md" new file mode 100644 index 0000000000000000000000000000000000000000..c5c2f471ff517c39689b28bcf44a8225faf0b335 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251203-jsDOM\345\257\271\350\261\241\345\217\212\345\205\266\345\270\270\347\224\250\346\226\271\346\263\225.md" @@ -0,0 +1,203 @@ +## 笔记 + +### Document 对象常用属性 + +#### 基础结构相关 + +- `document.documentElement`:获取 HTML 根元素(`` 标签) +- `document.head`:获取文档的 `` 元素 +- `document.body`:获取文档的 `` 元素 +- `document.title`:获取或设置文档的标题(对应 `` 标签内容) +- `document.URL`:获取当前文档的完整 URL +- `document.domain`:获取当前文档的域名(跨域相关场景常用) +- `document.referrer`:获取跳转至当前文档的前一个页面 URL(来源页面) + +#### 元素获取相关(便捷属性) + +- `document.forms`:获取文档中所有 `<form>` 元素的集合(HTMLCollection) +- `document.images`:获取文档中所有 `<img>` 元素的集合(HTMLCollection) +- `document.links`:获取文档中所有 `<a>` 标签(带 href 属性)和 `<area>` 元素的集合(HTMLCollection) +- `document.scripts`:获取文档中所有 `<script>` 元素的集合(HTMLCollection) +- `document.styleSheets`:获取文档中所有样式表(包括 `<style>` 和外部 CSS)的集合 + +#### 文档状态与元信息 + +- `document.readyState`:获取文档加载状态(loading:加载中;interactive:DOM 可交互;complete:完全加载完成) +- `document.characterSet`:获取或设置文档的字符编码(如 UTF-8) +- `document.doctype`:获取文档的 DOCTYPE 声明 +- `document.documentURI`:与 URL 类似,返回文档的统一资源标识符(部分场景下与 URL 等效) + +#### 其他常用属性 + +- `document.cookie`:获取或设置当前文档的 Cookie(字符串格式,需自行解析/拼接) +- `document.defaultView`:获取文档所属的窗口对象(即 window,部分浏览器兼容场景使用) +- `document.activeElement`:获取当前文档中获得焦点的元素(如输入框、按钮等) + +### Document 对象常用方法 + +#### 元素查询方法 + +- `querySelector(selector)`:根据 CSS 选择器获取第一个匹配的元素(返回单个 DOM 元素,支持复杂选择器) +- `querySelectorAll(selector)`:根据 CSS 选择器获取所有匹配的元素(NodeList,静态集合,不动态更新) + +#### 元素创建与插入/删除 + +- `createElement(tagName)`:创建一个指定标签名的新 DOM 元素 +- `createTextNode(text)`:创建一个文本节点(包含指定文本内容) +- `createDocumentFragment()`:创建文档片段(用于批量插入元素,提升性能,不直接属于 DOM 树) +- `appendChild(child)`:将子元素添加到指定父元素的末尾(若子元素已存在,会移动位置) +- `insertBefore(newChild, referenceChild)`:在参考子元素之前插入新子元素 +- `removeChild(child)`:删除指定的子元素(需通过父元素调用) +- `replaceChild(newChild, oldChild)`:用新子元素替换旧子元素 + +#### 文档操作与加载 + +- `write(text)`:向文档中写入内容(可写 HTML 字符串,加载期间使用,加载完成后会覆盖文档) +- `writeln(text)`:与 write 类似,末尾自动添加换行符 +- `open()`:打开文档输出流(配合 write 使用,较少单独使用) +- `close()`:关闭文档输出流(结束 write 写入操作) +- `getSelection()`:获取用户在文档中选中的文本内容(返回 Selection 对象) + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html + <div class="left-section"> + <h1 class="section-title">训练</h1> + <div class="base-card small-card" id="colorSwapCard"> + 天行健君子以自强不息<br>地势坤君子以厚德载物 + </div> + <div class="btn-group"> + <input type="button" class="common-btn" id="colorSwapBtn" value="交互颜色"> + <input type="button" class="common-btn" id="urlFetchBtn" value="获取地址"> + </div> + <div class="base-card small-card" id="textAppendCard"></div> + <div class="input-group"> + <input type="text" class="text-input-box" id="userInputTxt" placeholder="请输入文字"> + <input type="button" class="common-btn" id="textAppendBtn" value="添加"> + </div> + </div> + <div class="right-section"> + <h1 class="section-title">综合练习</h1> + <div class="base-card large-card" id="themeChangeCard"> + <h2>李白《行路难・其一》</h2> + 金樽清酒斗十千,玉盘珍羞直万钱。<br> + 停杯投箸不能食,拔剑四顾心茫然。<br> + 欲渡黄河冰塞川,将登太行雪满山。<br> + 闲来垂钓碧溪上,忽复乘舟梦日边。<br> + 行路难!行路难!多歧路,今安在?<br> + 长风破浪会有时,直挂云帆济沧海。<br> + </div> + <input type="button" class="common-btn" id="themeChangeBtn" value="切换主题"> + <div class="image-container" id="imageDialogArea"> + <a href="" id="imageOpenLink">打开图片对话框</a> + </div> + <div class="avatar-container"> + <input type="button" class="common-btn" id="addAvatarBtn" value="添加用户头像"> + <div class="avatar-list" id="avatarListContainer"></div> + </div> + </div> + <script> + // 训练1 + const colorSwapBtn = document.querySelector('#colorSwapBtn'); + const colorSwapCard = document.querySelector('#colorSwapCard'); + function swapBgTextColor() { + // getComputedStyle()获取实参dom元素的全局样式 + let targetCardStyle = getComputedStyle(colorSwapCard) + let currentBgColor = targetCardStyle.backgroundColor + let currentTextColor = targetCardStyle.color + colorSwapCard.style.backgroundColor = currentTextColor + colorSwapCard.style.color = currentBgColor + } + colorSwapBtn.addEventListener('click', swapBgTextColor) + + // 训练2 + const urlFetchBtn = document.querySelector('#urlFetchBtn'); + function fetchPageUrl() { + let pageUrl = document.URL + console.log(pageUrl); + + } + urlFetchBtn.addEventListener("click", fetchPageUrl) + + // 训练3 + const textAppendCard = document.querySelector('#textAppendCard') + const userInputTxt = document.querySelector('#userInputTxt') + const textAppendBtn = document.querySelector('#textAppendBtn') + function appendInputText() { + let textSpan = document.createElement("span") + let inputContent = document.createTextNode(userInputTxt.value) + // appendChild()将实参的dom节点添加到调用的dom节点列表中的尾部 + textSpan.appendChild(inputContent); + textAppendCard.appendChild(textSpan); + } + textAppendBtn.addEventListener("click", appendInputText) + + // 综合练习01 + const themeChangeBtn = document.querySelector('#themeChangeBtn'); + const themeChangeCard = document.querySelector('#themeChangeCard') + let themeIndex = 0 + function switchCardTheme() { + // 数组存储前景色和背景色,省略 + const foregroundColors = []; + const backgroundColor = []; + themeChangeCard.style.color = foregroundColors[themeIndex] + themeChangeCard.style.backgroundColor = backgroundColor[themeIndex] + themeIndex++ + if (themeIndex == foregroundColors.length) { + themeIndex = 0 + } + } + themeChangeBtn.addEventListener("click", switchCardTheme) + + // 综合练习02:图片对话框 + const imageOpenLink = document.querySelector('#imageOpenLink') + const imageDialogArea = document.querySelector('#imageDialogArea') + let dialogContainer = document.createElement("div") + let imageWrapper = document.createElement("div") + let deleteLink = document.createElement("a") + let deleteText = document.createTextNode("删除") + deleteLink.appendChild(deleteText) + let imgElement = document.createElement('img') + imgElement.src = "https://lf-flow-web-cdn.doubao.com/obj/flow-doubao/doubao/chat/static/image/logo-icon-white-bg.72df0b1a.png" + function openImageDialog(e) { + e.preventDefault(); + imageWrapper.appendChild(imgElement) + dialogContainer.appendChild(deleteLink) + dialogContainer.appendChild(imageWrapper) + imageDialogArea.appendChild(dialogContainer) + } + imageOpenLink.addEventListener("click", openImageDialog) + function removeImageDialog() { + imageDialogArea.removeChild(dialogContainer) + } + deleteLink.addEventListener("click", removeImageDialog) + + // 综合练习03 + </script> + <script> + let addAvatarBtn = document.querySelector("#addAvatarBtn"); + let avatarListContainer = document.querySelector("#avatarListContainer") + let avatarIndex = 0 + function addUserAvatar() { + // 数组存储头像地址,省略 + const userAvatarUrls = []; + let avatarImage = document.createElement("img") + avatarImage.src = userAvatarUrls[avatarIndex] + avatarImage.className = "avatar-item" + avatarImage.alt = `用户头像${avatarIndex + 1}` + avatarListContainer.appendChild(avatarImage) + avatarIndex++ + if (avatarIndex == userAvatarUrls.length){ + alert("头像数量达到上限") + } + } + addAvatarBtn.addEventListener("click", addUserAvatar) + </script> +``` + +#### 效果展示 +![20251203Show01](https://qiniu.lhchen.asia//20251203Show01.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251204-jsDOM\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\347\275\227\347\232\223\346\231\250/20251204-jsDOM\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..1d957e5479bbb816b302ef03ec6f9636c90dba2d --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251204-jsDOM\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,501 @@ +## 笔记 + +### 节点属性 + +#### 通用节点属性(所有节点共享) +| 属性名 | 说明 | +| ------ | ---- | +| `nodeType` | 节点类型标识(数字):元素节点=1、文本节点=3、属性节点=2、文档节点=9、注释节点=8 | +| `nodeName` | 节点名称:元素节点为大写标签名(如 DIV)、文本节点为 `#text`、注释节点为 `#comment` | +| `nodeValue` | 节点值:文本节点为文本内容、属性节点为属性值、元素/文档节点为 `null` | +| `parentNode` | 当前节点的父节点(唯一,文本/属性节点的父节点为对应元素节点) | +| `childNodes` | 当前节点的所有子节点集合(NodeList,包含文本、注释等所有类型节点) | +| `firstChild`/`lastChild` | 当前节点的首个/最后一个子节点(包含所有类型节点) | +| `previousSibling`/`nextSibling` | 当前节点的前一个/后一个兄弟节点(包含所有类型节点) | + +示例: +```javascript +// 获取元素节点 +const div = document.querySelector('div'); +console.log(div.nodeType); // 1(元素节点) +console.log(div.nodeName); // DIV(大写标签名) +console.log(div.nodeValue); // null(元素节点无值) + +// 获取文本节点 +const textNode = div.firstChild; +console.log(textNode.nodeType); // 3(文本节点) +console.log(textNode.nodeName); // #text +console.log(textNode.nodeValue); // 输出 div 内的文本内容 + +// 父/子/兄弟节点 +console.log(div.parentNode); // 获取 div 的父节点 +console.log(div.childNodes); // 获取 div 所有子节点(含文本、注释) +console.log(div.firstChild); // div 第一个子节点 +console.log(div.nextSibling); // div 的下一个兄弟节点 +``` + +#### 元素节点专属属性(Element 特有) +| 属性名 | 说明 | +| ------ | ---- | +| `children` | 仅包含子元素节点的集合(HTMLCollection) | +| `firstElementChild`/`lastElementChild` | 首个/最后一个子元素节点 | +| `previousElementSibling`/`nextElementSibling` | 前一个/后一个兄弟元素节点 | +| `id`/`class`/`name`/`title`/`href`/`src`/`value` | 元素内置属性(表单元素含 `disabled`/`checked`) | +| `style` | 行内样式对象(如 `element.style.color`) | +| `className` | 类名字符串,可直接赋值修改 | +| `dataset` | 获取 `data-*` 前缀的自定义属性(如 `data-id` → `element.dataset.id`) | + +示例: +```javascript +const div = document.querySelector('div'); +// 结构相关 +console.log(div.children); // 仅获取 div 的子元素(不含文本/注释) +console.log(div.firstElementChild); // div 第一个子元素 +console.log(div.nextElementSibling); // div 的下一个兄弟元素 + +// 内置属性 +div.id = 'box'; // 设置 id +console.log(div.href); // 获取 a 标签的 href(若 div 是 a 标签) +console.log(div.checked); // 获取复选框选中状态 + +// 样式/类名 +div.style.color = 'red'; // 设置行内样式 +div.className = 'active'; // 修改类名(覆盖原有) +console.log(div.className); // 输出 active + +// 自定义属性(data-*) +// HTML:<div data-id="123" data-name="测试"></div> +console.log(div.dataset.id); // 123 +console.log(div.dataset.name); // 测试 +div.dataset.age = 20; // 添加 data-age="20" +``` + +### 节点操作 + +#### 创建节点 +| 方法 | 说明 | +| ---- | ---- | +| `document.createElement(tagName)` | 创建元素节点 | +| `document.createTextNode(text)` | 创建文本节点 | +| `document.createComment(comment)` | 创建注释节点 | +| `document.createDocumentFragment()` | 创建文档片段(批量操作节点,提升性能) | + +示例: +```javascript +// 创建元素节点 +const div = document.createElement('div'); +div.className = 'box'; // 设置类名 +div.textContent = '新元素'; // 设置文本 + +// 创建文本节点 +const textNode = document.createTextNode('这是纯文本'); + +// 创建注释节点 +const commentNode = document.createComment('这是注释'); + +// 创建文档片段(批量添加 li 示例) +const fragment = document.createDocumentFragment(); +for (let i = 0; i < 5; i++) { + const li = document.createElement('li'); + li.textContent = `列表项${i+1}`; + fragment.appendChild(li); // 先添加到片段(不触发 DOM 重绘) +} +document.querySelector('ul').appendChild(fragment); // 一次性添加到 DOM +``` + +#### 插入节点 +| 方法 | 说明 | +| ---- | ---- | +| `parent.appendChild(child)` | 子节点添加到父节点末尾(已存在则移动) | +| `parent.insertBefore(newChild, referenceChild)` | 在参考节点前插入新节点,参考节点不存在则插末尾 | +| `element.insertAdjacentElement(position, newElement)` | 元素指定位置插入新元素(position:beforebegin/afterbegin/beforeend/afterend) | +| `element.insertAdjacentText(position, text)` | 元素指定位置插入文本节点(position 同上) | + +示例: +```javascript +const parent = document.querySelector('.parent'); +const newDiv = document.createElement('div'); +newDiv.textContent = '新节点'; + +// appendChild:添加到父节点末尾 +parent.appendChild(newDiv); + +// insertBefore:插入到第一个子元素前 +const firstChild = parent.firstElementChild; +parent.insertBefore(newDiv, firstChild); + +// insertAdjacentElement:多位置插入 +// HTML 结构:<div class="parent">原有内容</div> +parent.insertAdjacentElement('beforebegin', newDiv); // 父元素前面 +parent.insertAdjacentElement('afterbegin', newDiv); // 父元素内开头 +parent.insertAdjacentElement('beforeend', newDiv); // 父元素内末尾(同 appendChild) +parent.insertAdjacentElement('afterend', newDiv); // 父元素后面 + +// insertAdjacentText:插入文本 +parent.insertAdjacentText('afterbegin', '开头文本'); +``` + +#### 复制节点 +| 方法 | 说明 | +| ---- | ---- | +| `node.cloneNode(deep)` | 复制节点:deep=false 浅复制(仅当前节点)、deep=true 深复制(含所有子节点) | + +示例: +```javascript +const original = document.querySelector('#box'); +// 浅复制:仅复制 div 标签,不含子节点/文本 +const cloneShallow = original.cloneNode(false); +// 深复制:复制 div 及所有子节点、文本、属性 +const cloneDeep = original.cloneNode(true); + +// 修改复制节点的 id(避免重复) +cloneDeep.id = 'box-clone'; + +// 添加到 DOM +document.body.appendChild(cloneDeep); +``` + +#### 删除与替换节点 +| 方法 | 说明 | +| ---- | ---- | +| `parent.removeChild(child)` | 父节点删除子节点(返回被删节点,需确保是直接子元素) | +| `element.remove()` | 直接删除当前元素(IE 不兼容) | +| `parent.replaceChild(newChild, oldChild)` | 新节点替换父节点中的旧节点(返回旧节点) | + +示例: +```javascript +const parent = document.querySelector('.parent'); +const child = document.querySelector('.child'); + +// removeChild:通过父节点删除 +const removedNode = parent.removeChild(child); // 返回被删节点 + +// remove:直接删除(推荐) +child.remove(); + +// replaceChild:替换节点 +const newNode = document.createElement('p'); +newNode.textContent = '替换后的内容'; +const oldNode = parent.replaceChild(newNode, child); // 返回被替换的旧节点 +``` + +### innerHTML/Text, outerHTML/Text +| 方法 | 说明 | +| ---- | ---- | +| `innerHTML` | 获取/设置元素内的 HTML 内容(解析标签,有 XSS 风险) | +| `innerText` | 获取/设置元素内的文本内容(过滤标签,受 CSS 影响) | +| `outerHTML` | 获取/设置包含当前元素本身的 HTML 内容(替换元素本身) | +| `outerText` | 获取/设置包含当前元素本身的文本内容(替换元素为文本) | +| `textContent` | W3C 标准,获取/设置文本(不受 CSS 影响,性能更优) | + +示例: +```html +<!-- 初始结构 --> +<div id="box" style="display: none;"> + <p>Hello <span>World</span></p> +</div> +``` + +```javascript +const box = document.querySelector('#box'); + +// innerHTML +console.log(box.innerHTML); // 输出:<p>Hello <span>World</span></p> +box.innerHTML = '<h1>新的HTML内容</h1>'; // 设置后替换所有子节点 + +// innerText(受 display: none 影响,返回空) +console.log(box.innerText); // 空字符串 +box.style.display = 'block'; +console.log(box.innerText); // 输出:新的HTML内容(过滤标签) + +// textContent(不受 CSS 影响) +console.log(box.textContent); // 输出:新的HTML内容(即使 display: none 也能获取) + +// outerHTML +console.log(box.outerHTML); // 输出:<div id="box" style="display: block;"><h1>新的HTML内容</h1></div> +box.outerHTML = '<p>替换整个div的内容</p>'; // div 被替换为 p 标签 + +// outerText(极少用) +const test = document.createElement('div'); +test.textContent = '测试'; +console.log(test.outerText); // 输出:测试 +test.outerText = '替换为文本'; // 整个 div 元素被替换为文本节点 +``` + +#### 核心区别补充示例 +```javascript +// innerHTML vs innerText +const div = document.createElement('div'); +div.innerHTML = '<strong>加粗文本</strong>'; // 解析标签,生成 strong 元素 +console.log(div.innerHTML); // <strong>加粗文本</strong> +console.log(div.innerText); // 加粗文本(仅文本) + +// outerHTML vs innerHTML +console.log(div.innerHTML); // <strong>加粗文本</strong>(仅内部) +console.log(div.outerHTML); // <div><strong>加粗文本</strong></div>(包含自身) +``` + +### 总结 +1. 节点属性分**通用属性**(所有节点共享,如 nodeType/parentNode)和**元素专属属性**(如 children/dataset),操作元素优先用元素专属属性(过滤无用节点)。 +2. 节点操作核心:创建(createElement)→ 插入(appendChild/insertBefore)→ 复制(cloneNode)→ 删除/替换(remove/replaceChild),批量操作优先用文档片段提升性能。 +3. 文本/HTML 操作:`innerHTML` 解析标签(有 XSS 风险),`innerText/textContent` 仅处理文本(textContent 性能更优、不受 CSS 影响),`outerHTML` 会替换元素本身。 + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html +<div class="item01"> + <input type="text" name="" id="item01-txt" placeholder="请输入文字"> + <select name="" id="item01-select"> + <option value="red">红</option> + <option value="green">绿</option> + <option value="yellow">黄</option> + <option value="blue">蓝</option> + </select> + <input type="button" name="" id="item01-add-btn" value="添加"> + </div> + <div class="item02"> + <div class="lyric"> + <p>向前方!我们的血气方刚!崭锋芒,震虎狼!</p> + <p>向前方!我们的步伐铿锵!风雨里,我挺起胸膛!</p> + <p>向前方!我们的热血滚烫!将使命责任扛在肩上!</p> + <p>向前方!铁流滚滚向前方!乘风破浪,威震八方,势不可挡!</p> + </div> + <input type="text" name="" id="item02-txt" placeholder="请输入歌名"> + <input type="button" name="" id="item02-sure-btn" value="确认"> + </div> + <div class="item03"> + <ul id="movie-list"> + <li class="movie" data-number="1">1</li> + <li class="movie" data-number="2">2</li> + <li class="movie" data-number="3">3</li> + <li class="movie" data-number="4">4</li> + </ul> + <input type="text" name="" id="item03-number" placeholder="请输入编号"> + <input type="button" name="" id="item03-delete-btn" value="确认"> + </div> + <div class="item04"> + <ul id="vegetable-list"> + <li class="vegetable">黄瓜</li> + <li class="vegetable">茄子</li> + <li class="fruit">芒果</li> + </ul> + <ul id="fruit-list"> + <li class="fruit">西瓜</li> + <li class="fruit">蜜橘</li> + <li class="vegetable">萝卜</li> + </ul> + <input type="button" name="" id="item04-move-btn" value="移动"> + </div> + <div class="item05"> + <h3>在《倚天屠龙记》中,张三丰是_____派的掌门</h3> + <input type="radio" name="choose" id="a">A.少林 + <input type="radio" name="choose" id="b">B.武当 + <input type="radio" name="choose" id="c">A.昆仑 + <input type="radio" name="choose" id="d">A.峨眉<br> + <input type="button" name="" id="item04-submit-btn" value="提交"> + </div> + <script> + // 训练01 + let item01Div = document.querySelector('.item01') + let item01Txt = document.querySelector('#item01-txt') + let item01Select = document.querySelector('#item01-select') + let item01AddBtn = document.querySelector('#item01-add-btn') + function myItem01Add() { + let item01TxtSpan = document.createElement('span') + let setTxt = document.createTextNode(item01Txt.value) + let index = item01Select.selectedIndex; + let fgc = item01Select.options[index].value + item01TxtSpan.style.color = fgc + item01TxtSpan.appendChild(setTxt); + item01Div.appendChild(item01TxtSpan) + } + item01AddBtn.addEventListener("click", myItem01Add) + + // 训练02 + let item02Div = document.querySelector('.item02') + let item02Txt = document.querySelector('#item02-txt') + let item02SureBtn = document.querySelector('#item02-sure-btn') + let item02TxtP = document.createElement('p') + let item02Judge01 = true + function myItem02Add() { + let getTxt = document.createTextNode(item02Txt.value) + if ("钢铁洪流进行曲" == item02Txt.value && item02Judge01) { + let setTxt = document.createTextNode(getTxt.textContent) + item02TxtP.appendChild(setTxt) + item02Div.insertBefore(item02TxtP, document.querySelector('.lyric')) + item02Judge01 = false + } else if ("钢铁洪流进行曲" != item02Txt.value) { + if (!item02Judge01) { + item02Div.removeChild(item02TxtP) + } + item02Judge01 = true + } + } + item02SureBtn.addEventListener("click", myItem02Add) + + // 训练03 + let item03Div = document.querySelector('.item03') + let item03MovieList = document.querySelector('#movie-list') + let item03Movie = document.getElementsByClassName('movie') + let item03Number = document.querySelector('#item03-number') + let item03DeleteBtn = document.querySelector('#item03-delete-btn') + let item03TxtP = document.createElement('p') + function myItem03Delete() { + let item03Judge01 = true + let number = item03Number.value; + Array.from(item03Movie).forEach(item => { + if (item.dataset.number == number) { + item03Judge01 = false + item03MovieList.removeChild(item) + item03TxtP.textContent = '' + } + }) + if (item03Judge01 && item03TxtP.textContent == '') { + item03TxtP.appendChild(document.createTextNode('该编号不存在,请重新输入')) + item03Div.appendChild(item03TxtP) + item03Number.value = '' + } + } + item03DeleteBtn.addEventListener("click", myItem03Delete) + + // 训练04 + let item04Vegetable = document.querySelector('#vegetable-list') + let item04Fruit = document.querySelector('#fruit-list') + let item04Radish = document.querySelector('#fruit-list>.vegetable') + let item04Mango = document.querySelector('#vegetable-list>.fruit') + let item04MoveBtn = document.querySelector('#item04-move-btn') + function myItem04Change() { + let temporary01 = item04Mango; + let temporary02 = item04Radish; + item04Vegetable.replaceChild(temporary02, item04Mango); + + item04Fruit.appendChild(temporary01); + } + item04MoveBtn.addEventListener("click", myItem04Change) + + // 训练05 + let item05Div = document.querySelector('.item05') + let item05Choose = Array.from(document.querySelectorAll('[name="choose"]')) + let item05SubmitBtn = document.querySelector('#item04-submit-btn') + function myItem05Submit() { + for (let i = 0; i < item05Choose.length; i++) { + if (item05Choose[i].checked && item05Choose[i].id == 'b') { + console.log(true); + break + } + } + + } + item05SubmitBtn.addEventListener("click", myItem05Submit) + </script> +``` + +#### 效果展示 +![20251204Show01](https://cdn.lhchen.asia//20251204Show01.gif) +### 第一部分 + +#### 关键代码 +```html +<div class="item01"> + <p>一生只爱一人</p> + <a href="">将粗体改为斜体</a> + </div> + <div class="item02"> + <select name="" id="year"></select> + <select name="" id="month"></select> + <select name="" id="day"></select> + </div> + <div class="item03"> + 请选择表情:<select name="" id="emoji-list"></select> + </div> + <script> + // 综合练习01 + let item01TxtP = document.querySelector('.item01>p') + let item01TxtA = document.querySelector('.item01>a'); + let item01Div = document.querySelector('.item01'); + let item01ChangeP = document.createElement('p') + item01ChangeP.appendChild(document.createTextNode('一生只爱一人')) + let item01Judge01 = true + function myItem01Change(e) { + if (!item01Judge01) { + return + } + item01Judge01 = false + e.preventDefault() + item01Div.replaceChild(item01ChangeP, item01TxtP) + item01ChangeP.style.fontWeight = 'normal'; + item01ChangeP.style.fontStyle = 'italic'; + item01TxtA.textContent = "将斜体改为粗体" + } + item01TxtA.addEventListener("click", myItem01Change) + + // 综合练习02 + let item02Year = document.querySelector('#year') + let item02Month = document.querySelector('#month') + let item02Day = document.querySelector('#day') + let yearHTML = "" + for (let i = 1949; i <= 2049; i++) { + let str = `<option value = "${i}">${i}年</option>` + yearHTML += str + } + item02Year.innerHTML = yearHTML; + let monthHTML = "" + for (let i = 1; i <= 12; i++) { + let str = `<option value = "${i}">${i}月</option>` + monthHTML += str + } + item02Month.innerHTML = monthHTML + function myItem02Date() { + let year = item02Year.value + let month = item02Month.value + let dayNumber = new Date(year, month, 0) + let datehHTML = "" + for (let i = 1; i <= dayNumber.getDate(); i++) { + let str = `<option value = "${i}">${i}\日</option>` + datehHTML += str + } + item02Day.innerHTML = datehHTML + console.log(`${year}年${month}月有${dayNumber.getDate()}天`); + + } + item02Year.addEventListener("change", myItem02Date) + item02Month.addEventListener("change", myItem02Date) + //综合练习03 + const emojiUrls = [ + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f600.png", // 微笑 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f601.png", // 大笑 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f602.png", // 笑哭 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f603.png", // 憨笑 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f604.png", // 得意 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f605.png", // 害羞 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f606.png", // 眨眼 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f607.png", // 得意 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f608.png", // 坏笑 + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f609.png" // 挑眉 + ]; + const emojiNames = ["微笑", "大笑", "笑哭", "憨笑", "得意", "害羞", "眨眼", "得意", "坏笑", "挑眉"]; + let item03EmojiSelect = document.querySelector('#emoji-list') + let item03EmojiItemName = document.createElement("option") + let item03Div = document.querySelector('.item03'); + let item03EmojiItemImage = document.createElement("img") + emojiNames.forEach(name => { + let item03EmojiItemName = document.createElement("option") + let item03EmojiName = document.createTextNode(`${name}`) + item03EmojiItemName.appendChild(item03EmojiName) + item03EmojiSelect.appendChild(item03EmojiItemName) + }) + function myItem03Select() { + let item03index = item03EmojiSelect.selectedIndex; + + item03EmojiItemImage.src = emojiUrls[item03index] + item03Div.appendChild(item03EmojiItemImage) + } + item03EmojiSelect.addEventListener("change", myItem03Select) + </script> +``` +#### 效果展示 +![20251204Show02](https://qiniu.lhchen.asia//20251204Show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251205-jswindow\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251205-jswindow\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..ce1687213c85b317fedfa2ec9d5fb08c04354892 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251205-jswindow\345\257\271\350\261\241.md" @@ -0,0 +1,212 @@ +## 笔记 + +window 是浏览器全局对象,代表浏览器窗口。包含全局属性(如 document、location)、方法(如 alert、setTimeout),以及事件(如 load、resize)。全局变量 / 函数默认挂载其上,是 DOM 和 BOM 的核心访问入口。 + +### 常用方法 + +| 方法/属性 | 作用说明 | 示例代码 | +| ----------------------------- | --------------------------------------------------------- | ------------------------------------------------------------ | +| window.open() | 打开新窗口/标签页,可指定 URL、窗口尺寸、位置等参数 | `window.open('https://example.com', '_blank', 'width=500,height=300')` | +| window.close() | 关闭当前窗口(仅对 `window.open()` 打开的窗口生效) | `const newWin = window.open(); newWin.close();` | +| window.innerWidth/innerHeight | 获取窗口可视区域宽/高(含滚动条,只读) | `const w = window.innerWidth; const h = window.innerHeight;` | +| setTimeout(fn, delay) | 延迟指定毫秒执行一次函数,返回定时器 ID | `const timer = setTimeout(() => console.log('延迟执行'), 1000);` | +| clearTimeout(timerId) | 清除 `setTimeout` 创建的定时器 | `clearTimeout(timer);` | +| setInterval(fn, interval) | 每隔指定毫秒重复执行函数,返回定时器 ID | `const timer = setInterval(() => console.log('重复执行'), 1000);` | +| clearInterval(timerId) | 清除 `setInterval` 创建的定时器 | `clearInterval(timer);` | +| window.alert(message) | 显示无返回值的警告弹窗 | `window.alert('操作成功!');` | +| window.confirm(message) | 显示确认弹窗,返回布尔值(确认:true/取消:false) | `const res = window.confirm('确定删除?'); if(res) { /* 执行删除 */ }` | +| window.prompt(text, def) | 显示输入弹窗,返回输入内容(取消返回 null),def 为默认值 | `const name = window.prompt('请输入姓名', '张三');` | +| window.scrollTo(x, y) | 滚动到文档指定坐标,支持平滑滚动配置 | `window.scrollTo({ top: 0, behavior: 'smooth' }); // 平滑回到顶部` | +| window.scrollBy(x, y) | 相对当前位置滚动指定距离 | `window.scrollBy(0, 100); // 向下滚动 100px` | + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html +<audio src="https://samplelib.com/sounds/mp3/sample-3s.mp3" controls id="item01"></audio> + <div class="item02"> + <a href="">退出</a> + </div> + <div class="item03"> + <ul id="movie-list"> + <li class="movie">1.影片详情</li> + <li class="movie">2.影片详情</li> + <li class="movie">3.影片详情</li> + <li class="movie">4.影片详情</li> + </ul> + </div> + <div class="item04"> + <input type="button" name="" id="item04-open-btn" value="广告"> + </div> + <button id="item05-btn">打开窗口</button><br> + <input type="text" id="timer-input" readonly> + <button id="start-btn">开始计时</button> + <button id="pause-btn">暂停</button> + <script> + // 训练01 + function myItem01Play() { + alert('只有会员才能播放歌曲,请登录') + } + document.querySelector('#item01').addEventListener("play", myItem01Play) + + // 训练02 + function myItem02Quit(e) { + e.preventDefault() + let item02Result = window.confirm('您确定退出登录吗') + if (item02Result) { + console.log('退出成功'); + } else { + console.log('退出失败'); + + } + } + document.querySelector('.item02>a').addEventListener("click", myItem02Quit) + + // 训练03 + function myItem03Particulars() { + window.open("", 'particulars', "height=500,width=800,top=200,left=200") + } + document.querySelector('#movie-list').addEventListener("click", myItem03Particulars) + + // 训练04 + function myItem04Close() { + let advertising = window.open("", 'particulars', "height=500,width=800,top=200,left=200") + setTimeout(function () { + advertising.close() + }, 5000) + } + document.querySelector('#item04-open-btn').addEventListener("click", myItem04Close) + + function myItem05OpenWindow() { + let dropWindow = window.open("", "dropWindow", "height=200,width=300,top=0,left=0"); + const moveStep = 10; + const moveTimer = setInterval(() => { + + let currentTop = parseInt(dropWindow.screenTop); + if (currentTop >= (window.screen.height - 200)) { + clearInterval(moveTimer); + return; + } + dropWindow.moveTo(0, currentTop + moveStep); + }, 100); + } + document.querySelector('#item05-btn').addEventListener("click", myItem05OpenWindow); + + // 训练06 + let timerInterval = null; + let count = 0; + function myItem06Start() { + if (timerInterval) return; + timerInterval = setInterval(() => { + count++; + document.querySelector('#timer-input').value = count; + }, 1000); + } + function myItem06Pause() { + clearInterval(timerInterval); + timerInterval = null; + } + document.querySelector('#start-btn').addEventListener("click", myItem06Start); + document.querySelector('#pause-btn').addEventListener("click", myItem06Pause); + </script> +``` + +#### 效果展示 +![20251205Show01](https://qiniu.lhchen.asia//20251205Show01.gif) + + +### 第二部分 + +#### 关键代码 + +```html +<div class="exercise" id="exercise01"> + <button id="item01-calc-btn">开始答题</button> + <div id="item01-result"></div> + </div> + + <div class="exercise" id="exercise02"> + <button id="item02-ques-btn">开始答题</button> + <div id="item02-result"></div> + </div> + + <div class="exercise" id="exercise03"> + <button id="item03-start-btn">开始播放</button> + <button id="item03-stop-btn">停止播放</button> + <div id="img-container"></div> + </div> + + <script> + function myItem01CalcSum() { + let num1 = Math.floor(Math.random() * 9) + 1; + let num2 = Math.floor(Math.random() * 9) + 1; + let correctSum = num1 + num2; + let userAnswer = window.prompt(`${num1} + ${num2} = ?`, ""); + if (userAnswer === null) { + document.getElementById('item01-result').innerText = "你取消了答题"; + return; + } + if (isNaN(userAnswer) || userAnswer === "") { + window.alert("请输入有效的数字!"); + myItem01CalcSum(); + return; + } + let userNum = parseInt(userAnswer); + let isCorrect = userNum === correctSum; + let tipMsg = isCorrect ? "正确!" : `错误!正确答案是${correctSum}`; + let isContinue = window.confirm(`${tipMsg} 是否继续答题?`); + document.getElementById('item01-result').innerText = tipMsg; + if (isContinue) { + myItem01CalcSum(); + } + } + document.getElementById('item01-calc-btn').addEventListener('click', myItem01CalcSum); + + function myItem02SelectCity() { + let question = "2024年奥运会在哪座城市举办?\nA.罗马\nB.北京\nC.伦敦\nD.巴黎"; + let correctAnswer = "D"; + let userAnswer = window.prompt(question, ""); + if (userAnswer === null) { + document.getElementById('item02-result').innerText = "你取消了答题"; + return; + } + userAnswer = userAnswer.toUpperCase(); + let resultMsg = userAnswer === correctAnswer ? "答案正确!" : `答案错误!正确答案是${correctAnswer}`; + document.getElementById('item02-result').innerText = resultMsg; + } + document.getElementById('item02-ques-btn').addEventListener('click', myItem02SelectCity); + + const imgList = [ + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f600.png", + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f601.png", + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f602.png", + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f603.png", + "https://cdn.jsdelivr.net/npm/emoji-datasource-apple@15.0.1/img/apple/64/1f604.png" + ]; + let imgTimer = null; + let currentImgIndex = 0; + + function myItem03StartShowImg() { + if (imgTimer) return; + imgTimer = window.setInterval(() => { + let imgContainer = document.getElementById('img-container'); + imgContainer.innerHTML = `<img src="${imgList[currentImgIndex]}" alt="图片${currentImgIndex + 1}">`; + currentImgIndex = (currentImgIndex + 1) % imgList.length; + }, 1000); + } + + function myItem03StopShowImg() { + window.clearInterval(imgTimer); + imgTimer = null; + } + + document.getElementById('item03-start-btn').addEventListener('click', myItem03StartShowImg); + document.getElementById('item03-stop-btn').addEventListener('click', myItem03StopShowImg); + </script> +``` + +#### 效果展示 +![20251205Show02](https://qiniu.lhchen.asia//20251205Show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251208-jsBOM\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251208-jsBOM\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..5e0834dfbaa6f40b157289c5d84fe460c54b39c3 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251208-jsBOM\345\257\271\350\261\241.md" @@ -0,0 +1,55 @@ +## 笔记 + +BOM(浏览器对象模型)用于操作浏览器窗口,无统一标准但核心 API 通用。核心对象包括:window(顶层对象,全局作用域)、document(文档对象,操作 DOM)、location(控制 URL,如 href 跳转、reload 刷新)、history(浏览器历史,back/forward/go 导航)、navigator(获取浏览器信息)、screen(屏幕相关数据)。 + +关键特性:跨文档通信、窗口大小 / 位置控制、定时器(setTimeout/setInterval)。注意:BOM 依赖浏览器环境,无 DOM 独立存在,需区分 BOM(操作浏览器)与 DOM(操作页面内容)的边界,兼容性需适配不同浏览器差异。 + +### 常用方法 +BOM(浏览器对象模型)用于操作浏览器窗口,无统一标准但核心 API 通用。以下按核心对象分类,以表格形式整理各对象的常用方法/属性,结构清晰且贴合实际开发场景: + +#### location(控制 URL) +`location` 用于操作当前页面的 URL,实现跳转、刷新等核心导航功能。 + +| 方法/属性 | 作用说明 | 示例代码 | +|--------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------| +| location.href | 获取/设置当前页面 URL(最常用的跳转方式) | `console.log(location.href); location.href = 'https://example.com';` | +| location.reload() | 重新加载页面,参数 `true` 强制从服务器加载(跳过缓存) | `location.reload(); // 普通刷新` <br> `location.reload(true); // 强制刷新` | +| location.host | 获取 URL 中的主机名 + 端口号(如 `example.com:8080`) | `console.log(location.host);` | +| location.pathname | 获取 URL 中的路径部分(如 `/index.html`) | `console.log(location.pathname);` | +| location.search | 获取 URL 中的查询参数(如 `?id=1&name=test`) | `console.log(location.search);` | +| location.hash | 获取/设置 URL 中的哈希值(如 `#top`) | `location.hash = '#footer'; // 跳转到页面锚点` | + +#### history(浏览器历史) +`history` 用于操作浏览器的历史记录,实现前进、后退、跳转等导航操作。 + +| 方法/属性 | 作用说明 | 示例代码 | +|--------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------| +| history.back() | 回退到历史记录上一页(等同于浏览器后退按钮) | `history.back();` | +| history.forward() | 前进到历史记录下一页(等同于浏览器前进按钮) | `history.forward();` | +| history.go(n) | 跳转到历史记录指定页:n=0 刷新,正数前进,负数后退 | `history.go(-2); // 后退 2 页` <br> `history.go(1); // 前进 1 页` | +| history.length | 获取历史记录的总条数(只读) | `console.log(history.length); // 查看当前会话的历史记录数` | + +#### navigator(获取浏览器信息) +`navigator` 用于获取浏览器及客户端设备的相关信息,常用于浏览器兼容判断。 + +| 方法/属性 | 作用说明 | 示例代码 | +|--------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------| +| navigator.userAgent | 获取浏览器用户代理字符串(判断浏览器类型/版本、设备等) | `console.log(navigator.userAgent); // 如 Chrome/120.0.0.0 Safari/537.36` | +| navigator.language | 获取浏览器的首选语言(如 `zh-CN`、`en-US`) | `console.log(navigator.language);` | +| navigator.platform | 获取浏览器运行的操作系统平台(如 `Win32`、`MacIntel`) | `console.log(navigator.platform);` | +| navigator.onLine | 判断浏览器是否联网(返回布尔值,仅供参考) | `if(navigator.onLine) { console.log('已联网'); }` | + +#### screen(屏幕相关数据) +`screen` 用于获取客户端屏幕的分辨率、可用区域等硬件相关信息。 + +| 方法/属性 | 作用说明 | 示例代码 | +|--------------------------|--------------------------------------------------------------------------|--------------------------------------------------------------------------| +| screen.width/height | 获取屏幕物理分辨率的宽/高(只读,不含任务栏等) | `const screenW = screen.width; const screenH = screen.height;` | +| screen.availWidth/availHeight | 获取屏幕可用宽/高(排除任务栏、系统边框等,只读)| `const availW = screen.availWidth; const availH = screen.availHeight;` | +| screen.colorDepth | 获取屏幕的颜色深度(通常为 24 或 32) | `console.log(screen.colorDepth); // 输出 24` | + +### 核心注意事项 +1. `window` 作为顶层对象,其属性/方法可省略 `window.` 直接调用(如 `alert()` 等同于 `window.alert()`); +2. 窗口操作(`open()`/`close()`/`moveTo()`)受浏览器安全策略限制,无用户交互触发时易被拦截; +3. `location.href` 跳转与 `history.go()` 导航的区别:前者会新增历史记录,后者仅操作已有记录; +4. `navigator.userAgent` 可被篡改,仅作为浏览器判断的参考,不可作为唯一依据。 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251210-jsStyle\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251210-jsStyle\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..4af2db8e7ad3ea30209b990bd03ebc95b763c342 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251210-jsStyle\345\257\271\350\261\241.md" @@ -0,0 +1,156 @@ +## 笔记 + +### Style 对象常用属性 + +| 类别 | 属性名 | 说明 | 示例 | +| -------- | ----------------------- | ---------------------------------------------------------- | ------------------------------------------------------------ | +| 尺寸布局 | `width` | 设置 / 获取元素宽度(需带单位,如 px/em) | `elem.style.width = '200px'` | +| 尺寸布局 | `height` | 设置 / 获取元素高度(需带单位) | `const h = elem.style.height` | +| 尺寸布局 | `margin` | 外边距简写属性(可拆分 marginTop/marginLeft 等) | `elem.style.margin = '10px 20px'` | +| 尺寸布局 | `padding` | 内边距简写属性(可拆分 paddingTop/paddingRight 等) | `elem.style.padding = '8px'` | +| 尺寸布局 | `overflow` | 内容溢出处理方式(visible/hidden/scroll/auto) | `elem.style.overflow = 'hidden'` | +| 视觉样式 | `color` | 文本颜色(支持十六进制、RGB、颜色名) | `elem.style.color = '#ff0000'` | +| 视觉样式 | `backgroundColor` | 元素背景颜色 | `elem.style.backgroundColor = 'rgb(255,255,0)'` | +| 视觉样式 | `opacity` | 元素透明度(0-1 数值,1 为不透明) | `elem.style.opacity = '0.8'` | +| 视觉样式 | `border` | 边框简写属性(可拆分 borderWidth/borderColor/borderStyle) | `elem.style.border = '1px solid #ccc'` | +| 视觉样式 | `cursor` | 鼠标指针样式(pointer/default/help 等) | `elem.style.cursor = 'pointer'` | +| 文本样式 | `fontSize` | 字体大小(需带单位) | `elem.style.fontSize = '16px'` | +| 文本样式 | `textAlign` | 文本对齐方式(left/center/right/justify) | `elem.style.textAlign = 'center'` | +| 文本样式 | `lineHeight` | 行高(可带单位或纯数值) | `elem.style.lineHeight = '1.5'` | +| 定位相关 | `position` | 定位方式(static/relative/absolute/fixed/sticky) | `elem.style.position = 'absolute'` | +| 定位相关 | `top/left/right/bottom` | 定位元素偏移量(需带单位,非 static 定位生效) | `elem.style.left = '50%'` | +| 定位相关 | `zIndex` | 元素堆叠顺序(整数,定位元素生效) | `elem.style.zIndex = '999'` | +| 显示控制 | `display` | 元素显示方式(none/block/inline/flex 等) | `elem.style.display = 'flex'` | +| 批量操作 | `cssText` | 批量设置 / 获取所有内联样式(高效替代逐个设置) | `elem.style.cssText = 'width:100px; height:50px;'` | +| 遍历相关 | `length` | 返回内联样式的属性数量(用于遍历所有样式) | `for(let i=0; i<elem.style.length; i++) { console.log(elem.style[i]) }` | + +### Style 对象常用方法 + +| 方法名 | 说明 | 示例 | +| ----------------------- | ------------------------------------------------------------ | ------------------------------------------------------ | +| `setProperty()` | 按属性名设置样式值,支持自定义属性,可指定 `important` 优先级 | `elem.style.setProperty('color', 'blue', 'important')` | +| `getPropertyValue()` | 按属性名获取内联样式值(返回字符串) | `const color = elem.style.getPropertyValue('color')` | +| `removeProperty()` | 移除指定内联样式属性,恢复元素默认样式 | `elem.style.removeProperty('display')` | +| `getPropertyPriority()` | 获取样式属性的优先级(返回 'important' 或空字符串) | `const prio = elem.style.getPropertyPriority('color')` | + +## 补充说明 + +1. `style` 对象仅操作**内联样式**(元素 `style` 属性),无法获取 CSS 类 / 样式表中的样式; +2. 样式属性名采用驼峰命名(如 `backgroundColor`),对应 CSS 中的短横线命名(`background-color`); +3. 批量设置样式时,`cssText` 比逐个设置属性更高效,但会覆盖原有内联样式。 + +## 作业 + +### 第一部分 + +#### 关键代码 +```html + .laohu { + width: 200px; + height: 50px; + background-color: orange; + margin-bottom: 20px; + border-radius: 0 10px 10px 0; + line-height: 50px; + text-align: center; + font-size: 24px; + color: #FFF; + transition: 0.3s linear; + } + + .xiaohu { + width: 300px; + height: 80px; + line-height: 80px; + font-size: 40px; + } + <div class="item01"> + <div class="txt">哈基米哦南北绿豆</div><input type="button" name="" id="amplification" value="放大"> + </div> + <div class="item02"> + </div> + <div class="item03"> + <div class="laohu">老胡来了</div> + <div class="laohu">老胡来也</div> + <div class="laohu">老胡去了</div> + <div class="laohu">老胡去也</div> + <div class="laohu">老胡来去</div> + <div class="laohu">老胡去来</div> + </div> + <script> + // 训练01 + let item01Txt = document.querySelector('.txt') + let item01Btn = document.querySelector('#amplification') + let txtSize = Number(getComputedStyle(item01Txt).fontSize.replace(/px$/, '')); + function myItme01Click() { + console.log(txtSize); + txtSize += 2 + item01Txt.style.fontSize = `${txtSize}px` + item01Txt.style.color = getRandomHexColor() + } + function getRandomHexColor() { + const randomColor = Math.floor(Math.random() * 0xffffff).toString(16); + return '#' + randomColor.padStart(6, '0'); + } + item01Btn.addEventListener("click", myItme01Click); + + // 训练02 + let item02Div = document.querySelector('.item02') + function myItme02MoveCome() { + item02Div.style.border = "5px double blue" + } + function myItme02MoveOut() { + item02Div.style.removeProperty('border'); + } + item02Div.addEventListener("mousemove", myItme02MoveCome) + item02Div.addEventListener("mouseout", myItme02MoveOut) + + // 综合训练01 + let laohu = document.getElementsByClassName('laohu') + function myItme03Move(e) { + e.target.classList.add('xiaohu') + } + function myItme03Out(e) { + e.target.classList.remove('xiaohu') + } + Array.from(laohu).forEach(xiaohu => { + xiaohu.addEventListener("mousemove", myItme03Move) + xiaohu.addEventListener("mouseout", myItme03Out) + }) + </script> +``` + +#### 效果展示 +![20251210Show01](https://qiniu.lhchen.asia//20251210Show01.gif) +### 第二部分 + +#### 关键代码 + +```html + <div class="image01"></div> + <div class="image02"></div> + <div class="image03"></div> + <script> + let draggingElement = null + let image = document.getElementsByTagName("div"); + function imageActivate(e) { + draggingElement = e.target + } + function imageMove(e) { + if (!draggingElement) return + draggingElement.style.top = `${e.clientY}px` + draggingElement.style.left = `${e.clientX}px` + } + document.addEventListener("mousemove", imageMove) + function imageUnactivate() { + draggingElement = null + } + Array.from(image).forEach(picture => { + picture.addEventListener("mousedown", imageActivate) + picture.addEventListener("mouseup", imageUnactivate) + }); + </script> +``` + +#### 效果展示 +![20251210Show02](https://qiniu.lhchen.asia//20251210Show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251211-jsForm\345\257\271\350\261\241.md" "b/\347\275\227\347\232\223\346\231\250/20251211-jsForm\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..d43a3d854f73bd3468242ed99075d4866ae3c9a5 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251211-jsForm\345\257\271\350\261\241.md" @@ -0,0 +1,246 @@ +## 笔记 + +### Form 对象属性 + +| 属性名 | 类型 | 描述 | 示例 | +| --------------- | -------------------------- | ------------------------------------------------------------ | ----------------------------------------------- | +| `action` | String | 获取 / 设置表单提交的目标 URL | `form.action = "/api/submit";` | +| `method` | String | 表单提交的 HTTP 方法(GET/POST/PUT/DELETE 等) | `form.method = "POST";` | +| `enctype` | String | 表单数据编码类型- 默认:`application/x-www-form-urlencoded`- 文件上传:`multipart/form-data` | `form.enctype = "multipart/form-data";` | +| `target` | String | 提交后响应的展示目标- `_self`(当前窗口)、`_blank`(新窗口)- `_parent`/`_top`(父 / 顶级窗口) | `form.target = "_blank";` | +| `elements` | HTMLFormControlsCollection | 表单内所有控件的集合(操作控件的核心入口) | `const usernameInput = form.elements.username;` | +| `length` | Number | 表单内控件的数量(等同于 `elements.length`) | `console.log(form.length); // 输出控件总数` | +| `name` | String | 表单名称(对应 `<form name="">` 属性) | `form.name = "userForm";` | +| `autocomplete` | String | 表单整体自动完成功能(on/off) | `form.autocomplete = "off";` | +| `noValidate` | Boolean | 是否禁用表单默认验证(对应 `novalidate` 属性) | `form.noValidate = true;` | +| `acceptCharset` | String | 表单提交的字符编码(如 UTF-8/GBK) | `form.acceptCharset = "UTF-8";` | + +### Form 对象方法 + +| 方法名 | 参数 | 返回值 | 描述 | 示例 | +| ------------------ | ------------------------ | --------- | ------------------------------------------------------------ | ------------------------------------------ | +| `submit()` | 无 | undefined | 手动提交表单(不会触发 `onsubmit` 事件) | `form.submit();` | +| `reset()` | 无 | undefined | 重置表单到初始状态(触发 `onreset` 事件) | `form.reset();` | +| `checkValidity()` | 无 | Boolean | 检查所有控件是否通过验证(合法返回 true,否则 false) | `if (form.checkValidity()) form.submit();` | +| `reportValidity()` | 无 | Boolean | 检查验证并显示浏览器默认的错误提示(合法返回 true) | `form.reportValidity();` | +| `requestSubmit()` | [submitter: HTMLElement] | undefined | 模拟点击提交按钮提交(触发 `onsubmit` 事件),可指定提交按钮 | `form.requestSubmit(btnSubmit);` | + +### 表单控件通用属性 + +| 属性名 | 类型 | 描述 | 适用控件 | 示例 | +| -------------- | ------- | ----------------------------------------- | --------------------------------------- | -------------------------------------------------------- | +| `value` | String | 获取 / 设置控件的输入值(核心) | 所有输入类控件(input/select/textarea) | `input.value = "默认内容"; console.log(textarea.value);` | +| `name` | String | 控件名称(表单提交时的键名) | 所有控件 | `input.name = "username";` | +| `id` | String | 控件唯一标识 | 所有控件 | `input.id = "user-name";` | +| `type` | String | 控件类型(text/radio/checkbox/button 等) | input/button | `console.log(input.type); // "text"` | +| `disabled` | Boolean | 是否禁用控件(禁用后不可交互、不提交值) | 所有控件 | `input.disabled = true;` | +| `readOnly` | Boolean | 是否只读(仅输入类控件,可提交值) | input/textarea | `textarea.readOnly = true;` | +| `required` | Boolean | 是否为必填项(表单验证用) | 输入类控件 | `input.required = true;` | +| `checked` | Boolean | 是否选中(单选 / 复选框专属) | radio/checkbox | `checkbox.checked = true;` | +| `maxLength` | Number | 最大输入长度限制 | input/textarea | `input.maxLength = 20;` | +| `pattern` | String | 输入内容的正则验证规则 | input | `input.pattern = "^[a-z0-9]+$";` | +| `placeholder` | String | 输入框占位提示文本 | input/textarea | `input.placeholder = "请输入用户名";` | +| `defaultValue` | String | 控件的初始值(页面加载时的 value) | input/textarea | `console.log(input.defaultValue);` | + +### 表单控件方法 + +| 方法名 | 参数 | 返回值 | 描述 | 适用控件 | 示例 | +| --------------------- | --------------- | --------- | ---------------------------------------- | ---------------- | -------------------------------------------------- | +| `focus()` | 无 | undefined | 让控件获取焦点 | 所有可交互控件 | `input.focus();` | +| `blur()` | 无 | undefined | 让控件失去焦点 | 所有可交互控件 | `input.blur();` | +| `select()` | 无 | undefined | 选中输入框内的所有文本 | input/textarea | `input.select();` | +| `checkValidity()` | 无 | Boolean | 检查当前控件是否通过验证 | 所有带验证的控件 | `if (!input.checkValidity()) alert("输入不合法");` | +| `reportValidity()` | 无 | Boolean | 检查验证并显示浏览器默认错误提示 | 所有带验证的控件 | `input.reportValidity();` | +| `setCustomValidity()` | message: String | undefined | 设置自定义验证错误提示(清空传空字符串) | 所有带验证的控件 | `input.setCustomValidity("用户名不能少于6位");` | +| `click()` | 无 | undefined | 模拟点击控件(如按钮、单选框) | | | + +## 作业 + +### 第一部分 + +#### 关键代码 + +```html + <div class="item01"> + <label for="movieCDKEY">兑换码:</label> + <input type="text" name="movieCDKEY" id="movieCDKEY" placeholder="请输入兑换码"> + <input type="button" name="" id="ticket-btn" value="取票"> + </div> + <div class="item02"> + <textarea name="" id="agreement" cols="30" + rows="10">本协议由用户与本平台共同缔结,用户注册、登录、使用本平台服务,即视为同意并遵守本协议全部条款。用户享有平台提供的各项服务权益,需保证注册信息真实合法,不得发布违法侵权内容、不得实施危害平台系统安全的行为;平台为用户提供稳定安全的服务,有权对违规用户采取警告、限制功能、账号封禁等措施,同时将依法保护用户个人信息,非法定或约定情形不向第三方泄露。平台对因不可抗力、用户自身原因导致的服务异常不承担责任,双方争议协商不成,可向平台所在地有管辖权的人民法院提起诉讼。平台可根据业务调整更新协议,更新后将通过平台公告通知,用户继续使用服务即视为接受新协议。</textarea> + <div class="btn"> + <input type="button" name="" id="rows-add-btn" value="+"> + <input type="button" name="" id="rows-delete-btn" value="-"> + </div> + </div> + <div class="item03"> + <input type="checkbox" name="hobby" id="hobby1" value="reading">阅读 + <input type="checkbox" name="hobby" id="hobby2" value="sports">运动 + <input type="checkbox" name="hobby" id="hobby3" value="cooking">烹饪 + <input type="checkbox" name="hobby" id="hobby4" value="painting">绘画 + <input type="checkbox" name="hobby" id="hobby5" value="travel">旅行 + <input type="checkbox" name="hobby" id="hobby6" value="music">听音乐 + <input type="checkbox" name="hobby" id="hobby7" value="photography">摄影<br> + <input type="checkbox" name="hobby" id="hobby8" value="writing">写作 + <input type="checkbox" name="hobby" id="hobby9" value="dancing">跳舞 + <input type="checkbox" name="hobby" id="hobby10" value="gaming">游戏 + <input type="checkbox" name="hobby" id="hobby11" value="planting">养花 + <input type="checkbox" name="hobby" id="hobby12" value="handwork">手工 + <input type="checkbox" name="hobby" id="hobby13" value="petraising">养宠物 + <input type="checkbox" name="hobby" id="hobby14" value="slackoff">摸鱼 + </div> + <script> + // 训练01 + let Item01Btn = document.getElementById('ticket-btn') + let myItem01GertTicket = () => { + let myCDKEY = Number(document.querySelector('[name = movieCDKEY]').value); + if (myCDKEY == 1433223) { + console.log('取票成功,兑换码已核销'); + } + else { + console.log('兑换码不存在,请重新输入'); + document.querySelector('[name = movieCDKEY]').value = "" + + } + } + Item01Btn.addEventListener("click", myItem01GertTicket) + + // 训练02 + let Item02Txt = document.getElementById('agreement') + let Item02Add = document.getElementById('rows-add-btn') + let Item02Delete = document.getElementById('rows-delete-btn') + let row = Item02Txt.rows; + Item02Add.addEventListener("click", () => { + row += 1 + Item02Txt.rows = row + }) + Item02Delete.addEventListener("click", () => { + row -= 1 + Item02Txt.rows = row + }) + + // 训练03 + let Item03OptionsArr = Array.from(document.querySelectorAll("[name=hobby]")) + let hobbyArr = [] + Item03OptionsArr.forEach(hobby => { + hobby.addEventListener("change", () => { + if (hobby.checked) { + if (hobbyArr.length < 6) { + hobbyArr.push(hobby) + console.log(hobbyArr); + + } else { + hobby.checked = false + alert("超出") + } + } else { + hobbyArr = hobbyArr.filter(item => item !== hobby); + } + }) + }) + </script> +``` + +#### 效果展示 +![20251211Show01](https://qiniu.lhchen.asia//20251211Show01.gif) +### 第二部分 + +#### 关键代码 + +```html + <div class="item01"> + <p>请选择C</p> + <input type="radio" name="option" id="" value="A">A. + <input type="radio" name="option" id="" value="B">B. + <input type="radio" name="option" id="" value="C">C. + <input type="radio" name="option" id="" value="D">D. + <input type="button" id="item01-submit-btn" value="提交答案"> + </div> + <div class="item02"> + <input type="checkbox" name="hobby" id="hobby01">摸鱼 + <input type="checkbox" name="hobby" id="hobby02">追剧 + <input type="checkbox" name="hobby" id="hobby03">听歌 + <input type="checkbox" name="hobby" id="hobby04">逛街 + <input type="checkbox" name="hobby" id="hobby05">发呆 + <input type="checkbox" name="hobby" id="hobby06">撸猫 + <input type="checkbox" name="hobby" id="hobby07">喝茶 + <input type="checkbox" name="hobby" id="hobby08">爬山 + <input type="checkbox" name="hobby" id="hobby09">下棋 + <input type="checkbox" name="hobby" id="hobby10">练字<br> + <input type="button" id="item02-all-btn" value="全选"> + <input type="button" id="item02-notall-btn" value="全不选"> + <input type="button" id="item02-lnvert-btn" value="反选"> + </div> + <div class="item03"> + 选择城市:<select name="province" id="province"> + <option value="Fujian" checked>福建</option> + <option value="Hunan">湖南</option> + <option value="Hubei">湖北</option> + </select> + <select name="city" id="city"> + <option value="Xiamen">厦门</option> + <option value="Fuzhou">福州</option> + </select> + </div> + <script> + // 综合训练01 + let item01SubmitBtn = document.querySelector('#item01-submit-btn') + let item01OptionsArr = Array.from(document.querySelectorAll('[name=option]')) + let item01Judge = false; + function myItem01Submit() { + item01OptionsArr.forEach(option => { + if (option.checked) { + if (option.value == "C")item01Judge = true + }} + }) + if (!item01Judge) { + console.log('false'); + } + else { + console.log('true'); + } + } + item01SubmitBtn.addEventListener("click", myItem01Submit) + + // 综合训练02 + let item02AllBtn = document.querySelector('#item02-all-btn') + let item02NotallBtn = document.querySelector('#item02-notall-btn') + let item02lnvertBtn = document.querySelector('#item02-lnvert-btn') + let item02OptionsArr = Array.from(document.querySelectorAll('[name=hobby]')) + function myItme02CheckedAll() { + item02OptionsArr.forEach(option => option.checked = true) + } + item02AllBtn.addEventListener("click", myItme02CheckedAll) + item02NotallBtn.addEventListener("click", () => { + item02OptionsArr.forEach(option => { + option.checked = false + }) + }) + item02lnvertBtn.addEventListener("click", () => { + item02OptionsArr.forEach(option => option.checked = !option.checked) + }) + + // 综合训练03 + let province = document.querySelector("#province") + let city = document.querySelector("#city") + province.addEventListener("change", () => { + let cityList = '' + switch (province.value) { + case "Fujian": + cityList += `<option value="Xiamen">厦门</option><option value="Fuzhou">福州</option>`; + break; + case "Hunan": + cityList += `<option value="Yueyang">岳阳</option><option value="Changsha">长沙</option>`; + break; + case "Hubei": + cityList += `<option value=Jingzhou">荆州</option><option value="Wuhan">武汉</option>`; + break; + } + city.innerHTML = cityList + }) + </script> +``` + +#### 效果展示 +![20251211Show02](https://qiniu.lhchen.asia//20251211Show02.gif) \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251212-jsJSON\346\225\260\346\215\256\346\240\274\345\274\217.md" "b/\347\275\227\347\232\223\346\231\250/20251212-jsJSON\346\225\260\346\215\256\346\240\274\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..5d9df0ca46133ac904efb32701a66f81c3563416 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251212-jsJSON\346\225\260\346\215\256\346\240\274\345\274\217.md" @@ -0,0 +1,69 @@ +## 笔记 + +### JSON 基础格式 + +#### 对象 + +- 结构:花括号 `{}` 包裹,内部是唯一字符串键 + 值的键值对,键值用 `:` 分隔,键值对间用 `,` 分隔 +- 示例: + +```json +{ + "name": "张三", + "age": 25, + "isMember": true, + "address": {"city": "北京", "area": "朝阳"} +} +``` + +#### 数组 + +- 结构:方括号 `[]` 包裹,值为任意合法 JSON 类型,值之间用 `,` 分隔 +- 示例: + +```json +[123, "测试", false, null, ["a", "b"], {"key": "value"}] +``` + +#### 简单数据类型 + +| 类型 | 规则 | 示例 | +| ------ | --------------------- | ------------- | +| 字符串 | 双引号包裹 | `"JSON 笔记"` | +| 数字 | 整数 / 浮点数,无引号 | `99`、`1.68` | +| 布尔值 | 仅 `true`/`false` | `false` | +| null | 表示空值,无引号 | `null` | + +### JSON的转换 + +#### 序列化(JS 对象 → JSON 字符串) + +- 方法:`JSON.stringify(value[, replacer[, space]])` +- 作用:将 JS 对象 / 数组 / 基本类型转为标准 JSON 字符串 +- 示例: + +```javascript +const jsObj = { name: "李四", age: 30, hobbies: ["跑步", "听歌"] }; +// 基础转换 +const jsonStr = JSON.stringify(jsObj); +// 格式化输出(2个空格缩进) +const prettyStr = JSON.stringify(jsObj, null, 2); +``` + +- 注意:函数、undefined 会被忽略,循环引用对象会报错 + +#### 反序列化(JSON 字符串 → JS 对象) + +- 方法:`JSON.parse(text[, reviver])` +- 作用:将合法 JSON 字符串转为 JS 对象 / 数组 +- 示例: + +```javascript +const jsonStr = '{"name":"李四","age":30}'; +// 基础解析 +const jsObj = JSON.parse(jsonStr); +// 解析时处理数据(如年龄+1) +const handledObj = JSON.parse(jsonStr, (key, val) => key === "age" ? val + 1 : val); +``` + +- 注意:JSON 字符串必须合法(如键为双引号),否则报错 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251215-js.......md" "b/\347\275\227\347\232\223\346\231\250/20251215-js.......md" new file mode 100644 index 0000000000000000000000000000000000000000..48a9745e3c7e8e526fd5f798e391c3be812c4290 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251215-js.......md" @@ -0,0 +1,7 @@ +## 笔记 + +什么都没有...... + +## 作业 + +什么都没有...... \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251217-jsjQuery\345\272\22301.md" "b/\347\275\227\347\232\223\346\231\250/20251217-jsjQuery\345\272\22301.md" new file mode 100644 index 0000000000000000000000000000000000000000..21e29732e1e901e3eb2836862900e14e70e46e95 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251217-jsjQuery\345\272\22301.md" @@ -0,0 +1,565 @@ +## 笔记 + +jQuery 是基于 JavaScript 的轻量级 DOM 操作类库,核心宗旨是 **Write Less, Do More**,简化了 DOM 操作、事件处理、动画、AJAX 等常见开发场景。以下是 jQuery 高频操作的系统整理: + +### 核心基础 + +#### 引入 jQuery + +- CDN 引入(推荐) + + ```javascript + <!-- 最新版(生产环境建议指定版本) --> + <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> + <!-- 国内CDN --> + <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script> + ``` + +- **本地引入**:下载 jQuery 文件后,通过相对路径引入。 + +#### 入口函数(DOM 加载完成) + +替代原生 `window.onload`,执行时机更早(DOM 渲染完成即执行,无需等待资源加载): + +```javascript +// 写法1(推荐) +$(function() { + // DOM 操作代码 +}); + +// 写法2(完整写法) +$(document).ready(function() { + // DOM 操作代码 +}); +``` + +#### jQuery 对象与原生 DOM 转换 + +- jQuery 对象是类数组对象,不能直接调用原生 DOM 方法,需转换: + + ```javascript + // jQuery 对象转原生 DOM + const $div = $('#myDiv'); + const divDom = $div[0]; // 方式1:通过索引 + const divDom2 = $div.get(0); // 方式2:get() 方法 + + // 原生 DOM 转 jQuery 对象 + const dom = document.getElementById('myDiv'); + const $dom = $(dom); + ``` + + + +### DOM 选择器 + +jQuery 兼容 CSS 所有选择器,且扩展了专属选择器,核心语法:`$(selector)`。 + +#### 基础选择器 + +| 选择器 | 语法 | 说明 | +| ------------ | -------------- | ----------------------- | +| ID 选择器 | `$('#id')` | 匹配单个元素(ID 唯一) | +| 类选择器 | `$('.class')` | 匹配多个类名相同的元素 | +| 标签选择器 | `$('tag')` | 匹配所有指定标签的元素 | +| 通配符选择器 | `$('*')` | 匹配所有元素(慎用) | +| 组合选择器 | `$('div.box')` | 同时满足多个条件 | + +#### 层级选择器 + +| 选择器 | 语法 | 说明 | +| -------------- | ---------------------- | ---------------------------------- | +| 后代选择器 | `$('parent child')` | 匹配父元素下所有后代元素 | +| 子元素选择器 | `$('parent > child')` | 匹配父元素直接子元素 | +| 相邻兄弟选择器 | `$('prev + next')` | 匹配 prev 后紧邻的 next 元素 | +| 通用兄弟选择器 | `$('prev ~ siblings')` | 匹配 prev 后所有同级 siblings 元素 | + +#### 过滤选择器(重点) + +以 `:` 开头,筛选已有结果集: + +```javascript +// 基本过滤 +$('li:first'); // 第一个 li +$('li:last'); // 最后一个 li +$('li:eq(2)'); // 索引为 2 的 li(从 0 开始) +$('li:gt(1)'); // 索引大于 1 的 li +$('li:lt(3)'); // 索引小于 3 的 li +$('li:not(.active)'); // 排除含 active 类的 li +$(':visible'); // 可见元素 +$(':hidden'); // 隐藏元素(display:none/input type="hidden") + +// 内容过滤 +$('div:contains("文本")'); // 包含指定文本的 div +$('div:empty'); // 空元素(无内容/子元素) +$('div:has(p)'); // 包含 p 标签的 div + +// 属性过滤 +$('input[name="username"]'); // name 为 username 的 input +$('input[name!="username"]'); // name 不为 username 的 input +$('input[name^="user"]'); // name 以 user 开头的 input +$('input[name$="name"]'); // name 以 name 结尾的 input +$('input[name*="user"]'); // name 包含 user 的 input + +// 表单过滤(简化表单元素选择) +$(':input'); // 所有表单元素(input/select/textarea/button) +$(':text'); // 文本框(type="text") +$(':password'); // 密码框 +$(':radio'); // 单选框 +$(':checkbox'); // 复选框 +$(':submit'); // 提交按钮 +$(':reset'); // 重置按钮 +$(':button'); // 普通按钮 +$(':checked'); // 选中的单选/复选框 +$(':selected'); // 选中的下拉选项 +``` + +### DOM 操作 + +#### 内容操作 + +| 方法 | 说明 | +| -------- | ------------------------------------- | +| `html()` | 获取 / 设置元素的 HTML 内容(含标签) | +| `text()` | 获取 / 设置元素的文本内容(纯文本) | +| `val()` | 获取 / 设置表单元素的 value 值 | + +示例: + +```javascript +// 获取 +$('#div1').html(); // 获取 div1 的 HTML 内容 +$('#div1').text(); // 获取 div1 的文本内容 +$('#input1').val(); // 获取输入框的值 + +// 设置 +$('#div1').html('<p>新内容</p>'); // 设置 HTML 内容 +$('#div1').text('新文本'); // 设置文本内容 +$('#input1').val('默认值'); // 设置输入框值 +``` + +#### 属性操作 + +| 方法 | 说明 | +| -------------- | ------------------------------------------------------------ | +| `attr()` | 获取 / 设置元素的**自定义属性**(或原生属性) | +| `prop()` | 获取 / 设置元素的**原生属性 / 状态**(如 checked、selected) | +| `removeAttr()` | 移除属性 | +| `removeProp()` | 移除属性(极少用) | + +示例: + +```javascript +// attr 示例 +$('img').attr('src'); // 获取 img 的 src 属性 +$('img').attr('title', '图片'); // 设置 title 属性 +$('img').attr({src: '1.jpg', alt: '图片'}); // 批量设置属性 +$('img').removeAttr('title'); // 移除 title 属性 + +// prop 示例(单选/复选框必用) +$(':checkbox').prop('checked'); // 获取是否选中(返回 true/false) +$(':checkbox').prop('checked', true); // 设置选中 +``` + +⚠️ 注意:`attr` 返回属性的**初始值**(字符串),`prop` 返回**实时状态**(布尔值),表单状态(checked/selected)优先用 `prop`。 + +#### 样式操作 + +| 方法 | 说明 | +| --------------- | ---------------------------------- | +| `css()` | 获取 / 设置行内样式 | +| `addClass()` | 添加类名 | +| `removeClass()` | 移除类名 | +| `toggleClass()` | 切换类名(有则移除,无则添加) | +| `hasClass()` | 判断是否包含指定类名(返回布尔值) | + +示例: + +```javascript +// css 操作 +$('#div1').css('color'); // 获取颜色 +$('#div1').css('color', 'red'); // 设置单个样式 +$('#div1').css({ // 批量设置样式 + color: 'red', + fontSize: '16px', // 驼峰命名(或 'font-size') + background: '#fff' +}); + +// 类操作 +$('#div1').addClass('active'); // 添加 active 类 +$('#div1').removeClass('active'); // 移除 active 类 +$('#div1').toggleClass('active'); // 切换 active 类 +$('#div1').hasClass('active'); // 判断是否有 active 类 +``` + +#### 元素增删改 + +##### 创建元素 + +```javascript +const $newDiv = $('<div class="box">新元素</div>'); // 创建 jQuery 对象 +``` + +##### 添加元素 + +| 方法 | 说明 | +| ----------- | ---------------------------- | +| `append()` | 父元素末尾添加子元素(父调) | +| `prepend()` | 父元素开头添加子元素(父调) | +| `after()` | 元素后添加同级元素(自身调) | +| `before()` | 元素前添加同级元素(自身调) | + +示例: + +```javascript +// 子元素添加 +$('ul').append('<li>末尾项</li>'); // ul 末尾加 li +$('ul').prepend('<li>开头项</li>'); // ul 开头加 li + +// 同级元素添加 +$('div').after('<p>div 后面的 p</p>'); // div 后加 p +$('div').before('<p>div 前面的 p</p>'); // div 前加 p +``` + +##### 删除元素 + +| 方法 | 说明 | +| ---------- | ------------------------------------ | +| `remove()` | 删除元素(含自身及所有子元素、事件) | +| `empty()` | 清空元素内容(保留自身) | + +示例: + +```javascript +$('li').remove(); // 删除所有 li +$('li').eq(0).remove(); // 删除第一个 li +$('div').empty(); // 清空 div 内容 +``` + +##### 替换元素 + +```javascript +$('p').replaceWith('<span>替换后的内容</span>'); // 替换所有 p 为 span +``` + +##### 遍历元素 + +```javascript +$('li').each(function(index, domEle) { + // index:索引(从 0 开始) + // domEle:原生 DOM 元素(需转 jQuery 对象) + console.log(index, $(domEle).text()); + // 终止遍历:return false; +}); +``` + +##### 查找相关元素 + +| 方法 | 说明 | +| ------------ | -------------------------------------- | +| `parent()` | 父元素(直接父级) | +| `parents()` | 所有祖先元素(可传选择器过滤) | +| `children()` | 所有子元素(直接子级,可传选择器过滤) | +| `siblings()` | 所有同级元素(可传选择器过滤) | +| `find()` | 后代元素(必须传选择器) | +| `eq()` | 根据索引获取元素 | + +示例: + +```javascript +$('li').parent(); // li 的直接父元素 +$('li').parents('ul'); // li 的所有 ul 祖先 +$('ul').children('li.active'); // ul 中类为 active 的直接子 li +$('li').siblings('.active'); // li 的同级 active 元素 +$('div').find('p'); // div 下所有 p 元素 +$('li').eq(2); // 索引为 2 的 li +``` + +### 事件处理 + +#### 基础事件绑定 + +##### 快捷绑定(常用事件) + +```javascript +$('button').click(function() { // 点击事件 + console.log('点击了按钮'); +}); + +$('input').blur(function() { // 失焦事件 + console.log('输入框失焦'); +}); + +// 其他快捷事件:mouseover/mouseout/hover/keydown/keyup/change/submit 等 +``` + +##### `on()` 绑定(推荐,支持动态元素) + +```js +// 单个事件 +$('ul').on('click', 'li', function() { + // 委托 ul 下的 li 绑定点击(支持动态添加的 li) + console.log($(this).text()); +}); + +// 多个事件 +$('input').on({ + focus: function() { + $(this).css('border', '1px solid red'); + }, + blur: function() { + $(this).css('border', '1px solid #ccc'); + } +}); +``` + +##### 事件解绑 + +```javascript +$('button').off('click'); // 解绑点击事件 +$('button').off(); // 解绑所有事件 +``` + +#### 事件触发 + +```javascript +$('button').click(); // 手动触发点击事件 +$('button').trigger('click'); // 等效上面 +``` + +#### 事件对象 + +```javascript +$('button').click(function(e) { + e.preventDefault(); // 阻止默认行为(如a标签跳转) + e.stopPropagation(); // 阻止事件冒泡 + console.log(e.target); // 触发事件的原生 DOM 元素 +}); +``` + +## 作业 + +### 第一部分(数组1-7) + +#### 关键代码 + +```html + <script> + //2.1 + let arr01 = [1, 2, 3, 4, 5, 6, 7, 8, 9] + let sum01 = null + arr01.forEach(num => sum01 += num) + console.log(sum01); + + //2.2 + let arr02A = [1, 2, 3, 4, 5] + let arr02B = ['a', 'b', 'c', 'd', 'e'] + let arr02C = arr02A.concat(arr02B) + console.log(arr02A, arr02B, arr02C); + + //2.3 + let findNumber03 = 6 //出现3次 + let arr03 = [6, 2, 'a', 6, 45, 66, 1, 0, 'for', 9, 2, 8, 4, 6, '6'] + let count = arr03.filter(num => num === 6).length + console.log(count); + + //2.4 + let arr04A = [1, 2, 4, 4, 3, 3, 1, 5, 3] + let arr04B = [] + arr04A.forEach((num, index) => { + let lr = arr04A.indexOf(num) + let rl = arr04A.lastIndexOf(num) + if (lr !== rl) { + arr04B.push(num) + } + }) + let set04 = new Set(arr04B) + console.log(set04); + + //2.5 + let arr05A = [1, 2, 3, 4, 2, 5, 'a', 6, 2, 9, 0, 23, 5, '2', 7] + let removeNumber05 = 2 + let arr05B = arr05A.filter(num => num !== 2) + console.log(arr05A, arr05B); + + //2.6 + let arr06A = [{ name: "小明", score: 85 }, { name: "小红", score: 55 }, { name: "小刚", score: 90 }] + let arr06B = arr06A.filter(obj => obj.score >= 60).map(obj => obj.name) + console.log(arr06A,arr06B); + </script> +``` + +### 第二部分(数组7-24) + +#### 关键代码 + +```html + <script> + //2.7 + const arr07A = [1, 2, 3, 4, 5] + let arr07B = arr07A.map(num => num * 2) + console.log(arr07B); + + //2.8 + const arr08A = [1, 2, 3, 4, 5, 6, 7, 8, 9] + let arr08B = arr08A.filter(num => num % 2 !== 0) + console.log(arr08B); + + //2.9 + const arr09A = [10, 20, 30, 40, 50] + let arr09B = arr09A.reduce((sum, num) => sum + num, 0) + console.log(arr09B); + + //2.10 + const arr10 = [3, 7, 2, 9, 1, 5] + let result10 = arr10.reduce((acc, cur) => Math.max(acc,cur), arr10[0]) + console.log(result10); + + //2.11 + const arr11 = [2, 5, 8, 12, 15, 7] + let result11 = arr11.find(num => num > 10) + console.log(result11); + + //2.12 + const arr12 = [1, 5, 3, -2, 8, -5] + let result12 = arr12.findIndex(num => num < 0) + console.log(result12); + + //2.13 + const arr13 = [1, 3, 5, 7, 8] + let result13 = arr13.some(sum => sum % 2 == 0) + console.log(result13); + + //2.14 + const arr14 = [1, 2, 3, 4, 5] + let result14 = arr14.every(sum => sum > 0) + console.log(result14); + + //2.15 + const arr15A = [40, 100, 1, 5, 25, 10] + let arr15B = arr15A.sort((o1, o2) => o1 - o2) + console.log(arr15B); + + //2.16 + const arr16A = [ + { name: "小明", age: 20 }, + { name: "小红", age: 18 }, + { name: "小刚", age: 22 }, + { name: "小胡", age: 11 } + ] + let arr16B = arr16A.sort((o1, o2) => o1.age - o2.age) + console.log(arr16B); + + //2.17 + const arr17A = ['apple', 'banana', 'orange'] + let arr17B = arr17A.forEach((str, strIndex) => console.log(`索引${strIndex}:${str}`)) + + //2.18 + const arr18A = [[1, 2], [3, 4], [5, 6]] + let arr18B = arr18A.flat(2) + console.log(arr18B); + + //2.19 + const arr19 = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'] + arr19.reduce((acc, cur) =>acc[cur] = (acc[cur] || 0) + 1,{}) + + //2.20 + const arr20A = [ + { name: "鼠标", price: 29 }, + { name: "键盘", price: 89 }, + { name: "显示器", price: 899 }, + { name: "耳机", price: 199 } + ] + let arr20B = arr20A.filter(obj => obj.price > 50). + sort((o1, o2) => o1.price - o2.price). + map(obj => obj.name) + console.log(arr20B); + + //2.21 + const arr21A = [2, 5, 8, 3, 9] + let arr21B = arr21A.map(sum => sum * 2).filter(sum => sum > 10) + console.log(arr21B); + + //2.22 + const arr22A = [1, 2, 2, 3, 4, 4, 5, 1] + let arr22B = arr22A.reduce((acc, cur) => { + if (acc.indexOf(cur) == -1) acc.push(cur) + return acc + }, [] + ) + console.log(arr22B); + + //2.23 + const arr23 = [ + { name: "小明", score: 85 }, + { name: "小红", score: 92 }, + { name: "小刚", score: 78 }, + { name: "小丽", score: 88 } + ] + let result23 = arr23.reduce((acc, num) => acc + num.score, 0) / arr23.length + console.log(result23); + + //2.24 + const arr24 = [ + { name: "张三", age: 17 }, + { name: "李四", age: 20 }, + { name: "王五", age: 25 }, + { name: "赵六", age: 16 } + ] + arr24.filter(obj => obj.age >= 18).map(obj => console.log(`"${obj.name}"(${obj.age}岁)`)); + </script> +``` + +### 第三部分(jQuery基础) + +#### 关键代码 + +```html + <script> + // 5.1.1 + $(document).ready(() => {console.log('jQuery已就绪');}) + + //5.1.2 + console.log($ === jQuery); + + //5.1.3 + console.log($('#demo')[0]); + + //5.1.4 + let jQueryObj04 = $('#demo') + let domObj = jQueryObj04[0] + jQueryObj04 = $(domObj) + console.log(jQueryObj04); + console.log(domObj); + + //5.1.5 + $('#demo').css({ + backgroundColor: 'red', + width: '200px', + height: '200px' + }).addClass('box').fadeIn() + </script> +``` + +### 第四部分(jQuery选择器与操作) + +#### 关键代码 + +```html + <script> + // 5.2.1 + $('.item').css({color:'red'}) + + // 5.2.2 + $('li:first').css('backgroundColor','blue') + $('li:last').css('backgroundColor','green') + + //5.2.3 + $('#container').find('span').text('hahahaha') + + //5.2.4 + $('table td:odd').css('backgroundColor','blue') + + //5.2.5 + $('.item').each((index,domObj)=>{return $(domObj).text(`第${index+1}个item`)}) + </script> +``` diff --git "a/\347\275\227\347\232\223\346\231\250/20251218-jsjQuery\345\272\22302.md" "b/\347\275\227\347\232\223\346\231\250/20251218-jsjQuery\345\272\22302.md" new file mode 100644 index 0000000000000000000000000000000000000000..cc7ea85337703eea5df4a2426bd396fca20c5dda --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251218-jsjQuery\345\272\22302.md" @@ -0,0 +1,332 @@ +## 笔记 + +### 动画效果 + +#### 基础显示隐藏 + +| 方法 | 说明 | +| ---------- | -------------------------------------- | +| `show()` | 显示元素(可传时长:ms/'slow'/'fast') | +| `hide()` | 隐藏元素 | +| `toggle()` | 切换显示 / 隐藏 | + +示例: + +```javascript +$('div').show(500); // 500ms 显示 +$('div').hide('slow'); // 慢速隐藏 +$('div').toggle(); // 切换 +``` + +#### 滑动效果 + +| 方法 | 说明 | +| --------------- | ------------ | +| `slideDown()` | 下滑显示 | +| `slideUp()` | 上滑隐藏 | +| `slideToggle()` | 切换滑动效果 | + +示例: + +```javascript +$('div').slideDown(300); // 300ms 下滑 +$('div').slideToggle(); // 切换滑动 +``` + +#### 淡入淡出 + +| 方法 | 说明 | +| -------------- | --------------------- | +| `fadeIn()` | 淡入 | +| `fadeOut()` | 淡出 | +| `fadeToggle()` | 切换淡入淡出 | +| `fadeTo()` | 淡到指定透明度(0-1) | + +示例: + +```javascript +$('div').fadeIn(); // 淡入 +$('div').fadeTo(500, 0.5); // 500ms 淡到 50% 透明度 +``` + +#### 自定义动画 + +`animate()`:自定义 CSS 动画(仅支持数值型样式,如宽高、位置、透明度) + +```javascript +$('div').animate({ + left: '200px', + width: '300px', + opacity: 0.8 +}, 1000, function() { + // 动画完成回调 + console.log('动画结束'); +}); +``` + +#### 动画控制 + +```javascript +$('div').stop(); // 停止当前动画(立即) +$('div').delay(500); // 延迟 500ms 执行后续动画 +``` + +### AJAX 操作 + +jQuery 封装了 AJAX,简化请求流程,核心方法: + +#### 通用方法 `$.ajax()` + +```javascript +$.ajax({ + url: 'https://api.example.com/data', // 请求地址 + type: 'GET', // 请求方式(GET/POST) + dataType: 'json', // 响应数据类型(json/text/html/xml) + data: { // 请求参数(GET 拼在 URL,POST 放请求体) + id: 1, + name: 'test' + }, + async: true, // 是否异步(默认 true) + timeout: 5000, // 超时时间(ms) + beforeSend: function(xhr) { + // 请求发送前执行(如设置请求头) + xhr.setRequestHeader('Token', '123456'); + }, + success: function(res) { + // 请求成功回调 + console.log(res); + }, + error: function(xhr, status, error) { + // 请求失败回调 + console.log('失败:', error); + }, + complete: function() { + // 请求完成(无论成败)回调 + } +}); +``` + +#### 简化方法 + +| 方法 | 说明 | +| ------------- | ---------------------------- | +| `$.get()` | GET 请求(简化版 $.ajax) | +| `$.post()` | POST 请求 | +| `$.getJSON()` | GET 请求,自动解析 JSON 数据 | + +示例: + +```javascript +// GET 请求 +$.get('https://api.example.com/data', {id: 1}, function(res) { + console.log(res); +}, 'json'); + +// POST 请求 +$.post('https://api.example.com/add', {name: 'test'}, function(res) { + console.log(res); +}); + +// 获取 JSON +$.getJSON('https://api.example.com/json', function(res) { + console.log(res); +}); +``` + +### 常用工具方法 + +jQuery 提供了独立于 DOM 的工具方法,前缀 `$`: + +```javascript +// 1. 数组/对象遍历 +$.each([1,2,3], function(index, val) { + console.log(index, val); +}); + +// 2. 数组去重 +$.unique([1,2,2,3]); // [1,2,3] + +// 3. 类型判断 +$.type('abc'); // "string" +$.type([]); // "array" +$.isArray([]); // true +$.isFunction(function(){}); // true + +// 4. 合并对象/数组 +$.extend({}, {a:1}, {b:2}); // {a:1, b:2} + +// 5. 解析 JSON +$.parseJSON('{"name":"test"}'); // {name: "test"} +``` + +### 注意事项 + +**版本兼容**:jQuery 3.x 移除了 1.x/2.x 的部分旧特性(如 `bind()`/`live()`),优先用 `on()` 绑定事件。 + +**避免重复引入**:多次引入 jQuery 会导致$被覆盖,可通过 jQuery.noConflict()解决: + +```javascript +const jq = jQuery.noConflict(); // 自定义别名 +jq('#div1').text('新内容'); +``` + +**性能优化:** + +- 缓存 jQuery 对象:`const $li = $('li');`(避免重复选择) +- 减少 DOM 操作:批量修改先隐藏元素,操作后再显示 +- 避免使用通配符选择器 `$('*')` + +**动态元素事件**:动态添加的元素需用事件委托(`on()` 第二个参数传选择器)。 + +**与原生 JS 结合**:复杂逻辑可结合原生 JS,jQuery 侧重 DOM 操作,原生侧重业务逻辑。 + +## 作业 + +### 第一部分(jQuery 事件处理) + +#### 关键代码 + +```html + <script> + //5.3.1 + $('#changeBtn').on({ + click: () => { + $('#title').text('新标题') + } + }) + + //5.3.2 + $('#box').hover(function () { + $(this).css({ + 'background-color': 'yellow' + }) + }, function () { + $(this).css({ + 'background-color': 'gray' + }) + }) + + //5.3.3 + $('#addBtn').on('click', function () { $('#list').append('<li>项目</li>') }) + $('#list').on('click', function () { console.log(`被点击了`); }) + + //5.3.4 + $('form>button').on({ + click: function (e) { + console.log($('#username').val()); + e.preventDefault() + } + }) + + //5.3.5 + $('#btn').on('click',function(){ + console.log('被点击了'); + }) + $('#removeBtn').on('click',function(){ + $('#btn').off('click') + console.log('移除事件'); + }) + </script> +``` + +### 第二部分(jQuery DOM 操作) + +#### 关键代码 + +```html +<script> + //5.5.1 + $('#addBtn').on('click', function () {$('#list').append(`<li>项目${$('#list li').length + 1}</li>`)}) + + //5.5.2 + $('#removeBtn').on('click', function () {$('.special').remove()}) + + //5.5.3 + $('#cloneBtn').on('click', function () { $('#original').after($('#original').clone(true)) }) + + //5.5.4 + $('p').wrap('<div class="wrapper"></div>') + + //5.5.5 + $('#updateBtn').on('click',function(){$('#photo').attr({width:'200px',border :'1px solid black'})}) + </script> +``` + +### 第三部分(函数) + +#### 关键代码 + +```html + <script> + //2.2.1 + function greet(name) { console.log(`你好,${name}!`); } + greet('老胡胡') + + //2.2.2 + function max(num01, num02) { console.log(Math.max(num01, num02)); } + max(15, 23) + + //2.2.3 + function calculateArea(...args) { + if (args.length == 2) console.log(args[0] * args[1]); + else if (args.length == 1) console.log(args[0] * args[0]); + else console.log(`请输入一或二个参数`); + } + calculateArea(5) + calculateArea(5, 10) + calculateArea(5, 5, 5) + + //2.2.4 + function filterEven(arr) { console.log(arr.filter(num => num % 2 == 0)); } + filterEven([1, 2, 3, 4, 5, 6]) + + //2.2.5 + function sumAll(...args) { console.log(args.reduce((acc, cur) => acc += cur, 0)); } + sumAll(1, 2, 3, 4, 5) + + //2.2.6 + fn08() + + //2.2.7 + //没讲过 + + //2.2.8 + function fn08() { + var item08A = `young胡` + let item08B = `old胡` + console.log(item08A, item08B); + + } + // console.log(item08A); + // console.log(item08B); + + //2.2.9 + //没讲过 + + //2.2.10 + function factorial(n) { } + + //2.2.11 + function fibonacci(n) { } + + //2.2.12 + //没讲过 + (function () {let private = "私有";}()) + // console.log(private); + + //2.2.13-2.2.17 + //没讲过 + + //2.2.18 + //没讲过 + let obj18 = { + name: '老胡', + age: 41, + city:'龙岩', + job:'老师' + } + function getUser({ name, age, city }) {console.log(name,age,city);} + getUser(obj18) + </script> +``` + diff --git "a/\347\275\227\347\232\223\346\231\250/20251219-js\346\225\260\347\273\204\351\253\230\347\272\247\346\226\271\346\263\225.md" "b/\347\275\227\347\232\223\346\231\250/20251219-js\346\225\260\347\273\204\351\253\230\347\272\247\346\226\271\346\263\225.md" new file mode 100644 index 0000000000000000000000000000000000000000..b57d91546375f9b0113f71eda9f9c1acb714ea6b --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251219-js\346\225\260\347\273\204\351\253\230\347\272\247\346\226\271\346\263\225.md" @@ -0,0 +1,127 @@ +## 笔记 + +### 数组核心属性 + +| 属性名 | 说明 | 示例 | +| ----------------- | --------------------------------------------------- | ------------------------------------------------------ | +| `length` | 表示数组元素的个数,可读写(修改会截断 / 扩展数组) | `const arr = [1,2,3]; arr.length = 2; // arr变为[1,2]` | +| `constructor` | 指向数组构造函数 `Array` | `arr.constructor === Array // true` | +| `prototype` | 数组原型(用于扩展方法,非实例属性) | `Array.prototype.myMethod = () => {}` | +| `Symbol.iterator` | 迭代器接口(支持`for...of`遍历) | `for (let item of arr) {}` | + +### 数组方法分类基础版本(是否修改原数组) + +#### 会修改原数组的方法 + +这类方法直接操作原数组,执行后原数组的内容 / 结构会发生变化。 + +| 方法名 | 功能 | 示例 | +| -------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `push()` | 向数组末尾添加一个 / 多个元素,返回新长度 | `const arr = [1,2]; arr.push(3); // arr变为[1,2,3]` | +| `pop()` | 删除数组最后一个元素,返回被删除的元素 | `const arr = [1,2,3]; arr.pop(); // arr变为[1,2]` | +| `unshift()` | 向数组开头添加一个 / 多个元素,返回新长度 | `const arr = [2,3]; arr.unshift(1); // arr变为[1,2,3]` | +| `shift()` | 删除数组第一个元素,返回被删除的元素 | `const arr = [1,2,3]; arr.shift(); // arr变为[2,3]` | +| `splice(start, deleteCount, ...items)` | 增 / 删 / 改数组元素,返回被删除的元素数组 | `const arr = [1,2,3]; arr.splice(1,1,4); // arr变为[1,4,3]` | +| `sort((a,b) => {})` | 对数组元素排序(默认按字符串 Unicode 码点),返回排序后的数组 | `const arr = [3,1,2]; arr.sort(); // arr变为[1,2,3]` | +| `reverse()` | 反转数组元素顺序,返回反转后的数组 | `const arr = [1,2,3]; arr.reverse(); // arr变为[3,2,1]` | +| `fill(value, start, end)` | 用指定值填充数组(覆盖指定范围),返回填充后的数组 | `const arr = [1,2,3]; arr.fill(0,1,2); // arr变为[1,0,3]` | +| `copyWithin(target, start, end)` | 复制数组指定范围元素到目标位置,返回修改后的数组 | `const arr = [1,2,3,4]; arr.copyWithin(0,2); // arr变为[3,4,3,4]` | + +#### 不修改原数组的方法 + +这类方法不会改变原数组,而是返回新数组(或其他类型值),原数组保持原样。 + +##### 返回新数组的方法 + +| 方法名 | 功能 | 示例 | +| -------------------------- | ---------------------------------------------- | ------------------------------------------------------------ | +| `slice(start, end)` | 截取数组指定范围元素,返回新数组(含头不含尾) | `const arr = [1,2,3]; const newArr = arr.slice(1); // newArr=[2,3],arr仍为[1,2,3]` | +| `concat(...arrays/values)` | 拼接数组 / 值,返回新数组 | `const arr1 = [1,2]; const arr2 = arr1.concat(3,[4]); // arr2=[1,2,3,4],arr1不变` | +| `map((item) => {})` | 遍历数组,对每个元素处理后返回新数组 | `const arr = [1,2]; const newArr = arr.map(i => i*2); // newArr=[2,4],arr仍为[1,2]` | +| `filter((item) => {})` | 过滤数组元素,返回符合条件的新数组 | `const arr = [1,2,3]; const newArr = arr.filter(i => i>1); // newArr=[2,3],arr不变` | +| `flat(depth)` | 扁平化数组,返回新数组(depth 为扁平化深度) | `const arr = [1,[2,[3]]]; const newArr = arr.flat(2); // newArr=[1,2,3],arr不变` | +| `flatMap((item) => {})` | `map + flat(1)` 结合,返回新数组 | `const arr = [1,2]; const newArr = arr.flatMap(i => [i,i*2]); // newArr=[1,2,2,4]` | +| `with(index, value)` | 替换数组指定索引的元素,返回新数组(ES2023) | `const arr = [1,2]; const newArr = arr.with(0, 3); // newArr=[3,2],arr仍为[1,2]` | + +##### 返回非数组值的方法 + +| 方法名 | 功能 | 示例 | +| -------------------------------------- | ------------------------------------------ | ------------------------------------------------------ | +| `forEach((item) => {})` | 遍历数组(无返回值,仅执行回调) | `arr.forEach(i => console.log(i)); // 原数组不变` | +| `find((item) => {})` | 返回第一个符合条件的元素(无则 undefined) | `arr.find(i => i>1); // 原数组不变` | +| `findIndex((item) => {})` | 返回第一个符合条件的元素索引(无则 - 1) | `arr.findIndex(i => i>1); // 原数组不变` | +| `includes(value, start)` | 判断数组是否包含指定值,返回布尔值 | `arr.includes(2); // 原数组不变` | +| `indexOf(value, start)` | 返回指定值首次出现的索引(无则 - 1) | `arr.indexOf(2); // 原数组不变` | +| `lastIndexOf(value, start)` | 返回指定值最后出现的索引(无则 - 1) | `arr.lastIndexOf(2); // 原数组不变` | +| `every((item) => {})` | 判断所有元素是否符合条件,返回布尔值 | `arr.every(i => i>0); // 原数组不变` | +| `some((item) => {})` | 判断是否有元素符合条件,返回布尔值 | `arr.some(i => i>1); // 原数组不变` | +| `reduce((acc, item) => {}, init)` | 累加 / 归并数组,返回最终归并值 | `arr.reduce((sum, i) => sum+i, 0); // 原数组不变` | +| `reduceRight((acc, item) => {}, init)` | 从右到左归并数组,返回最终归并值 | `arr.reduceRight((sum, i) => sum+i, 0); // 原数组不变` | +| `join(separator)` | 将数组转为字符串,返回拼接后的字符串 | `arr.join(','); // 原数组不变` | +| `toString()` | 将数组转为字符串(默认用逗号分隔) | `arr.toString(); // 原数组不变` | +| `toLocaleString()` | 按本地化规则转为字符串 | `arr.toLocaleString(); // 原数组不变` | +| `entries()` | 返回迭代器(包含索引和值) | `for (let [i, v] of arr.entries()) {} // 原数组不变` | +| `keys()` | 返回索引迭代器 | `for (let i of arr.keys()) {} // 原数组不变` | +| `values()` | 返回值迭代器 | `for (let v of arr.values()) {} // 原数组不变` | + +### 数组方法分类完整版本(是否修改原数组) + +#### 修改原数组的方法 + +这类方法直接操作原数组,执行后原数组的内容 / 结构会发生变化,返回值标注在说明中。 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| -------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `push()` | 向数组末尾添加 1 + 元素,返回新长度 | `array.push(...items)`<br>✅ `items`:要添加的元素(1 个或多个) | `items`:<br>- 必选<br>- 任意类型的元素,数量不限 | `const arr = [1,2]; arr.push(3,4); // arr变为[1,2,3,4],返回4` | +| `pop()` | 删除数组最后一个元素,返回被删除的元素 | `array.pop()`<br>无参数 | 无 | `const arr = [1,2,3]; arr.pop(); // arr变为[1,2],返回3` | +| `unshift()` | 向数组开头添加 1 + 元素,返回新长度 | `array.unshift(...items)`<br>✅ `items`:要添加的元素(1 个或多个) | `items`:<br>- 必选<br>- 任意类型的元素,数量不限 | `const arr = [2,3]; arr.unshift(1); // arr变为[1,2,3],返回3` | +| `shift()` | 删除数组第一个元素,返回被删除的元素 | `array.shift()`<br>无参数 | 无 | `const arr = [1,2,3]; arr.shift(); // arr变为[2,3],返回1` | +| `splice()` | 增 / 删 / 改数组元素,返回被删除的元素数组 | `array.splice(start, deleteCount, ...items)`<br>✅ `start`:起始索引<br>❓ `deleteCount`:删除数量(默认删到末尾)<br>❓ `items`:要添加的元素(可选) | - `start`:<br> 必选,整数,指定操作起始位置(负数表示倒数)<br>- `deleteCount`:<br> 可选,非负整数,要删除的元素数量(0 则不删除)<br>- `items`:<br> 可选,要插入到数组中的元素 | `const arr = [1,2,3]; arr.splice(1,1,4); // arr变为[1,4,3],返回[2]` | +| `sort()` | 排序数组元素(默认按字符串 Unicode 码点),返回排序后的数组 | `array.sort(compareFn)`<br>❓ `compareFn(a, b)`:排序对比函数(可选) | - `compareFn`:<br> 可选,回调函数,接收两个参数:<br> ✅ `a`:第一个用于比较的元素<br> ✅ `b`:第二个用于比较的元素<br> 返回值:<0 则 a 排 b 前,=0 则位置不变,>0 则 b 排 a 前 | `const arr = [3,1,2]; arr.sort((a,b) => a-b); // arr变为[1,2,3],返回[1,2,3]` | +| `reverse()` | 反转数组元素顺序,返回反转后的数组 | `array.reverse()`<br>无参数 | 无 | `const arr = [1,2,3]; arr.reverse(); // arr变为[3,2,1],返回[3,2,1]` | +| `fill()` | 用指定值填充数组(覆盖指定范围),返回填充后的数组 | `array.fill(value, start, end)`<br>✅ `value`:填充值<br>❓ `start`:起始索引(默认 0)<br>❓ `end`:结束索引(默认数组长度,不含) | - `value`:<br> 必选,任意类型,填充到数组的值<br>- `start`:<br> 可选,整数,填充起始位置(负数表示倒数)<br>- `end`:<br> 可选,整数,填充结束位置(不含) | `const arr = [1,2,3]; arr.fill(0,1,2); // arr变为[1,0,3],返回[1,0,3]` | +| `copyWithin()` | 复制数组指定范围元素到目标位置,返回修改后的数组 | `array.copyWithin(target, start, end)`<br>✅ `target`:目标位置索引<br>❓ `start`:复制起始索引(默认 0)<br>❓ `end`:复制结束索引(默认数组长度,不含) | - `target`:<br> 必选,整数,复制元素要粘贴到的位置<br>- `start`:<br> 可选,整数,复制起始位置(负数表示倒数)<br>- `end`:<br> 可选,整数,复制结束位置(不含) | `const arr = [1,2,3,4]; arr.copyWithin(0,2); // arr变为[3,4,3,4],返回[3,4,3,4]` | + +#### 不修改原数组的方法 + +这类方法不会改变原数组,返回新数组 / 非数组值,原数组保持原样。 + +##### 返回新数组的方法 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| ----------- | ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `slice()` | 截取数组指定范围元素,返回新数组(含头不含尾) | `array.slice(start, end)`<br>❓ `start`:起始索引(默认 0)<br>❓ `end`:结束索引(默认数组长度,不含) | - `start`:<br> 可选,整数,截取起始位置(负数表示倒数)<br>- `end`:<br> 可选,整数,截取结束位置(不含) | `const arr = [1,2,3]; const newArr = arr.slice(1); // newArr=[2,3],arr仍为[1,2,3]` | +| `concat()` | 拼接数组 / 值,返回新数组 | `array.concat(...arrays/values)`<br>❓ `arrays/values`:要拼接的数组或值(可选) | `arrays/values`:<br>- 可选<br>- 任意数量的数组或单个值(任意类型) | `const arr1 = [1,2]; const arr2 = arr1.concat(3,[4]); // arr2=[1,2,3,4],arr1不变` | +| `map()` | 遍历数组,对每个元素处理后返回新数组 | `array.map(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:处理函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 map 的原数组(可选) | - `callback`:<br> 必选,对每个元素的处理逻辑,返回处理后的值<br>- `thisArg`:<br> 可选,指定 callback 内 this 的指向<br>- `currentValue`:<br> 必选,数组中正在处理的当前元素<br>- `index`:<br> 可选,当前元素在数组中的索引<br>- `array`:<br> 可选,调用 map 的原数组 | `const arr = [1,2]; const newArr = arr.map((item, idx) => item*2); // newArr=[2,4],arr不变` | +| `filter()` | 过滤数组元素,返回符合条件的新数组 | `array.filter(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:筛选函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 filter 的原数组(可选) | - `callback`:<br> 必选,返回布尔值(true 保留元素,false 过滤)<br>- `thisArg`:<br> 可选,指定 callback 内 this 的指向<br>- `currentValue`:<br> 必选,数组中正在处理的当前元素<br>- `index`:<br> 可选,当前元素在数组中的索引<br>- `array`:<br> 可选,调用 filter 的原数组 | `const arr = [1,2,3]; const newArr = arr.filter((item) => item>1); // newArr=[2,3],arr不变` | +| `flat()` | 扁平化数组,返回新数组 | `array.flat(depth)`<br>❓ `depth`:扁平化深度(默认 1) | `depth`:<br>- 可选<br>- 非负整数,指定扁平化的层级(Infinity 表示无限层级) | `const arr = [1,[2,[3]]]; const newArr = arr.flat(2); // newArr=[1,2,3],arr不变` | +| `flatMap()` | `map + flat(1)`结合,返回新数组 | `array.flatMap(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:处理函数(同 map)<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 flatMap 的原数组(可选) | - `callback`:<br> 必选,返回单个值或数组(最终会被扁平化 1 层)<br>- 其他参数同 map | `const arr = [1,2]; const newArr = arr.flatMap(i => [i,i*2]); // newArr=[1,2,2,4]` | +| `with()` | 替换数组指定索引的元素,返回新数组(ES2023) | `array.with(index, value)`<br>✅ `index`:要替换的索引<br>✅ `value`:新值 | - `index`:<br> 必选,整数,要替换的元素索引(负数表示倒数)<br>- `value`:<br> 必选,任意类型,替换后的新值 | `const arr = [1,2]; const newArr = arr.with(0, 3); // newArr=[3,2],arr仍为[1,2]` | + +##### 返回非数组值的方法 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| ------------------ | ------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `forEach()` | 遍历数组(无返回值,仅执行回调) | `array.forEach(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:遍历执行的函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 forEach 的原数组(可选) | - `callback`:<br> 必选,无返回值(返回值会被忽略)<br>- `thisArg`:<br> 可选,指定 callback 内 this 的指向<br>- `currentValue`:<br> 必选,数组中正在处理的当前元素<br>- `index`:<br> 可选,当前元素在数组中的索引<br>- `array`:<br> 可选,调用 forEach 的原数组 | `arr.forEach((item, idx) => console.log(idx, item)); // 原数组不变` | +| `find()` | 返回第一个符合条件的元素(无则 undefined) | `array.find(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:查找条件函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 find 的原数组(可选) | - `callback`:<br> 必选,返回布尔值(true 则返回当前元素)<br>- 其他参数同 forEach | `const arr = [1,2,3]; arr.find(item => item>1); // 返回2,arr不变` | +| `findIndex()` | 返回第一个符合条件的元素索引(无则 - 1) | `array.findIndex(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:查找条件函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 findIndex 的原数组(可选) | - `callback`:<br> 必选,返回布尔值(true 则返回当前索引)<br>- 其他参数同 forEach | `const arr = [1,2,3]; arr.findIndex(item => item>1); // 返回1,arr不变` | +| `includes()` | 判断数组是否包含指定值,返回布尔值 | `array.includes(value, start)`<br>✅ `value`:要查找的值<br>❓ `start`:起始查找索引(默认 0) | - `value`:<br> 必选,任意类型,要查找的目标值<br>- `start`:<br> 可选,整数,查找起始位置(负数表示倒数) | `const arr = [1,2,3]; arr.includes(2); // 返回true,arr不变` | +| `indexOf()` | 返回指定值首次出现的索引(无则 - 1) | `array.indexOf(value, start)`<br>✅ `value`:要查找的值<br>❓ `start`:起始查找索引(默认 0) | - `value`:<br> 必选,任意类型,要查找的目标值<br>- `start`:<br> 可选,整数,查找起始位置(负数表示倒数) | `const arr = [1,2,3]; arr.indexOf(2); // 返回1,arr不变` | +| `lastIndexOf()` | 返回指定值最后出现的索引(无则 - 1) | `array.lastIndexOf(value, start)`<br>✅ `value`:要查找的值<br>❓ `start`:起始查找索引(默认数组长度 - 1) | - `value`:<br> 必选,任意类型,要查找的目标值<br>- `start`:<br> 可选,整数,反向查找的起始位置(负数表示倒数) | `const arr = [1,2,2,3]; arr.lastIndexOf(2); // 返回2,arr不变` | +| `every()` | 判断所有元素是否符合条件,返回布尔值 | `array.every(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:判断函数<br> ❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 every 的原数组(可选) | - `callback`:<br> 必选,返回布尔值(所有元素返回 true 则最终为 true)<br>- 其他参数同 forEach | `const arr = [1,2,3]; arr.every(item => item>0); // 返回true,arr不变` | +| `some()` | 判断是否有元素符合条件,返回布尔值 | `array.some(callback(currentValue, index, array), thisArg)`<br>✅ `callback`:判断函数<br>❓ `thisArg`:执行 callback 时的 this 指向(可选)<br>callback 参数:<br>✅ `currentValue`:当前处理的元素<br>❓ `index`:当前元素索引(可选)<br>❓ `array`:调用 some 的原数组(可选) | - `callback`:<br> 必选,返回布尔值(任意元素返回 true 则最终为 true)<br>- 其他参数同 forEach | `const arr = [1,2,3]; arr.some(item => item>2); // 返回true,arr不变` | +| `reduce()` | 累加 / 归并数组,返回最终归并值 | `array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)`<br>✅ `callback`:归并函数<br>❓ `initialValue`:累加器初始值(可选)<br>callback 参数:<br>✅ `accumulator`:累加器(累计结果)<br>✅ `currentValue`:当前处理的元素<br>❓ `currentIndex`:当前元素索引(可选)<br>❓ `array`:调用 reduce 的原数组(可选) | - `callback`:<br> 必选,返回累计结果(会作为下一次的 accumulator)<br>- `initialValue`:<br> 可选,累加器初始值(无则用数组第一个元素)<br>- `accumulator`:<br> 必选,累计的结果值<br>- `currentValue`:<br> 必选,当前处理的元素<br>- `currentIndex`:<br> 可选,当前元素索引<br>- `array`:<br> 可选,调用 reduce 的原数组 | `const arr = [1,2,3]; arr.reduce((sum, item) => sum+item, 0); // 返回6,arr不变` | +| `reduceRight()` | 从右到左归并数组,返回最终归并值 | `array.reduceRight(callback(accumulator, currentValue, currentIndex, array), initialValue)`<br>✅ `callback`:归并函数(同 reduce)<br>❓ `initialValue`:累加器初始值(可选)<br>callback 参数:同 reduce | 同 reduce,仅遍历顺序为从右到左 | `const arr = [1,2,3]; arr.reduceRight((sum, item) => sum+item, 0); // 返回6,arr不变` | +| `join()` | 将数组转为字符串,返回拼接后的字符串 | `array.join(separator)`<br>❓ `separator`:分隔符(默认逗号) | `separator`:<br>- 可选<br>- 字符串,元素之间的分隔符(空字符串则无分隔) | `const arr = [1,2,3]; arr.join(','); // 返回"1,2,3",arr不变` | +| `toString()` | 将数组转为字符串(默认用逗号分隔) | `array.toString()`<br>无参数 | 无 | `const arr = [1,2,3]; arr.toString(); // 返回"1,2,3",arr不变` | +| `toLocaleString()` | 按本地化规则转为字符串 | `array.toLocaleString(locales, options)`<br>❓ `locales`:语言 / 地区代码(可选)<br>❓ `options`:格式化选项(可选) | - `locales`:<br> 可选,如 "zh-CN"、"en-US"<br>- `options`:<br> 可选,对象,配置格式化规则 | `const arr = [1234, new Date()]; arr.toLocaleString(); // 按本地格式返回字符串` | +| `entries()` | 返回迭代器(包含索引和值) | `array.entries()`<br>无参数 | 无 | `for (let [i, v] of arr.entries()) {} // 原数组不变` | +| `keys()` | 返回索引迭代器 | `array.keys()`<br>无参数 | 无 | `for (let i of arr.keys()) {} // 原数组不变` | +| `values()` | 返回值迭代器 | `array.values()`<br>无参数 | 无 | `for (let v of arr.values()) {} // 原数组不变` | + +#### 标注说明 + +- ✅:参数为**必选** +- ❓:参数为**可选** +- 回调函数的返回值:除标注外,`map`返回处理后的值、`filter`返回布尔值、`find/findIndex`返回布尔值、`every/some`返回布尔值、`reduce/reduceRight`返回累计值,`forEach`无返回值(返回 undefined)。 +- `thisArg`参数:所有带`thisArg`的方法,若省略则 callback 内的`this`指向:非严格模式下为全局对象,严格模式下为 undefined \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251222-js\345\215\232\345\256\242CRUD01.md" "b/\347\275\227\347\232\223\346\231\250/20251222-js\345\215\232\345\256\242CRUD01.md" new file mode 100644 index 0000000000000000000000000000000000000000..bf3d67d3b0e78aaef3053ac447467981542c842c --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251222-js\345\215\232\345\256\242CRUD01.md" @@ -0,0 +1,442 @@ + + +## 笔记:罗老师手把手教你搓模态框 + +实现一个可控制显隐、遮挡底层操作、承载交互内容的模态框组件,核心是**遮罩层隔离底层操作** + **内容容器承载交互** + **类名控制显隐 / 内容切换**。 + +### 实现步骤(核心三步) + +#### 构建全屏遮罩层(隔离底层操作) + +##### 核心要求 + +创建 100vw*100vh (全屏)的半透明遮罩层,模态框显示时阻止用户操作底层的 “数据渲染 / 交互层”。 + +##### 具体实现 + +**HTML 结构**:创建遮罩层容器,作为模态框的外层容器: + +```html +<!-- 模态框遮罩层(核心容器) --> +<div class="modal-mask" id="modalMask"> + <!-- 模态框内容容器(步骤2实现) --> + <div class="modal-content"></div> +</div> +``` + + + +**CSS 样式**:设置全屏、半透明、固定定位,初始隐藏,阻止点击穿透: + +```css +/* 遮罩层核心样式 */ +.modal-mask { + /* 全屏覆盖 */ + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + /* 半透明黑色背景,遮挡底层 */ + background: rgba(0, 0, 0, 0.7); + /* 层级高于底层(根据实际调整z-index) */ + z-index: 999; +} +``` + +#### 构建模态框内容容器(承载交互内容) + +##### 核心要求 + +在遮罩层内定义合适大小的盒子作为交互消息容器,通过定位确定位置(通常居中)。 + +##### 具体实现 + +**CSS 样式**:给内容容器设置尺寸、背景、圆角等样式,绝对 / 弹性定位居中: + +```css +/* 模态框内容容器 */ +.modal-content { + /* 绝对定位 */ + position: absolute; + /* 水平垂直居中 */ + /* 还可通过 position: absolute + top: 50% + left: 50% + transform: translate(-50%, -50%)实现居中。 */ + left: 50%; + top: 50%; + margin-left: calc(-400px /2); + margin-top: calc(-250px /2); + /* 交互消息容器大小 */ + width: 400px; + height: 250px; + /* 其余美化样式 */ + background-color: rgb(255, 255, 255); + border-radius: 5px; + z-index: 1000; +} +``` + +#### 类名控制显隐与内容切换 + +##### 核心要求 + +- 初始化(onload)时给模态框加 `hide` 类隐藏; +- 触发事件(如点击按钮)时移除 `hide` 类显示; +- 通过 `show` 类(或多类名)控制模态框内不同交互内容的显示。 + +##### 具体实现 + +**定义显隐类名**: + +```css +/* 显示模态框的类 */ +.show { + display: block; +} + +/* 隐藏模态框的类(初始默认) */ +.hide { + display: none; +} +``` + +**JS 控制显隐与内容切换**:开发中往往只需要.hide和.show其中一个类就可以达到隐藏或显示的效果,以下是只使用.hide类的示例 + +```javascript + // 1. 初始化:给遮罩层加hide类隐藏 + document.addEventListener('DOMContentLoaded', () => { + const modalMask = document.getElementById('modalMask'); + modalMask.classList.add('hide'); + }); + + // 2. 打开模态框:移除hide类即可显示 + const openModalBtn = document.getElementById('显示开关'); + openModalBtn.addEventListener('click', () => { + const modalMask = document.getElementById('modalMask'); + modalMask.classList.remove('hide'); + // 如果有内部内容切换,同理:移除hide类显示 + document.querySelector('.content-item.login').classList.remove('hide'); + }); + + // 3. 关闭模态框:添加hide类即可隐藏 + function closeModal() { + const modalMask = document.getElementById('modalMask'); + modalMask.classList.add('hide'); + // 内部内容如需隐藏,加hide类即可 + document.querySelector('.content-item.login').classList.add('hide'); + } + + // 4.绑定关闭事件 + const closeModalBtn = document.getElementById('关闭开关'); + const modalMask = document.getElementById('modalMask'); + closeModalBtn.addEventListener('click', closeModal); + modalMask.addEventListener('click', (e) => { + if (e.target === modalMask) closeModal(); + }); +``` + +### 关键细节与最佳实践 + +**层级控制**:遮罩层 `z-index` 需高于页面所有底层内容(建议 999+),内容容器 `z-index` 高于遮罩层,避免被遮挡。 + +**阻止底层滚动**:模态框显示时,给 `body` 添加 `overflow: hidden`,防止底层页面滚动:关闭时移除该类 + +```css +body.modal-open { + overflow: hidden; +} +``` + +## 作业 + +### 一个用于渲染页面的前端与其样式 + +#### HTML + +```html +<!DOCTYPE html> +<html lang="zh-cn"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale = 1.0"> + <title>博客 + + + + + +
+ +
+ +
+
+
+

博客列表

+
+
+ +
查找
+
新增
+
+
+ + + + + + + + + + + + +
序号标题内容摘要作者发布日期操作
+
+
+
+ + + + +``` +#### CSS + +```css +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: Arial, sans-serif; + font-size: 14px; + background-color: rgb(245, 245, 245); +} + +.container { + height: auto; + width: 100vw; + display: flex; + justify-content: center; + align-items: center; + +} + +.blog-container { + height: auto; + width: 800px; + display: flex; + flex-direction: column; + background-color: #fff; + border-radius: 5px; +} + +.blog-title { + line-height: 40px; + margin-top: 10px; + margin-left: 20px; +} + +.search-section { + height: 40px; + display: flex; + justify-content: space-between; + align-items: center; + margin: 0 20px; +} + +#searchInput { + width: 660px; + height: 30px; + border-radius: 5px; + border: 1px solid grey; + padding-left: 5px; +} + +.action-button { + background-color: rgb(238, 238, 238); + text-align: center; + line-height: 30px; + width: 42px; + border-radius: 3px; + user-select: none; + border: 1px solid grey; + cursor: pointer; + transition: 0.3s ease-in-out +} + +.action-button:hover { + transform: translateY(-1px); + background-color: rgb(200, 200, 200); +} + +.blog-list { + padding-top: 10px; + margin: 0 20px; +} + +table { + border-collapse: collapse; + width: 100%; +} + +.container td, +th { + border: 1px solid rgb(220, 220, 220) !important; + padding: 0 5px; + text-align: center; +} + +td { + line-height: 28px; +} + +th { + background-color: #f0f0f0; + line-height: 40px; + font-size: 20px; +} + +.action-group { + display: flex; + width: 100%; + height: 100%; + justify-content: space-around; + align-items: center; +} + +.action-item { + text-align: center; + line-height: 26px; + width: 38px; + border-radius: 3px; + user-select: none; + color: #fff; + cursor: pointer; + transition: 0.3s ease-in-out; +} + +.edit-button { + background-color: rgb(0, 128, 0); +} + +.delete-button { + background-color: rgb(255, 0, 0); +} + +.edit-button:hover { + background-color: rgb(0, 100, 0); +} + +.delete-button:hover { + background-color: rgb(200, 0, 0); +} + + +#mask-layer { + width: 100vw; + height: 100vh; + background-color: rgba(0, 0, 0, 0.8); + position: fixed; + justify-content: center; + align-items: center; +} + + + +#modal-box { + position: absolute; + left: 50%; + top: 50%; + margin-left: calc(-400px /2); + margin-top: calc(-250px /2); + width: 400px; + height: 250px; + background-color: rgb(255, 255, 255); + border-radius: 5px; +} + +.modal-table>p { + padding-bottom: 20px; + font-size: 30px; + font-weight: 800; + text-align: center; + +} +#mask-layer table,tr,td{ + border: none; +} + +.operate { + padding: 20px; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.hidden { + overflow: hidden; +} +``` + diff --git "a/\347\275\227\347\232\223\346\231\250/20251224-js\345\215\232\345\256\242CRUD02.md" "b/\347\275\227\347\232\223\346\231\250/20251224-js\345\215\232\345\256\242CRUD02.md" new file mode 100644 index 0000000000000000000000000000000000000000..22baed41599cdd50dbd6f5ed5a003eb453da8298 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251224-js\345\215\232\345\256\242CRUD02.md" @@ -0,0 +1,170 @@ +## 笔记 + +老虎来也!!!老虎到此一游!!! + +## 作业 + +### 实现增删改 + +```js +const url = 'https://api.9ihub.com/api/posts' + +// 初始化数据 +$(function () { + $('#mask-layer').addClass('hide') + $('.add').addClass('hide') + $('.update').addClass('hide') + let str = `` + fetch(url) + .then(res => res.json()) + .then(data => { + data.sort((o1, o2) => o1.id - o2.id); + data.forEach(item => { + str += ` + ${item.id} + ${item.title} + ${item.summary} + ${item.author} + ${item.published_at} + +
+
编辑
+
删除
+
+ + ` + }); + $('#blog-table-body').append(str) + console.log(data); + }) + .catch(err => console.error(err)); +}) + +//删除数据 +$('#blog-table-body').on('click', '.delete-button', function () { + const postId = $(this).closest('tr').attr('id').replace('blog', '') + let urlDelete = `https://api.9ihub.com/api/posts/${postId}` + console.log(postId); + fetch(urlDelete, { + method: 'DELETE' + }) + .then(res => { + if (res.ok) { + console.log('deleted'); + $(`#blog${postId}`).remove() + } + else console.error('delete failed'); + }) + .catch(err => console.error(err)); +}) + +//添加数据 +$('.add-button').on('click', function () { + $('#mask-layer').addClass('show') + $('.add').addClass('show') + $('body').addClass('hidden') +}) +$('#add-sure').on('click', function () { + let newTitle = $('#add-title').val() + let newSummary = $('#add-summary').val() + let newAuthor = $('#add-author').val() + let addObj = '' + fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + title: newTitle, + summary: newSummary, + author: newAuthor, + published_at: '2025-12-18T09:37:00Z' + }) + }) + .then(res => res.json()) + .then(created => { + addObj = ` + ${created.id} + ${newTitle} + ${newSummary} + ${newAuthor} + ${created.published_at} + +
+
编辑
+
删除
+
+ + `; + $('#blog-table-body').append(addObj); + } + ) + .catch(err => console.error(err)); + closeAddModalBox() + $('#add-title').val('') + $('#add-summary').val('') + $('#add-author').val('') +}) +$('#add-cancel').on('click', function() { + $('#mask-layer').removeClass('show') + $('.add').removeClass('show') + $('body').removeClass('hidden') +}) + +//编辑数据 +$('#blog-table-body').on('click', '.edit-button', function () { + $('#mask-layer').addClass('show') + $('.update').addClass('show') + $('body').addClass('hidden') +}) +let updateId = null +function blogId(obj, id) { + updateId = id + console.log($(obj).data('id')); +} +$('#update-sure').on('click', function () { + let postId = updateId + let urlPut = `https://api.9ihub.com/api/posts/${postId}` + let newTitle = $('#update-title').val() + let newSummary = $('#update-summary').val() + let newAuthor = $('#update-author').val() + fetch(urlPut, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + title: newTitle, + summary: newSummary, + author: newAuthor, + published_at: new Date().toISOString() + }) + }) + .then(res => res.json()) + .then(updated => { + let putObj = ` + ${updated.id} + ${newTitle} + ${newSummary} + ${newAuthor} + ${updated.published_at} + +
+
编辑
+
删除
+
+ + `; + $(`#blog${postId}`).replaceWith(putObj) + }) + .catch(err => console.error(err)); + closeUpdateModalBox() +}) +$('#update-cancel').on('click', function() { + $('#mask-layer').removeClass('show') + $('.update').removeClass('show') + $('body').removeClass('hidden') +}) + + + + + +``` + diff --git "a/\347\275\227\347\232\223\346\231\250/20251225-\346\234\215\345\212\241\351\203\250\347\275\26201.md" "b/\347\275\227\347\232\223\346\231\250/20251225-\346\234\215\345\212\241\351\203\250\347\275\26201.md" new file mode 100644 index 0000000000000000000000000000000000000000..94f2d7f8ae8126708f963073fd33cdf210400ef8 --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251225-\346\234\215\345\212\241\351\203\250\347\275\26201.md" @@ -0,0 +1,142 @@ +## 笔记 + +### 一、部署前的核心准备 + +#### 1. 服务器准备 + +- 要求:带公网 IP 的 Linux 服务器(如 Ubuntu/CentOS) +- 核心作用:存放网站程序、运行服务的硬件载体 + +#### 2. 域名准备 + +- 要求:已完成备案的域名(国内服务器必需) +- 核心作用:让用户通过易记的域名访问网站,而非复杂的 IP 地址 + +### 二、服务器基础操作(Linux 常用命令) + +#### 1. 登录服务器 + +| 方式 | 说明 | +| ------ | ------------------------------------------------- | +| telnet | 上古时期协议,安全性低,不推荐 | +| SSH | 现代主流方式,命令示例:`ssh 用户名@服务器公网IP` | + +#### 2. 文件 / 目录管理 + +| 操作 | 命令 | 说明 | +| --------------- | ---------------- | ---------------------------------------------------- | +| 创建空文件 | `touch 文件名` | 例:`touch index.html` | +| 创建 / 编辑文件 | `vim 文件名` | 例:`vim index.html`(按 i 编辑,Esc+:+wq 保存退出) | +| 创建文件夹 | `mkdir 文件夹名` | 例:`mkdir /var/www/abc.liing.top` | +| 切换目录 | `cd 目录路径` | 例:`cd /var/www/abc.liing.top` | +| 列出目录内容 | `ls` | 查看当前目录文件;`ls -l`查看详细信息 | + +#### 3. 软件管理(apt 命令) + +| 操作 | 命令 | 说明 | +| ---------- | ------------------------- | --------------------------------------------- | +| 更新软件源 | `apt update` | 同步最新软件包列表(操作前先执行) | +| 安装软件 | `apt install 软件名 -y` | 例:`apt install nginx -y`(-y 自动确认安装) | +| 更新软件 | `apt upgrade -y` | 更新已安装的软件包 | +| 卸载软件 | `apt uninstall 软件名 -y` | 例:`apt uninstall nginx -y` | + +#### 4. 服务管理(systemctl 命令) + +| 操作 | 命令 | 说明 | +| ------------ | -------------------------- | ---------------------------------------------------- | +| 查看服务状态 | `systemctl status 服务名` | 例:`systemctl status nginx` | +| 启动服务 | `systemctl start 服务名` | 例:`systemctl start nginx` | +| 停止服务 | `systemctl stop 服务名` | 例:`systemctl stop nginx` | +| 重启服务 | `systemctl restart 服务名` | 例:`systemctl restart nginx` | +| 设置自启动 | `systemctl enable 服务名` | 例:`systemctl enable nginx`(服务器重启后自动运行) | + +### 三、域名解析(域名绑定) + +#### 1. 核心概念 + +- 域名解析:将易记的域名指向服务器公网 IP 的过程(让用户输入域名能找到对应服务器) +- IP 地址:网络中服务器的唯一标识,是解析的核心目标 + +#### 2. 操作步骤 + +1. 登录域名服务商后台(如阿里云、腾讯云) +2. 找到 “域名解析” 模块,添加解析记录 +3. 记录类型选 “A 记录”,主机记录填二级域名(如www),记录值填服务器公网 IP +4. 保存解析,等待生效(通常 5-10 分钟) + +### 四、Nginx 部署网站(核心步骤) + +#### 1. 安装 Nginx + +```bash +# 更新软件源 +apt update +# 安装Nginx +apt install nginx -y +# 验证安装(查看状态) +systemctl status nginx +``` + +#### 2. 配置 Nginx + +##### (1)配置文件位置 + +- 核心目录:`/etc/nginx/conf.d/`(推荐在此目录创建自定义配置文件) +- 文件名规范:建议以域名命名,例:`www.lhchen.asia.conf` + +##### (2)创建配置文件 + +```bash +# 新建配置文件 +vim /etc/nginx/conf.d/www.lhchen.asia.conf +``` + +##### (3)配置文件内容(基础版) + +```nginx +server { + # 监听80端口(HTTP协议) + listen 80; + # 绑定的域名 + server_name www.lhchen.asia; + + # 网站根目录配置 + location / { + # 网站文件存放路径 + root /var/www/www.lhchen.asia; + # 默认首页文件 + index index.html; + } +} +``` + +#### 3. 准备网站文件 + +```bash +# 创建网站根目录 +mkdir -p /var/www/www.lhchen.asia +# 创建测试首页文件 +touch /var/www/www.lhchen.asia/index.html +# 编辑首页内容(示例) +echo "

Hello, My Website!

" > /var/www/www.lhchen.asia/index.html +``` + +#### 4. 重启 Nginx 生效配置 + +```bash +systemctl restart nginx +``` + +### 五、可选配置:SSL 证书(HTTPS) + +- 作用:加密网站通信,提升安全性,浏览器显示 “锁” 图标 +- 部署方式: + 1. 申请免费证书(如 Let's Encrypt) + 2. 将证书文件上传至服务器 + 3. 修改 Nginx 配置,监听 443 端口并配置证书路径 + +### 总结 + +1. 部署网站核心流程:服务器准备 → 域名解析 → 安装 Web 服务(Nginx) → 配置站点 → 上传网站文件 → 验证访问。 +2. Linux 核心操作:掌握 SSH 登录、文件 / 目录管理、apt 软件安装、systemctl 服务管理是基础。 +3. Nginx 关键:配置文件需绑定域名和网站根目录,修改后必须重启服务才能生效。 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/20251226-\346\234\215\345\212\241\351\203\250\347\275\26202.md" "b/\347\275\227\347\232\223\346\231\250/20251226-\346\234\215\345\212\241\351\203\250\347\275\26202.md" new file mode 100644 index 0000000000000000000000000000000000000000..56a921dbce1f1ea109a9ad6f7f61a3823e11c2bd --- /dev/null +++ "b/\347\275\227\347\232\223\346\231\250/20251226-\346\234\215\345\212\241\351\203\250\347\275\26202.md" @@ -0,0 +1,7 @@ +## 笔记 + + 俄罗斯方块 + +## 作业 + + 俄罗斯方块 \ No newline at end of file diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..c171d01045ecfb07982eaeb5f75f55d2aa281ab0 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..c3171c331dd7de445f310348aad1e84b6671e87c Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251110_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..333b5a1c1351c1b24fbe60cb64b2f2d8d4558750 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..b0b53c99a6200442ebfa39f11ccb1926bbf10c47 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show03.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show03.png" new file mode 100644 index 0000000000000000000000000000000000000000..b1cc315013fe50ded101395fc614e13a35604e12 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251112_Image/show03.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..60f1d24cf6f6e4d65ac2b7ea1856b233688e9ec3 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..9d5dad8e7a1443236dc4d1eb34361d8522a2a3d7 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251113_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..9ab848b350f706c1d707b94b005c3061297d92e1 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..2a4b80b876c23ce98d5b41beb5681352ddda1042 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show03.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show03.png" new file mode 100644 index 0000000000000000000000000000000000000000..877c5fc50f1514b361cc3705497a6b930cd758ff Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251114_Image/show03.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251117_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251117_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..3aa10d5dadda2eca1f91d86eb2f47a0261be2a75 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251117_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..05483b381ed801bd5c7ae78367612e359fcc2e4f Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..120966f70b7057b5bd402f71b22896a49d64b178 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251119_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..a7cd7ab535ab56d2a6028e1854c2b10139ecc2b0 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..94dc07b2c7d36d07c6083317dff407962eb53f72 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251120_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show01.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show01.png" new file mode 100644 index 0000000000000000000000000000000000000000..192f108fd85c651c5d80f0f88f8915df0be37e47 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show01.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show02.png" "b/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show02.png" new file mode 100644 index 0000000000000000000000000000000000000000..1ac9b147bba4a9d9190ab1f358beb6b34b7d403c Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251124_Image/show02.png" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show01.gif" "b/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show01.gif" new file mode 100644 index 0000000000000000000000000000000000000000..c270418f52aa162daea235ae6777cf361c3e5df1 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show01.gif" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show02.gif" "b/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show02.gif" new file mode 100644 index 0000000000000000000000000000000000000000..410d55d0779e2515b4b735c0c4ead4cd13cc5d19 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251127_Image/show02.gif" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show01.gif" "b/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show01.gif" new file mode 100644 index 0000000000000000000000000000000000000000..271f77ac60020c876603191c22e9ef6b8849f4c6 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show01.gif" differ diff --git "a/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show02.gif" "b/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show02.gif" new file mode 100644 index 0000000000000000000000000000000000000000..a88473f5d330dff9111d0c2fa789b80cfe0cc240 Binary files /dev/null and "b/\347\275\227\347\232\223\346\231\250/Image/20251128_Image/show02.gif" differ