diff --git "a/\345\205\250\344\277\212\346\236\227/20251110-\350\257\276\345\240\202\347\254\224\350\256\260js\345\211\215\347\236\273.md" "b/\345\205\250\344\277\212\346\236\227/20251110-\350\257\276\345\240\202\347\254\224\350\256\260js\345\211\215\347\236\273.md" new file mode 100644 index 0000000000000000000000000000000000000000..2f808ecad389b16fec48818fd6733887573b3392 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251110-\350\257\276\345\240\202\347\254\224\350\256\260js\345\211\215\347\236\273.md" @@ -0,0 +1,38 @@ +# javaScript的几种使用方式 + +### 直接在页面中输入js代码 + ``` + + ``` + +### 链入外部js文件 + ``` + + + ``` + src中链接的就是外部js文件 + +### 引用 + ``` + + + ``` + + ## 作业 + ``` +

千里之行,始于足下。

+ document.getElementById('demo'); + + + + 我不是小灰灰 + +
+

我不是第一题

+

收货地址:

+ +

我不是第二题

+ + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251119-\345\257\271\350\261\241.md" "b/\345\205\250\344\277\212\346\236\227/20251119-\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..039334b9c41976e4f9769d48455cb7803bb905e3 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251119-\345\257\271\350\261\241.md" @@ -0,0 +1,214 @@ +## 对象的创建 +对象是键值对的集合(键为字符串 / Symbol,值为任意类型:基本类型、函数、对象等),用于存储和组织相关数据与功能,最常用的创建语法如下: +## 函数 +### 函数的定义 +#### 函数是有关键字function,函数名加一组参数以及置于花括号中需要执行的一段代码定义的。 +- 在同一个页面不要定义两个名称相同的函数 +例子 +``` +function hello(){ // 定义函数名称为hello + document.write(`say,hello`);//定义函数体 +} +function hello(){ // 定义相同的函数名 + alert(`say hello`); // 定义函数载体 +} +``` +- 由于两个函数名相同第一个函数被第二个函数给覆盖,导致第一个函数不被执行,因此在同一个页面中定义的函数名称必须唯一 +### 函数的简单调用与参数 +``` + function fn(parameters){ //定义函数 + some statements; //parameters 参数名 + } + fn(parameters); //调用函数 + + function 自定义函数名 (形参1,形参2,形参3){ + 函数体 + } +``` +### JavaScript 中的内置函数 +函数|描述| +|----------|--------| +parseInt()|将字符型转换为整型| +parseFloat()|将字符型转换为浮点型| +isNaN()|判断一个数值是否为NaN| +isFinite()|判断一个数值是否有限| +eval()|求字符中表达式的值| +encodeURL()|将URL字符串进行编码| +decodeURL()|对已编码的URL字符串进行解码| + + +### 匿名函数 +- 匿名函数定义函数的方法不需要指定函数名,把定义的含数赋值给一个变量,后面的程序就可以通过这个变量来调用这个函数,有很好的的可读性 +``` +let sum=function(x,y){ + return `x+y;` +}; +alert(`100+200="+sum(100,200)`) +页面显示的是:100+200=300 +``` + +总结: + +如果需要遍历键和值,推荐使用 Object.entries()。 +如果只需要键,使用 Object.keys()。 +如果只需要值,使用 Object.values()。 +for...in 由于会遍历原型链,现在已经不推荐用于遍历对象的自身属性。 +## 代码 +``` + + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251121-javascript\345\206\205\347\275\256\345\207\275\346\225\260.MD" "b/\345\205\250\344\277\212\346\236\227/20251121-javascript\345\206\205\347\275\256\345\207\275\346\225\260.MD" new file mode 100644 index 0000000000000000000000000000000000000000..cee6902704a7342f84699dae805119c653ec94b5 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251121-javascript\345\206\205\347\275\256\345\207\275\346\225\260.MD" @@ -0,0 +1,190 @@ +## 事件与Event +事件的核心概念 +事件:用户操作(如点击、输入)或浏览器行为(如页面加载完成)触发的行为。 +事件流:事件触发后在 DOM 树中的传播顺序,分为 冒泡阶段(从触发元素向上传播)和 捕获阶段(从顶层元素向下传播)。 +事件处理程序:响应事件的函数(如点击按钮后执行的逻辑)。 +Event常用方法 +事件类型 |触发场景 |示例 +|----|----|----| +click |鼠标左键点击元素 |按钮点击、链接跳转 +dblclick |鼠标左键双击元素 |双击编辑文本 +mouseover |鼠标移入元素(含子元素) |hover 提示框 +mouseout |鼠标移出元素(含子元素) |hover 提示框消失 +mousemove |鼠标在元素内移动 |拖拽功能、鼠标轨迹 +keydown |键盘按下(按住时连续触发) |输入框快捷键、游戏控制 +keyup |键盘松开 |输入完成验证 +input |输入框内容变化(实时触发) |搜索框联想、实时校验 +change |输入框内容确认变化(失焦 / 回车) |下拉框选择、文件上传 +focus |元素获得焦点(如点击输入框) |输入框激活样式 +blur |元素失去焦点(如点击输入框外) |输入框失活、内容保存 +submit |表单提交(点击提交按钮 / 回车) |登录表单、搜索表单 +load |页面 / 资源(图片、脚本)加载完成 |页面初始化逻辑 +resize |浏览器窗口大小改变| 响应式布局调整 +scroll |页面 / 元素滚动 |滚动加载、回到顶部 +事件绑定 +HTML 属性绑定(不推荐,耦合度高) +直接在 HTML 标签中通过 on事件名 属性指定处理函数,仅适用于简单场景。 +``` + + + + +``` +缺点:HTML 与 JS 耦合,无法绑定多个同类型事件。 + +DOM 属性绑定(简单场景可用) +通过 JS 获取 DOM 元素后,直接给 on事件名 属性赋值(函数引用或匿名函数)。 +``` + + + +``` +缺点:同一事件只能绑定一个处理函数(后续绑定会覆盖前一个)。 + +addEventListener(推荐,功能最强) +DOM 标准方法,支持绑定多个同类型事件、控制事件流(冒泡 / 捕获)、移除事件。 + +语法: +``` +元素.addEventListener(事件名, 处理函数, [捕获阶段标志]); +// 第三个参数:true=捕获阶段触发,false=冒泡阶段触发(默认false) +示例: + + + + +``` +- 优点: + +支持多个同类型事件(按绑定顺序触发); +可控制事件流(捕获 / 冒泡); +可通过 removeEventListener 移除事件(避免内存泄漏)。 +## 数组 +### 数组的创建 +创建方式: + +// 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); // 创建包含指定元素的数组 +####数组操作 +- 增 +方法 描述示例代码 结果(原数组变化) + +push(element1,...) 在数组 末尾 添加一个 / 多个元素 |let arr = [1,2]; arr.push(3,4); arr 变为 [1,2,3,4] +unshift(element1,...) 在数组 开头 添加一个 / 多个元素 let arr = [3,4]; arr.unshift(1,2); |arr 变为 [1,2,3,4] +splice(start, 0, item1,...) 在指定索引 start 处 插入 一个 / 多个元素 let arr = [1,4]; arr.splice (1, 0, 2, 3); // 索引 1 处插入,删除 0 个元素 arr 变为 [1,2,3,4] +- 删 +方法 描述 示例代码 结果(原数组变化) +pop() 删除数组 末尾 的最后一个元素 let arr = [1,2,3]; arr.pop(); arr 变为 [1,2](返回被删除的元素 3) +shift() 删除数组 开头 的第一个元素 let arr = [1,2,3]; arr.shift(); arr 变为 [2,3](返回被删除的元素 1) +splice(start, deleteCount) 从指定索引 start 开始,删除 deleteCount 个元素 let arr = [1,2,3,4]; arr.splice (1, 2); // 索引 1 开始,删除 2 个元素 arr 变为 [1,4](返回被删除的元素 [2,3]) +- 改 +方式 描述 示例代码 结果(原数组变化) +索引直接赋值 通过元素的索引直接修改其值 let arr = [1,2,3]; arr[1] = 20; arr 变为 [1,20,3] +splice(start, deleteCount, item1,...) 从指定索引 start 开始,替换 deleteCount 个元素为新元素 let arr = [1,2,3,4]; arr.splice (1, 2, "a", "b"); // 索引 1 开始,删除 2 个,插入 2 个 arr 变为 [1,"a","b",4](返回被删除的元素 [2,3]) +- 查 +方法 描述 示例代码 结果 +索引直接访问 通过元素的索引直接访问其值 let arr = [10, 20, 30]; console.log(arr[1]); 输出 20 +indexOf(element) 返回指定元素在数组中 第一次出现 的索引(无则返回 -1) let arr = [10, 20, 30, 20]; arr.indexOf(20); 返回 1 +lastIndexOf(element) 返回指定元素在数组中 最后一次出现 的索引(无则返回 -1) let arr = [10, 20, 30, 20]; arr.lastIndexOf(20); 返回 3 +includes(element) 判断数组是否包含指定元素(返回布尔值) let arr = [10, 20, 30]; arr.includes(20); 返回 true +find(callback) 返回数组中 第一个满足回调函数条件 的元素(无则返回 undefined) let arr = [5, 12, 8, 130]; arr.find(item => item > 10); 返回 12 +findIndex(callback) 返回数组中 第一个满足回调函数条件 的元素的索引(无则返回 -1) let arr = [5, 12, 8, 130]; arr.findIndex(item => item > 10); 返回 1 +遍历 +遍历数组中的每个元素并进行操作。 + +方法 描述 示例代码 +for 循环 使用索引遍历数组,最传统的方式 let arr = [1,2,3]; for (let i = 0; i < arr.length; i++) { console.log(arr[i]); } +forEach(callback) 遍历数组,对每个元素执行 callback(无返回值) let arr = [1,2,3]; arr.forEach((item, index) => console.log(item, index)); +for...of 循环 遍历数组元素(ES6+,简洁直观) let arr = [1,2,3]; for (let item of arr) { console.log(item); } +数组的常用方法 +除了上述操作方法外,还有一些常用的数组处理方法。 + +|方法 |描述 |示例代码 +|----|----|----| +map(callback) 遍历数组,|对每个元素执行 callback,返回 新数组(元素为回调返回值)|let arr = [1,2,3]; let newArr = arr.map (item => item * 2); //newArr 为 [2,4,6] +filter(callback) 遍历数组,|筛选出 满足条件(回调返回 true)的元素,返回新数组 |let arr = [1,2,3,4]; let newArr = arr.filter (item => item > 2); //newArr 为 [3,4] +reduce((acc, cur) => ..., initialValue)| 数组累加器,对数组元素逐个处理,返回最终累加结果 |let arr = [1,2,3,4]; let sum = arr.reduce ((acc, cur) => acc + cur, 0); //sum 为 10 +sort((a,b) => ...) |对数组元素排序(默认按 Unicode 编码排序,需自定义比较函数) |let arr = [3,1,2]; arr.sort ((a,b) => a - b); // 升序 → [1,2,3] +reverse()| 反转数组元素的顺序 |let arr = [1,2,3]; arr.reverse(); → [3,2,1] +join(separator) |将数组元素拼接为字符串,separator 为分隔符(默认逗号) |let arr = [1,2,3]; arr.join("-"); → "1-2-3" +concat(arr1, arr2,...) |合并多个数组,返回 新数组 let arr1 = [1,2]; |let arr2 = [3,4]; let newArr = arr1.concat(arr2); → [1,2,3,4] +slice(start, end) |截取数组(从 start 索引开始,到 end 索引结束,不包含 end),返回新数组 |let arr = [1,2,3,4]; arr.slice (1, 3); → [2,3](原数组不变) +flat(depth) |数组扁平化(将多维数组转为一维 / 指定深度) |let arr = [1, [2, [3]]]; arr.flat(2); → [1,2,3] +## 代码 +``` +

综合训练1

+

生成一个随机数

+
+ + + +
+ + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251124-\346\225\260\347\273\204\347\232\204\345\256\232\344\271\211.md" "b/\345\205\250\344\277\212\346\236\227/20251124-\346\225\260\347\273\204\347\232\204\345\256\232\344\271\211.md" new file mode 100644 index 0000000000000000000000000000000000000000..3bc90a2b993640f233137926e58a7e53716692c4 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251124-\346\225\260\347\273\204\347\232\204\345\256\232\344\271\211.md" @@ -0,0 +1,110 @@ +## string 对象 +# 笔记 + +## String对象 + +### String对象的创建 +``` +var newstr = new String(StringText); +``` +### 格式化字符串 + +|方法|说明| +|--|--| +|anchor|创建HTML锚| +|big|使用大号字体显示字符串| +|small|使用小号字体显示字符串| +|fontsize|使用指定的字体显示大小| +|bold|使用粗体显示字符串| +|italics|使用斜体显示字符串| + +## 代码图 +``` + + + + + + + + + + + + + +``` +## 效果图 +![](https://gitee.com/quan-junlin/tuchuangimgs/raw/master/Picgo/20251130184347423.png) \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/\345\205\250\344\277\212\346\236\227/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..306a2a8ae825294341f60a13c1cd0795d6ac0a3c --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,98 @@ +## 笔记 +## 正则表达式 + 正则表达式描述了一种字符串的匹配模式,即通过使用一系列普通字符串和特殊字符串来构建能够明确描述文本字符串的匹配模式,可以用来检查一个字符串是否含有某个字符串、将匹配的字符串替换或者从某个字符串中去除某个符合条件的字符串等。 + +## 正则表达式基本结构 +```js + /匹配对象的模式/ +``` + +## 正则表达式的作用 + + 1. 测试字符串的某个模式 + 2. 替换文本 + 3. 根据模式匹配 + +## 正则表达式语法 +书130~132 +## 代码图 +``` + + +``` +``` + + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" "b/\345\205\250\344\277\212\346\236\227/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..dfc7a30108a88c49c83144c0a23194645844367d --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" @@ -0,0 +1,130 @@ +## 笔记 + +## 异常处理 + +### 异常处理用2种 + 1. onerror事件 + 2. try...ccatch...finally事件 + +### 异常类型 + + 一个程序通常会出现3种类型的异常,分别为语法异常、运行时的异常、和逻辑异常。 + +### 使用try...ccatch...finally语句处理异常 +```js + //格式 + try{ + somestatements; + + }catch(err){ + somestatements; + + }finally{ + somestatements; + + } +``` + try:尝试执行代码的关键字。 + catch:捕捉异常的关键字。 + finally:最终被处理的区块的关键字,该关键字和后面花括号中的语句可以省略。 + +### Error对象 + try...ccatch...finally语句中,catch捕捉到的对象通常为Error对象,在该对象中包含异常的描述信息。JavaScript定义了6种类型的异常. + +|异常类型|发生异常原因| +|--|--| +|EvalError|错误发生在eval()函数中| +|RangeError|数字的值超出JavaScript可表示的范围| +|ReferenceError|使用了非法的应用| +|SyntaxError|语法错误| +|TypeError|变量的类型错误| +|URLError|在encodeURL()函数或者decodeURL()函数中发生了错误| + +#### Error对象有以下2个属性: +1. name: 表示异常类型的字符串 +2. message: 实际的异常信息 +## 代码图 +``` + +

综合练习1

+ +
+ + +
+ + +
+

综合练习2

+ + +
+ + +
+ + + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\345\205\250\344\277\212\346\236\227/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..d3b0cc7acf98b3e7ab3399d6484a261aef4e6af1 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,157 @@ +## 笔记 + +## 事件事件 + +### 概述 + + 1. 事件处理过程分为3步:1、发生事件;2、启动事件处理方程;3、事件处理程序做出反应。 + 2. 通常,事件处理器的命名原则是在事件名称加前缀欧尼,例如对于click事件,其处理器为onclick。 + +### 常用事件 + + 1. onclick——单击事件 + +### DOM事件模型——取消事件传递和默认处理 +``` +js +//取消游览器的事件传递 +function someHandle(event){ + event.stopPropagation(); +} +//取消事件传递后的默认处理 +function someHandle(event){ + event.preventDefault(); +} +``` +## 代码图 +``` + document.write(`

训练1

`) + function fn(cursor, i) { + if (i == 1) { + cursor.style.border = '5px solid red' + } + else { + cursor.style.border = 'none' + } + } + + + + +
+
+
+

训练2

+

中国的国球是什么()

+

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

+ + +

训练3

+
+
+ + +``` +``` +// 训练4 + function getWindowSize() { + let width = window.innerWidth; + let height = window.innerHeight; + alert(`窗口宽度:${width}px\n窗口高度:${height}px`) + } +``` +## 练习5 +```js +// 训练5 + function color(event) { + let obj = event.target; + obj.style.background = "red"; + obj.onblur = function () { + obj.style.background = "blue"; + }; + } +``` +## 示例图: +## 练习6和训练7 +``` + 训练6 + let yearSelect = document.getElementById('year'); + let currentYear = new Date().getFullYear(); + for(let i = currentYear ; i >= 1900; i--){ + let option = document.createElement('option'); + option.value = i; + option.textContent = i + '年'; + yearSelect.appendChild(option); + } + + function showBirth(){ + let year = yearSelect.value; + let month = document.getElementById('month').value; + let resultDom = document.getElementById('result'); + + if(year && month){ + let formatMonth = month.toString().padStart(2,'0'); + resultDom.textContent = `你的出生年月是:${year}年${formatMonth}月`; + }else{ + resultDom.textContent =''; + } + } + // 训练7 + function resetBirth(){ + document.getElementById('result').textContent=''; + return ture; + } + + + + + + + + + + + +
+ +``` +## 效果图 +![](https://gitee.com/quan-junlin/tuchuangimgs/raw/master/Picgo/20251130185321708.png) diff --git "a/\345\205\250\344\277\212\346\236\227/20251201-\344\275\234\344\270\232+\347\254\224\350\256\260.md" "b/\345\205\250\344\277\212\346\236\227/20251201-\344\275\234\344\270\232+\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..bdb45aff32ca1113bcbc22ee8cd2664ac5ad39ca --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251201-\344\275\234\344\270\232+\347\254\224\350\256\260.md" @@ -0,0 +1,4 @@ +## 笔记 +/ 拖拽过程中(移动时连续触发)drag +// 拖拽结束(松开鼠标时)dragend +// 进入放置区域dragenter \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251203-\344\275\234\344\270\232+\347\254\224\350\256\260.md" "b/\345\205\250\344\277\212\346\236\227/20251203-\344\275\234\344\270\232+\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..46dc2987dd127df7048e5f0b0d0c2dc0cb09a5cd --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251203-\344\275\234\344\270\232+\347\254\224\350\256\260.md" @@ -0,0 +1,134 @@ +## 笔记 +### querySelector():它返回文档中与指定的css选择器匹配的第一个元素。如果没有找到匹配项,则返回null +createEiement():根据指定名称创建元素 +appendchild():将一个节点(元素)作为最后个子元素添加到别一个元素中 +## 代码图 +``` + + + +``` +``` + + + + + + Document + + + +
+ + + + +``` +``` + +
+ + +``` +``` + --> + + +
+        

李白 《行路难.其一》

+

金樽清酒斗十千,玉盘珍羞直万钱

+

停杯投箸不能食,拔剑四顾心茫然

+

欲渡黄河冰塞川,将登太行雪满山

+

闲来垂钓碧溪上,忽复乘舟梦日边

+

行路难!行路难!,多歧路,今安在

+

长风破浪会有时,直挂云帆济沧海

+
+ + +``` +``` + 弹出图片与对话框 + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251204-\344\275\234\344\270\232+\347\254\224\350\256\260.md" "b/\345\205\250\344\277\212\346\236\227/20251204-\344\275\234\344\270\232+\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..4ff909875ce92e5e86cbc4a9d2f2cb73001df1ed --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251204-\344\275\234\344\270\232+\347\254\224\350\256\260.md" @@ -0,0 +1,10 @@ +## 笔记 +增:创建 +appendChild()--插入节点末尾 +createElement() --创建标签 +createTextNode() --添加文本 +insertBefore()- 插入标签 +cloneNode()-复制标签 +删: +removeChild() +替换节点replaceChild() diff --git "a/\345\205\250\344\277\212\346\236\227/20251205-\344\275\234\344\270\232+\347\254\224\350\256\260.md" "b/\345\205\250\344\277\212\346\236\227/20251205-\344\275\234\344\270\232+\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..47ba6ae083cf35c2b5e8530ff1d8d0169b56ebcc --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251205-\344\275\234\344\270\232+\347\254\224\350\256\260.md" @@ -0,0 +1,263 @@ +## 笔记 +## 代码图 +``` + + + +
+ + +``` +``` + 想什么输赢,公平,剧情都被你洞悉 + + +
+ + + +``` +``` +

最新电影资讯

+ + 输入影片资讯编号: + + + +``` +``` +
+ + +
+ + +``` +``` +

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

+ + + + + + + + +
+ + + +``` +``` + +``` +``` + +
一生只爱一个人
+将粗体改为斜体 +``` +``` + + + + + +``` +``` + + + + +
+ +``` diff --git "a/\345\205\250\344\277\212\346\236\227/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\347\261\273\345\236\213.md" "b/\345\205\250\344\277\212\346\236\227/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\347\261\273\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..7be3f2f20b6de5e64d875f9d2194e95c4dd025ad --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\347\261\273\345\236\213.md" @@ -0,0 +1,283 @@ +# JavaScript 浏览器对象知识点总结 + +## 📍 location 对象 + +### 知识点 +1. **作用**:包含当前URL的信息,可用于获取和设置URL +2. **属性**: + - `href`:完整的URL + - `protocol`:协议(http:、https:) + - `host`:主机名和端口号 + - `hostname`:主机名 + - `port`:端口号 + - `pathname`:路径部分 + - `search`:查询字符串(?之后的部分) + - `hash`:锚点部分(#之后的部分) + - `origin`:协议+主机名+端口号 +3. **方法**: + - `assign(url)`:加载新文档 + - `replace(url)`:替换当前文档(不产生历史记录) + - `reload(force)`:重新加载当前页面 + - `toString()`:返回完整的URL + +### 示例 +```javascript +// 获取当前URL信息 +console.log('完整URL:', location.href); +console.log('协议:', location.protocol); +console.log('主机:', location.host); +console.log('路径:', location.pathname); +console.log('查询参数:', location.search); +console.log('锚点:', location.hash); +console.log('源:', location.origin); + +// 操作URL +// 1. 跳转到新页面(会产生历史记录) +location.assign('https://www.example.com'); + +// 2. 替换当前页面(不会产生历史记录) +location.replace('https://www.example.com'); + +// 3. 重新加载页面 +location.reload(); // 可能从缓存加载 +location.reload(true); // 强制从服务器重新加载 + +// 4. 修改URL的部分内容 +// 只修改hash,不会重新加载页面 +location.hash = '#section1'; + +// 只修改search,会重新加载页面 +location.search = '?page=2'; + +// 完整URL修改,会跳转到新页面 +location.href = 'https://newdomain.com/path'; +``` + +--- + +## 🧭 navigator 对象 + +### 知识点 +1. **作用**:包含浏览器的信息和状态 +2. **常用属性**: + - `userAgent`:用户代理字符串 + - `platform`:操作系统平台 + - `language`:浏览器主语言 + - `languages`:用户偏好的语言数组 + - `cookieEnabled`:是否启用cookie + - `onLine`:是否联网 + - `geolocation`:地理位置API + - `mediaDevices`:媒体设备API + - `hardwareConcurrency`:CPU核心数 +3. **常用方法**: + - `sendBeacon()`:异步发送数据到服务器 + - `clipboard`:剪贴板API + - `vibrate()`:设备振动(移动端) + +### 示例 +```javascript +// 浏览器信息检测 +console.log('用户代理:', navigator.userAgent); +console.log('操作系统:', navigator.platform); +console.log('主语言:', navigator.language); +console.log('支持语言:', navigator.languages); +console.log('Cookie启用:', navigator.cookieEnabled); +console.log('在线状态:', navigator.onLine); +console.log('CPU核心数:', navigator.hardwareConcurrency); + +// 特性检测(推荐方式) +if ('geolocation' in navigator) { + navigator.geolocation.getCurrentPosition(position => { + console.log('纬度:', position.coords.latitude); + console.log('经度:', position.coords.longitude); + }); +} + +if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { + // 可以访问摄像头/麦克风 +} + +// 发送数据到服务器(适合页面卸载时) +navigator.sendBeacon('/api/log', JSON.stringify({ + event: 'page_unload', + time: Date.now() +})); + +// 剪贴板操作 +if (navigator.clipboard) { + // 写入剪贴板 + navigator.clipboard.writeText('要复制的文本').then(() => { + console.log('复制成功'); + }); + + // 读取剪贴板 + navigator.clipboard.readText().then(text => { + console.log('剪贴板内容:', text); + }); +} + +// 设备振动(移动设备) +if ('vibrate' in navigator) { + // 振动200ms + navigator.vibrate(200); + // 模式:振动200ms,暂停100ms,振动300ms + navigator.vibrate([200, 100, 300]); +} +``` + +--- + +## 🖥️ screen 对象 + +### 知识点 +1. **作用**:包含屏幕/显示器的信息 +2. **属性**: + - `width` / `height`:屏幕的总宽度/高度 + - `availWidth` / `availHeight`:可用宽度/高度(减去任务栏等) + - `colorDepth`:颜色深度(位) + - `pixelDepth`:像素深度(位) + - `orientation`:屏幕方向 + - `availLeft` / `availTop`:可用空间的左边/上边坐标 + +### 示例 +```javascript +// 获取屏幕信息 +console.log('屏幕分辨率:', screen.width + 'x' + screen.height); +console.log('可用区域:', screen.availWidth + 'x' + screen.availHeight); +console.log('可用区域起点:', 'left=' + screen.availLeft + ', top=' + screen.availTop); +console.log('颜色深度:', screen.colorDepth + '位'); +console.log('像素深度:', screen.pixelDepth + '位'); + +// 屏幕方向检测 +if ('orientation' in screen) { + console.log('当前方向:', screen.orientation.type); + console.log('角度:', screen.orientation.angle); + + // 监听方向变化 + screen.orientation.addEventListener('change', () => { + console.log('方向变为:', screen.orientation.type); + }); +} + +// 响应式设计应用 +function checkScreenSize() { + if (screen.width < 768) { + console.log('小屏幕设备(手机)'); + } else if (screen.width < 1024) { + console.log('中等屏幕设备(平板)'); + } else { + console.log('大屏幕设备(桌面)'); + } +} + +// 检测是否高DPI屏幕(Retina) +const isRetina = window.devicePixelRatio > 1; +console.log('设备像素比:', window.devicePixelRatio); +console.log('是否高DPI:', isRetina); +``` + +--- + +## 📜 history 对象 + +### 知识点 +1. **作用**:操作浏览器会话历史 +2. **属性**: + - `length`:历史记录栈中的URL数量 + - `state`:当前历史记录状态对象 +3. **方法**: + - `back()`:后退到上一个页面 + - `forward()`:前进到下一个页面 + - `go(n)`:前进或后退n个页面 + - `pushState(state, title, url)`:添加历史记录 + - `replaceState(state, title, url)`:替换当前历史记录 + +### 示例 +```javascript +// 获取历史记录信息 +console.log('历史记录数量:', history.length); +console.log('当前状态:', history.state); + +// 基本导航 +// 后退一页(等价于点击后退按钮) +history.back(); + +// 前进一页(等价于点击前进按钮) +history.forward(); + +// 前进/后退多页 +history.go(-2); // 后退2页 +history.go(1); // 前进1页 +history.go(0); // 刷新当前页 + +// HTML5 History API +// 1. pushState - 添加新历史记录(不会加载页面) +const state1 = { page: 'home', data: { title: '首页' } }; +history.pushState(state1, '首页', '/home'); + +const state2 = { page: 'about', data: { title: '关于我们' } }; +history.pushState(state2, '关于我们', '/about'); + +// 2. replaceState - 替换当前历史记录 +const state3 = { page: 'contact', data: { title: '联系我们' } }; +history.replaceState(state3, '联系我们', '/contact'); + +// 监听popstate事件(用户点击前进/后退按钮时触发) +window.addEventListener('popstate', (event) => { + console.log('位置变化:', event.state); + console.log('当前URL:', location.href); + + // 根据state更新页面内容 + if (event.state) { + updateContent(event.state); + } +}); + +// 监听hashchange事件(hash变化时) +window.addEventListener('hashchange', () => { + console.log('Hash变为:', location.hash); +}); + +// 单页应用(SPA)路由示例 +function navigateTo(page, stateData) { + const state = { page, data: stateData }; + const title = stateData?.title || page; + const url = `/${page}`; + + history.pushState(state, title, url); + renderPage(page, stateData); +} + +function updateContent(state) { + switch(state.page) { + case 'home': + document.title = '首页 - 我的网站'; + document.getElementById('content').innerHTML = '

欢迎来到首页

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

关于我们

公司简介...

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

联系我们

联系方式...

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

第一题

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

第二题

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

第一题

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

第二题

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

请选择课程

+
+ c语言 + 机械制图 + 单片机 + 自动控制 + 传感器 + 高等数学
+ 计算机基础 + Oracle数据库 + 商务英语 + plc设计基础 +
+ + + +``` +``` +

电影《变相怪杰》的主演是谁?

+ 布拉德-皮特 + 亚当-桑德勒 + 金-盖瑞 + 杰夫-丹尼尔斯 +
+ + + +``` +``` + + 看电影 + 听音乐 + 演奏乐器 + 打篮球 + 看书 + 上网 +
+ + + + + + +``` +``` + +

选择城市:

+ + + + +``` \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251212.md" "b/\345\205\250\344\277\212\346\236\227/20251212.md" new file mode 100644 index 0000000000000000000000000000000000000000..5d9df0ca46133ac904efb32701a66f81c3563416 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251212.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/\345\205\250\344\277\212\346\236\227/20251215.md" "b/\345\205\250\344\277\212\346\236\227/20251215.md" new file mode 100644 index 0000000000000000000000000000000000000000..48a9745e3c7e8e526fd5f798e391c3be812c4290 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251215.md" @@ -0,0 +1,7 @@ +## 笔记 + +什么都没有...... + +## 作业 + +什么都没有...... \ No newline at end of file diff --git "a/\345\205\250\344\277\212\346\236\227/20251217.md" "b/\345\205\250\344\277\212\346\236\227/20251217.md" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/\345\205\250\344\277\212\346\236\227/20251218.md" "b/\345\205\250\344\277\212\346\236\227/20251218.md" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/\345\205\250\344\277\212\346\236\227/20251219js\345\272\223.md" "b/\345\205\250\344\277\212\346\236\227/20251219js\345\272\223.md" new file mode 100644 index 0000000000000000000000000000000000000000..b83e5043b76cbf84e970134debec121f69fb26e5 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251219js\345\272\223.md" @@ -0,0 +1,129 @@ +## 笔记 + +### 数组核心属性 + +| 属性名 | 说明 | 示例 | +| ----------------- | --------------------------------------------------- | ------------------------------------------------------ | +| `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) {}` | + +### 二、数组方法分类基础版本(是否修改原数组) + +#### 2.1 会修改原数组的方法 + +这类方法直接操作原数组,执行后原数组的内容 / 结构会发生变化。 + +| 方法名 | 功能 | 示例 | +| -------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `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]` | + +#### 2.2 不修改原数组的方法 + +这类方法不会改变原数组,而是返回新数组(或其他类型值),原数组保持原样。 + +##### (1)返回新数组的方法 + +| 方法名 | 功能 | 示例 | +| -------------------------- | ---------------------------------------------- | ------------------------------------------------------------ | +| `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]` | + +##### (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()) {} // 原数组不变` | + +我已为你优化表格中「完整语法(标注必选 / 可选参数)」和「参数说明」字段的排版,通过换行让内容更易读,同时保留原有的逻辑和格式: + +### 三、数组方法分类完整版本(是否修改原数组) + +#### 3.1修改原数组的方法 + +这类方法直接操作原数组,执行后原数组的内容 / 结构会发生变化,返回值标注在说明中。 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| -------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `push()` | 向数组末尾添加 1 + 元素,返回新长度 | `array.push(...items)`
✅ `items`:要添加的元素(1 个或多个) | `items`:
- 必选
- 任意类型的元素,数量不限 | `const arr = [1,2]; arr.push(3,4); // arr变为[1,2,3,4],返回4` | +| `pop()` | 删除数组最后一个元素,返回被删除的元素 | `array.pop()`
无参数 | 无 | `const arr = [1,2,3]; arr.pop(); // arr变为[1,2],返回3` | +| `unshift()` | 向数组开头添加 1 + 元素,返回新长度 | `array.unshift(...items)`
✅ `items`:要添加的元素(1 个或多个) | `items`:
- 必选
- 任意类型的元素,数量不限 | `const arr = [2,3]; arr.unshift(1); // arr变为[1,2,3],返回3` | +| `shift()` | 删除数组第一个元素,返回被删除的元素 | `array.shift()`
无参数 | 无 | `const arr = [1,2,3]; arr.shift(); // arr变为[2,3],返回1` | +| `splice()` | 增 / 删 / 改数组元素,返回被删除的元素数组 | `array.splice(start, deleteCount, ...items)`
✅ `start`:起始索引
❓ `deleteCount`:删除数量(默认删到末尾)
❓ `items`:要添加的元素(可选) | - `start`:
必选,整数,指定操作起始位置(负数表示倒数)
- `deleteCount`:
可选,非负整数,要删除的元素数量(0 则不删除)
- `items`:
可选,要插入到数组中的元素 | `const arr = [1,2,3]; arr.splice(1,1,4); // arr变为[1,4,3],返回[2]` | +| `sort()` | 排序数组元素(默认按字符串 Unicode 码点),返回排序后的数组 | `array.sort(compareFn)`
❓ `compareFn(a, b)`:排序对比函数(可选) | - `compareFn`:
可选,回调函数,接收两个参数:
✅ `a`:第一个用于比较的元素
✅ `b`:第二个用于比较的元素
返回值:<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()`
无参数 | 无 | `const arr = [1,2,3]; arr.reverse(); // arr变为[3,2,1],返回[3,2,1]` | +| `fill()` | 用指定值填充数组(覆盖指定范围),返回填充后的数组 | `array.fill(value, start, end)`
✅ `value`:填充值
❓ `start`:起始索引(默认 0)
❓ `end`:结束索引(默认数组长度,不含) | - `value`:
必选,任意类型,填充到数组的值
- `start`:
可选,整数,填充起始位置(负数表示倒数)
- `end`:
可选,整数,填充结束位置(不含) | `const arr = [1,2,3]; arr.fill(0,1,2); // arr变为[1,0,3],返回[1,0,3]` | +| `copyWithin()` | 复制数组指定范围元素到目标位置,返回修改后的数组 | `array.copyWithin(target, start, end)`
✅ `target`:目标位置索引
❓ `start`:复制起始索引(默认 0)
❓ `end`:复制结束索引(默认数组长度,不含) | - `target`:
必选,整数,复制元素要粘贴到的位置
- `start`:
可选,整数,复制起始位置(负数表示倒数)
- `end`:
可选,整数,复制结束位置(不含) | `const arr = [1,2,3,4]; arr.copyWithin(0,2); // arr变为[3,4,3,4],返回[3,4,3,4]` | + +#### 3.2不修改原数组的方法 + +这类方法不会改变原数组,返回新数组 / 非数组值,原数组保持原样。 + +##### (1)返回新数组的方法 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| ----------- | ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `slice()` | 截取数组指定范围元素,返回新数组(含头不含尾) | `array.slice(start, end)`
❓ `start`:起始索引(默认 0)
❓ `end`:结束索引(默认数组长度,不含) | - `start`:
可选,整数,截取起始位置(负数表示倒数)
- `end`:
可选,整数,截取结束位置(不含) | `const arr = [1,2,3]; const newArr = arr.slice(1); // newArr=[2,3],arr仍为[1,2,3]` | +| `concat()` | 拼接数组 / 值,返回新数组 | `array.concat(...arrays/values)`
❓ `arrays/values`:要拼接的数组或值(可选) | `arrays/values`:
- 可选
- 任意数量的数组或单个值(任意类型) | `const arr1 = [1,2]; const arr2 = arr1.concat(3,[4]); // arr2=[1,2,3,4],arr1不变` | +| `map()` | 遍历数组,对每个元素处理后返回新数组 | `array.map(callback(currentValue, index, array), thisArg)`
✅ `callback`:处理函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 map 的原数组(可选) | - `callback`:
必选,对每个元素的处理逻辑,返回处理后的值
- `thisArg`:
可选,指定 callback 内 this 的指向
- `currentValue`:
必选,数组中正在处理的当前元素
- `index`:
可选,当前元素在数组中的索引
- `array`:
可选,调用 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)`
✅ `callback`:筛选函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 filter 的原数组(可选) | - `callback`:
必选,返回布尔值(true 保留元素,false 过滤)
- `thisArg`:
可选,指定 callback 内 this 的指向
- `currentValue`:
必选,数组中正在处理的当前元素
- `index`:
可选,当前元素在数组中的索引
- `array`:
可选,调用 filter 的原数组 | `const arr = [1,2,3]; const newArr = arr.filter((item) => item>1); // newArr=[2,3],arr不变` | +| `flat()` | 扁平化数组,返回新数组 | `array.flat(depth)`
❓ `depth`:扁平化深度(默认 1) | `depth`:
- 可选
- 非负整数,指定扁平化的层级(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)`
✅ `callback`:处理函数(同 map)
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 flatMap 的原数组(可选) | - `callback`:
必选,返回单个值或数组(最终会被扁平化 1 层)
- 其他参数同 map | `const arr = [1,2]; const newArr = arr.flatMap(i => [i,i*2]); // newArr=[1,2,2,4]` | +| `with()` | 替换数组指定索引的元素,返回新数组(ES2023) | `array.with(index, value)`
✅ `index`:要替换的索引
✅ `value`:新值 | - `index`:
必选,整数,要替换的元素索引(负数表示倒数)
- `value`:
必选,任意类型,替换后的新值 | `const arr = [1,2]; const newArr = arr.with(0, 3); // newArr=[3,2],arr仍为[1,2]` | + +##### (2)返回非数组值的方法 + +| 方法名 | 功能 | 完整语法(标注必选 / 可选参数) | 参数说明 | 示例 | +| ------------------ | ------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| `forEach()` | 遍历数组(无返回值,仅执行回调) | `array.forEach(callback(currentValue, index, array), thisArg)`
✅ `callback`:遍历执行的函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 forEach 的原数组(可选) | - `callback`:
必选,无返回值(返回值会被忽略)
- `thisArg`:
可选,指定 callback 内 this 的指向
- `currentValue`:
必选,数组中正在处理的当前元素
- `index`:
可选,当前元素在数组中的索引
- `array`:
可选,调用 forEach 的原数组 | `arr.forEach((item, idx) => console.log(idx, item)); // 原数组不变` | +| `find()` | 返回第一个符合条件的元素(无则 undefined) | `array.find(callback(currentValue, index, array), thisArg)`
✅ `callback`:查找条件函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 find 的原数组(可选) | - `callback`:
必选,返回布尔值(true 则返回当前元素)
- 其他参数同 forEach | `const arr = [1,2,3]; arr.find(item => item>1); // 返回2,arr不变` | +| `findIndex()` | 返回第一个符合条件的元素索引(无则 - 1) | `array.findIndex(callback(currentValue, index, array), thisArg)`
✅ `callback`:查找条件函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 findIndex 的原数组(可选) | - `callback`:
必选,返回布尔值(true 则返回当前索引)
- 其他参数同 forEach | `const arr = [1,2,3]; arr.findIndex(item => item>1); // 返回1,arr不变` | +| `includes()` | 判断数组是否包含指定值,返回布尔值 | `array.includes(value, start)`
✅ `value`:要查找的值
❓ `start`:起始查找索引(默认 0) | - `value`:
必选,任意类型,要查找的目标值
- `start`:
可选,整数,查找起始位置(负数表示倒数) | `const arr = [1,2,3]; arr.includes(2); // 返回true,arr不变` | +| `indexOf()` | 返回指定值首次出现的索引(无则 - 1) | `array.indexOf(value, start)`
✅ `value`:要查找的值
❓ `start`:起始查找索引(默认 0) | - `value`:
必选,任意类型,要查找的目标值
- `start`:
可选,整数,查找起始位置(负数表示倒数) | `const arr = [1,2,3]; arr.indexOf(2); // 返回1,arr不变` | +| `lastIndexOf()` | 返回指定值最后出现的索引(无则 - 1) | `array.lastIndexOf(value, start)`
✅ `value`:要查找的值
❓ `start`:起始查找索引(默认数组长度 - 1) | - `value`:
必选,任意类型,要查找的目标值
- `start`:
可选,整数,反向查找的起始位置(负数表示倒数) | `const arr = [1,2,2,3]; arr.lastIndexOf(2); // 返回2,arr不变` | +| `every()` | 判断所有元素是否符合条件,返回布尔值 | `array.every(callback(currentValue, index, array), thisArg)`
✅ `callback`:判断函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 every 的原数组(可选) | - `callback`:
必选,返回布尔值(所有元素返回 true 则最终为 true)
- 其他参数同 forEach | `const arr = [1,2,3]; arr.every(item => item>0); // 返回true,arr不变` | +| `some()` | 判断是否有元素符合条件,返回布尔值 | `array.some(callback(currentValue, index, array), thisArg)`
✅ `callback`:判断函数
❓ `thisArg`:执行 callback 时的 this 指向(可选)
callback 参数:
✅ `currentValue`:当前处理的元素
❓ `index`:当前元素索引(可选)
❓ `array`:调用 some 的原数组(可选) | - `callback`:
必选,返回布尔值(任意元素返回 true 则最终为 true)
- 其他参数同 forEach | `const arr = [1,2,3]; arr.some(item => item>2); // 返回true,arr不变` | +| `reduce()` | 累加 / 归并数组,返回最终归并值 | `array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)`
✅ `callback`:归并函数
❓ `initialValue`:累加器初始值(可选)
callback 参数:
✅ `accumulator`:累加器(累计结果)
✅ `currentValue`:当前处理的元素
❓ `currentIndex`:当前元素索引(可选)
❓ `array`:调用 reduce 的原数组(可选) | - `callback`:
必选,返回累计结果(会作为下一次的 accumulator)
- `initialValue`:
可选,累加器初始值(无则用数组第一个元素)
- `accumulator`:
必选,累计的结果值
- `currentValue`:
必选,当前处理的元素
- `currentIndex`:
可选,当前元素索引
- `array`:
可选,调用 reduce 的原数组 | `const arr = [1,2,3]; arr.reduce((sum, item) => sum+item, 0); // 返回6,arr不变` | +| `reduceRight()` | 从右到左归并数组,返回最终归并值 | `array.reduceRight(callback(accumulator, currentValue, currentIndex, array), initialValue)`
✅ `callback`:归并函数(同 reduce)
❓ `initialValue`:累加器初始值(可选)
callback 参数:同 reduce | 同 reduce,仅遍历顺序为从右到左 | `const arr = [1,2,3]; arr.reduceRight((sum, item) => sum+item, 0); // 返回6,arr不变` | +| `join()` | 将数组转为字符串,返回拼接后的字符串 | `array.join(separator)`
❓ `separator`:分隔符(默认逗号) | `separator`:
- 可选
- 字符串,元素之间的分隔符(空字符串则无分隔) | `const arr = [1,2,3]; arr.join(','); // 返回"1,2,3",arr不变` | +| `toString()` | 将数组转为字符串(默认用逗号分隔) | `array.toString()`
无参数 | 无 | `const arr = [1,2,3]; arr.toString(); // 返回"1,2,3",arr不变` | +| `toLocaleString()` | 按本地化规则转为字符串 | `array.toLocaleString(locales, options)`
❓ `locales`:语言 / 地区代码(可选)
❓ `options`:格式化选项(可选) | - `locales`:
可选,如 "zh-CN"、"en-US"
- `options`:
可选,对象,配置格式化规则 | `const arr = [1234, new Date()]; arr.toLocaleString(); // 按本地格式返回字符串` | +| `entries()` | 返回迭代器(包含索引和值) | `array.entries()`
无参数 | 无 | `for (let [i, v] of arr.entries()) {} // 原数组不变` | +| `keys()` | 返回索引迭代器 | `array.keys()`
无参数 | 无 | `for (let i of arr.keys()) {} // 原数组不变` | +| `values()` | 返回值迭代器 | `array.values()`
无参数 | 无 | `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/\345\205\250\344\277\212\346\236\227/20251222.md" "b/\345\205\250\344\277\212\346\236\227/20251222.md" new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git "a/\345\205\250\344\277\212\346\236\227/20251224.md" "b/\345\205\250\344\277\212\346\236\227/20251224.md" new file mode 100644 index 0000000000000000000000000000000000000000..bf3d67d3b0e78aaef3053ac447467981542c842c --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251224.md" @@ -0,0 +1,442 @@ + + +## 笔记:罗老师手把手教你搓模态框 + +实现一个可控制显隐、遮挡底层操作、承载交互内容的模态框组件,核心是**遮罩层隔离底层操作** + **内容容器承载交互** + **类名控制显隐 / 内容切换**。 + +### 实现步骤(核心三步) + +#### 构建全屏遮罩层(隔离底层操作) + +##### 核心要求 + +创建 100vw*100vh (全屏)的半透明遮罩层,模态框显示时阻止用户操作底层的 “数据渲染 / 交互层”。 + +##### 具体实现 + +**HTML 结构**:创建遮罩层容器,作为模态框的外层容器: + +```html + + +``` + + + +**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 + + + + + + + 博客 + + + + + +
+
排名品牌市场份额
+ + + + + + + + + + + + + + + + +
请输入标题:
请输入内容摘要:
请输入作者:
+ + +
+ + +
+ +
+ + + +
+
+
+

博客列表

+
+
+ +
查找
+
新增
+
+
+ + + + + + + + + + + + +
序号标题内容摘要作者发布日期操作
+
+
+
+ + + + +``` +#### 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/\345\205\250\344\277\212\346\236\227/20251225.md" "b/\345\205\250\344\277\212\346\236\227/20251225.md" new file mode 100644 index 0000000000000000000000000000000000000000..22baed41599cdd50dbd6f5ed5a003eb453da8298 --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251225.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/\345\205\250\344\277\212\346\236\227/20251226.md" "b/\345\205\250\344\277\212\346\236\227/20251226.md" new file mode 100644 index 0000000000000000000000000000000000000000..25abf3ec3ae03e895b47276d48ad2381195c2abc --- /dev/null +++ "b/\345\205\250\344\277\212\346\236\227/20251226.md" @@ -0,0 +1,3 @@ +## 在前面 +##代码 +在前面