diff --git "a/\351\203\255\345\260\217\344\270\234/20251110-JS\345\237\272\347\241\200.md" "b/\351\203\255\345\260\217\344\270\234/20251110-JS\345\237\272\347\241\200.md" new file mode 100644 index 0000000000000000000000000000000000000000..44e35b486e46f1d386b9197e4d693955cc7114d0 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251110-JS\345\237\272\347\241\200.md" @@ -0,0 +1,41 @@ +# 笔记 +## 语言 +- JavaScript +- c# (高级语言) +- c/c++ +- java +- Python +- Swift +- Go +- Kotlin +- Rust (低级语言) +- TypeScript +- php +- 等等... +### 高级语言与低级语言的区别 + 高级语言可以比喻成人们更能理解的语言。 + 低级语言可以比喻成机械(硬件)的语言如:101101这种二进制语言。 +## JavaScript嵌入式和引用式 +```html + + + + + +``` +# 练习 +```html + + + + + +``` +示例图:!![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116160916770.png) \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251112-JS\345\237\272\347\241\200.md" "b/\351\203\255\345\260\217\344\270\234/20251112-JS\345\237\272\347\241\200.md" new file mode 100644 index 0000000000000000000000000000000000000000..59ff0b3d4947c4d5f0805d309275ce8188f8733b --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251112-JS\345\237\272\347\241\200.md" @@ -0,0 +1,105 @@ +# 笔记 +## 1.数据类型 + 1.数值型(number) + - 十进制 + - 十六进制 + - 八进制 + - 浮点型 + - 特殊值(Infinity)——无穷 + - 特殊值(NaN)——产生未知的结果或错误 + 2.字符串型(string) + 3.布尔型 + 3.特殊数据类型 + - 未定义值(undefined)——var a + - 空值(null) + 转义字符 +|转义字符|描述|转义字符|描述| +|--|--|--|--| +|\b|退格|\v|垂直制表符| +|\n|换行符|\r|Enter符| +|\t|水平字表符|两个反斜杠|反斜杠| +|\f|换页|\OOO|八进制整数,范围为000~777| +|\'|单引号|\xHHH|十六进制整数,范围为00~FF| +|\"|双引号|\uhhhh|十六进制编码的Unicode字符| + +## 2.常量和变量 + 1. + + +# 练习 +1. +``` + + +``` +2. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116161616691.png) + +3. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116162145598.png) +4. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116162026662.png) + +5. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116162044705.png) + +6. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116162059003.png) diff --git "a/\351\203\255\345\260\217\344\270\234/20251113-\345\276\252\347\216\257\350\257\255\345\217\245.md" "b/\351\203\255\345\260\217\344\270\234/20251113-\345\276\252\347\216\257\350\257\255\345\217\245.md" new file mode 100644 index 0000000000000000000000000000000000000000..4e800f94cf2c3f1f7382beaea91d8cb2c6a12e6e --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251113-\345\276\252\347\216\257\350\257\255\345\217\245.md" @@ -0,0 +1,90 @@ +# 作业 +1. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116164300040.png) +2. +``` + +
+ 请选择你的出生年月: + + +
+ + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116164613516.gif) +3. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116164424278.png) +4. +``` + + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116164438359.png) diff --git "a/\351\203\255\345\260\217\344\270\234/20251114-\346\265\201\347\250\213\346\216\247\345\210\266\350\257\255\345\217\245.md" "b/\351\203\255\345\260\217\344\270\234/20251114-\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..d09d49fe80317ec4f922a05a5dd59d186ece91b1 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251114-\346\265\201\347\250\213\346\216\247\345\210\266\350\257\255\345\217\245.md" @@ -0,0 +1,127 @@ +# 作业 +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251116165147037.png) +1. +``` + + +``` +2. +``` + + +``` +3. +``` + + +``` +4. +``` + + +``` +5. +``` + + +``` +6. +``` + + +``` +7. +``` + + +``` diff --git "a/\351\203\255\345\260\217\344\270\234/20251117-\345\207\275\346\225\260.md" "b/\351\203\255\345\260\217\344\270\234/20251117-\345\207\275\346\225\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..536dd6c7bb076893f30d815baf8cc2381ae8abd8 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251117-\345\207\275\346\225\260.md" @@ -0,0 +1,89 @@ +# 笔记 + +## 函数的定义 + +### 定义和调用 + +- 定义可指定形参 +- 调用的时候可任意指定实参,也可不指定 + +### 返回值 + +- 有return,则有返回值,而且通常不为undefined +- 无return,总是私下返回一个undefined + +## 流程控制 + +### 判断 + +- if(){} +- if(){}...else{} +- if(){}...else if(){}... +- if(){}...else if(){}...else +- switch(){case} + +### 循环 + +- for(let i = 0; i < 10; i++){} +- while(){} +- do{}...while{} + +# 练习示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123141752373.png) + +# 练习 + +## 训练1 +``` + +``` + +## 训练2 +``` + +``` + +## 训练3 +``` + function compare(sun1,sun2){ + if(sun1 > sun2){ + document.write('
较大的是'+sun1); + }else{ + document.write('
较大的是'+sun2); + } + } + compare(9,10); +``` + +## 训练4 +``` + function mincompare(sun1,sun2,sun3){ + let min = sun1; + if(min > sun2){ + min = sun2; + } + if(min > sun3){ + min = sun3; + } + document.write('
最小的是'+min); + + } + mincompare(16,12,17); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251119-\345\207\275\346\225\260\344\270\216\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251119-\345\207\275\346\225\260\344\270\216\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..9b33f8acfdc9297c5d565d25bb5dbc8c972f6e4d --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251119-\345\207\275\346\225\260\344\270\216\345\257\271\350\261\241.md" @@ -0,0 +1,217 @@ +# 笔记 + +## 函数 + +### 函数的嵌套 +``` + function a(){ + alert('123'); + } + function b(){ + a(); + } + b(); +``` +### 递归函数 +递归函数就是函数在自身的函数体内调用自身. +``` + function fn(num){ + if(num <= 1){ + return 1; + }else{ + return fn(num-1)*num; + } + } + alert('10!的结果为'+fn(10)); +``` +### 内置函数 +#### 内置函数分为两类: 数值处理函数和字符串处理函数 +``` + 1. parselnt()函数 ——> 讲首位为数字的字符串转换成'数字' + + let str1 = "123mn"; + document.write(parselnt(str1)); ——>123 +``` +``` + 2. parseFloat()函数 ——> 讲首位为数字的字符串转换成'浮点型数字' + + let str1 = "123.45mn"; + document.write(parseFloat(str1)); ——>123.45 +``` +``` + 3.isNaN()函数 ——> 用于检验某个值是否为NaN + + let num1 = 456; + let num2 = "456mn "; + document.write(isNaN(str1)); ——> false + document.write(isNaN(str2)); ——> true +``` +``` + 4.isFinite() ——> 用于检验一个数值是否有限 + + document.write(isFinite(567)); ——>trun + document.write(isFinite(567mn)); ——>false + document.write(isFinite(10/0)); ——>false +``` +### 字符串处理函数 +``` + 1.eval函数 ——>计算字符串表达式的值 + + document.write(eval("5+7")) ——>12 + eval("x=7;y=9;document.write(x*y)"); ——>63 +``` +``` + 2.encodeURL()函数 ——>用于URL字符串进行编码 + + encodeURL(url); ——>对URL字符串进行编码并输出 +``` +``` + 3.decodeURL()函数 ——>用于对已编码进行解码 + + document.write(decodeURL(url)); ——>对编码后的URL字符串进行解码并输出 +``` +### 匿名函数 +``` + 格式: + let 变量名 = function(参数1,参数2,...){ + 函数体 + } + + 使用Function()构造函数 + let sum = new Function("x","y","alert(x+y);"); + sum(100,200) +``` + +# 作业 + +## 练习示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123141228718.png) + +## 练习5 +``` + function price(score1,score2,score3){ + var consumption = score1 + score2 + score3; + return consumption; + } + function judgment(score1,score2,score3){ + var count = price(score1,score2,score3); + if(count >= 500){ + document.write('该用户可以享受优惠活动
'); + }else{ + document.write('该用户不享受优惠活动
'); + } + } + judgment(199,156,165); + +``` +## 练习6 +``` + function score(score1,score2,score3,score4){ + var totalScore = score1 + score2 + score3 + score4; + return totalScore; + } + function test(score1,score2,score3,score4){ + var testscore = score(score1,score2,score3,score4); + if(testscore >= 550){ + document.write('该学生成绩达到本科分数线
'); + }else{ + document.write('该学生成绩未达到本科分数线
'); + } + } + test(108,115,126,237); +``` +## 练习7 +``` + var logIn = function(user,pwd){ + if(user == 'mr' && pwd == 'mrsoft'){ + return '用户登入成功'; + }else{ + return '用户登入失败'; + } + } + document.write(logIn('mr','mrsoft')+'
'); +``` +## 练习8 +``` + let sum = function(){ + let j = 0; + for(let i = 1; i <= 1000; i++){ + if( i % 3 == 0 && i % 5 == 0){ + document.write(i+' '); + j++; + if(j % 7 == 0){ + document.write('
'); + } + } + } + } + sum(); +``` + +## 综合练习示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123141327060.gif) + +## 综合练习 +``` + //综合练习1 + function age(score){ + if( 0 <= score && score <= 6){ + return '童年'; + }else if(7 <= score && score <= 17){ + return '少年'; + }else if(18 <= score && score <= 40){ + return '青年'; + }else if(41 <= score && score <= 65){ + return '中年'; + }else if(score >= 66){ + return '老年'; + } + } + alert('20岁正处在'+age(20)+'时期'); + + //综合练习2 + function getMonthDays(year,month){ + return new Date(year,month,0).getDate(); + + } + // alert('2024年6月有'+getMonthDays(2024,6)+'天'); + + //综合练习3 + function table(gettr,gettd){ + const table = document.createElement('table'); + table.border = '1'; + table.cellSpacing = '0'; + for(let i = 0; i <= gettr; i++ ){ + const tr = document.createElement('tr'); + for(let j = 0; j <= gettd; j++){ + const td = document.createElement('td'); + tr.appendChild(td); + } + table.appendChild(tr); + } + document.body.appendChild(table); + } + table(5,6); +``` + +## 斐波那契数列示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123141346007.png) + + +## 斐波那契数列 + +``` + function fn(n){ + if(n == 1 || n == 2){ + return 1; + } + //初始化数组,包含前两项 + const sequence = [1,1]; + for(let i = 2;i < n; i++){ + const nextNumber = sequence[i - 1] + sequence[i - 2]; + sequence.push(nextNumber); + } + return sequence; + } + document.write(fn(8)); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251120-\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251120-\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..649e7814866aa8c03f5702f754039ff42ecdf1fe --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251120-\345\257\271\350\261\241.md" @@ -0,0 +1,146 @@ +# 笔记 +## 对象的概念 + - 对象可以理解一个容器,一个放属性和方法的容器 +``` + 创建对象的语法 + var 对象名 = { 属性1,属性2,属性3,属性4,属性5,......} +``` +## 操作对象 +``` + 访问属性:有俩种方式一种是“对象名.属性名”,一种是“对象名.[属性名]”. + + 添加属性:对象名.属性 = “值” + + 删除属性:delete 对象名.属性 + + 添加方法:方法名:function(){} +``` +## 遍历对象 +``` + for(let key in 对象名){ + + } +``` +## 内部对象 +``` + Math对象 + + Date对象 + + Event对象 +``` + +# 作业 + +## 练习 + +### 练习示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123140210003.gif) + +### 练习1 +``` + let startDate_1 = new Date(2023,4,1); + let endDate_1 = new Date(2023,5,1); + let result_1 = endDate_1 - startDate_1; + let convert_1 = result_1 /(1000*60*60); + document.write("间隔"+convert_1+"小时
"); +``` +### 练习2 +``` + let examDate = new Date(2023,5,7); + let now = new Date(); + let result_2 = examDate - now; + let convert_2 =Math.ceil(result_2/(1000*60*60*24)); + document.write("距离2023年高考还有"+convert_2+"天
"); +``` +### 练习3 +``` + //训练3 + // 1. 获取页面的 body 元素,我们将在整个页面监听点击 + const pageBody = document.body; + + // 2. 为 body 添加 'mousedown' 事件监听器 + pageBody.addEventListener('mousedown', function(event) { + // 3. 定义一个变量来存储按键名称 + let buttonName; + + // 4. 根据 event.button 的值判断按键 + switch (event.button) { + case 0: + buttonName = "左键"; + break; + case 1: + buttonName = "滚轮键(中键)"; + break; + case 2: + buttonName = "右键"; + break; + default: + buttonName = "未知按键"; + } + + // 5. 弹出对话框显示结果 + alert(`你刚刚单击了鼠标${buttonName}。\n event.button 的值为: ${event.button}`); + }); +``` +### 综合示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251123140502129.gif) + +### 综合练习 + + +``` + +
+

请输入要生成随机数的位数:

+ + +
+ + +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251121-\345\206\205\351\203\250\345\257\271\350\261\241\344\270\216\346\225\260\347\273\204.md" "b/\351\203\255\345\260\217\344\270\234/20251121-\345\206\205\351\203\250\345\257\271\350\261\241\344\270\216\346\225\260\347\273\204.md" new file mode 100644 index 0000000000000000000000000000000000000000..0925788b2d54a58199a760c7cf175e6482b46473 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251121-\345\206\205\351\203\250\345\257\271\350\261\241\344\270\216\346\225\260\347\273\204.md" @@ -0,0 +1,195 @@ +# 笔记 + +## 内部对象 + +### Math对象 + +#### 常用常量 + +- `Math.PI`:圆周率(约 3.14159) + +#### 数值运算方法 + +- `Math.abs(x)`:返回 x 的绝对值 + ```javascript + console.log(Math.abs(-5)); // 5 + ``` + +- `Math.ceil(x)`:向上取整(进一法) + ```javascript + console.log(Math.ceil(3.2)); // 4 + ``` + +- `Math.floor(x)`:向下取整(去尾法) + ```javascript + console.log(Math.floor(3.9)); // 3 + ``` + +- `Math.round(x)`:四舍五入取整 + ```javascript + console.log(Math.round(3.5)); // 4 + console.log(Math.round(3.4)); // 3 + `` + +- `Math.max(...values)`:返回一组数中的最大值 + ```javascript + console.log(Math.max(1, 5, 3)); // 5 + ``` + +- `Math.min(...values)`:返回一组数中的最小值 + ```javascript + console.log(Math.min(1, 5, 3)); // 1 + ``` + +- `Math.pow(x, y)`:返回 x 的 y 次幂 + ```javascript + console.log(Math.pow(2, 3)); // 8 + ``` + +- `Math.sqrt(x)`:返回 x 的平方根 + ```javascript + console.log(Math.sqrt(16)); // 4 + ``` + +- `Math.random()`:返回 0 到 1 之间的随机数(包含 0,不包含 1) + ```javascript + console.log(Math.random()); // 例如:0.456789 + // 生成1到10的随机整数 + console.log(Math.floor(Math.random() * 10) + 1); + ``` +### Date对象 + +Date 用于处理日期和时间,需要通过`new Date()`实例化使用。 + +#### 实例化方式 + +```javascript +new Date(); // 当前时间 +new Date(timestamp); // 时间戳(毫秒) +new Date(year, month, day, hours, minutes, seconds, milliseconds); // 指定日期 +new Date(dateString); // 日期字符串,如"2025-11-21" +``` + +#### 常用获取方法 + +- `getFullYear()`:获取年份(4 位数) + javascript + ```javascript + const now = new Date(); + console.log(now.getFullYear()); // 2025 + ``` + +- `getMonth()`:获取月份(0-11,0 代表 1 月) + javascript + ```javascript + console.log(now.getMonth() + 1); // 11(当前月份) + ``` + +- `getDate()`:获取日期(1- + javascript + ```javascript + console.log(now.getDate()); // 21 + ``` + +- `getHours()`:获取小时(0) + +- `getMinutes()`:获取分钟(0-59) + +- `getSeconds()`:获取秒数(0-59) + +- `getMilliseconds()`:获取毫秒数(0-999) + +- `getDay()`:获取星期几(0-6,0 代表周日) + javascript + ```javascript + console.log(now.getDay()); // 5(周五) + ``` + + + +- `getTime()`:获取时间戳(从 1970-01-01:00:00 UTC 到当前时间的毫秒数) + javascript + ```javascript + console.log(now.getTime()); + ``` + + + +#### 设置方法 + +- `setFullYear(year)`:设置年份 +- `setMonth(month)`:设置月份(0-11) +- `setDate(date)`:设置日期 +- `setHours(hours)`:设置小时 +- `setMinutes(minutes)`:设置分钟 +- `setSeconds(seconds)`:设置秒数 +- `setTime(timestamp)`:通过时间戳设置日期 + +#### 格式化方法 + +- `toString()`:转为字符串(如 "Fri Nov 21 2025 10:00:00 GMT+0800 (中国标准时间)") +- `toLocaleString()`:转为本地格式字符串(如 "2025/11/21 10:00:00") +- `toLocaleDateString()`:仅日期的本地格式(如 "2025/11/21") +- `toLocaleTimeString()`:仅时间的本地格式(如 "10:00:00") + +### Event对象 + +#### 常用属性 + +- `type`:事件类型(如 "click"、"keydown") +- `target`:触发事件的目标元素(事件源) +- `currentTarget`:绑定事件的元素(事件处理函数所属的元素) +- `clientX/clientY`:鼠标相对于视口的坐标(鼠标事件) +- `key`:按下的键盘按键值(键盘事件,如 "Enter"、"a") + +#### 常用方法 + +- `preventDefault()`:阻止事件的默认行为(如阻止 a 标签跳转、表单提交) + ```javascript + document.querySelector('a').addEventListener('click', (e) => { + e.preventDefault(); // 阻止链接跳转 + }); + ``` + +- `stopPropagation()`:阻止事件冒泡(阻止事件向父元素传播) + ```javascript + document.querySelector('.child').addEventListener('click', (e) => { + e.stopPropagation(); // 阻止事件冒泡到父元素 + console.log('子元素被点击'); + }); + ``` + +- `stopImmediatePropagation()`:阻止事件冒泡,且阻止当前元素后续的事件处理函数执行 + ```javascript + const btn = document.querySelector('button'); + btn.addEventListener('click', (e) => { + e.stopImmediatePropagation(); + console.log('第一个处理函数'); + }); + btn.addEventListener('click', () => { + console.log('第二个处理函数'); // 不会执行 + }); + ``` + +## 数组 + +### 定义数组 + +1. 定义空数组: arrayObject = new Array(); + +2. 指定数组长度: arrayObject = new Array(size); + +3. 指定数组元素: arrayObject = new Array(element1,element2,element3,...); + +4. 直接定义数组(最常用的): arraryObject = [element1,element2,element3,...]; + +### 数组的增删改查 + +1. push(a,b,c...); + +2. pop(); + +3. splice() + +4. + diff --git "a/\351\203\255\345\260\217\344\270\234/20251124-String\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251124-String\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..59b2e72541db158914d0844159a41cdc3af06930 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251124-String\345\257\271\350\261\241.md" @@ -0,0 +1,106 @@ +# 笔记 + +## String对象 + +### String对象的创建 +``` +var newstr = new String(StringText); +``` +### 格式化字符串 + +|方法|说明| +|--|--| +|anchor|创建HTML锚| +|big|使用大号字体显示字符串| +|small|使用小号字体显示字符串| +|fontsize|使用指定的字体显示大小| +|bold|使用粗体显示字符串| +|italics|使用斜体显示字符串| + +# 练习 +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130162000946.png) + +## 练习1 +```js + //训练1——获取当前星期 + let weekDays = ['周日','周一','周二','周三','周四','周五','周六']; + let today = new Date(); + let year = today.getFullYear(); + const month = today.getMonth() + 1; + const date = today.getDate(); + let currentWeekDay = weekDays[today.getDay()]; + document.write(`今天是${year}年${month}月${date}日
当前星期:${currentWeekDay}
`); +``` +## 练习2 +```js + //训练2——获取最大值 + let arr1 = [5,7,6,3,9,2]; + Array.prototype.maxArray = function(){ + // 1. 处理空数组(避免无意义计算,返回 undefined 或抛出提示) + if(this.length === 0){ + return undefined; + } + // 2. 初始化最大值为数组第一个元素 + let max = this[0]; + for(let i = 1; i < this.length; i++){ + // 3. 遍历数组,对比更新最大值 + if(typeof this[i] === 'number' && !isNaN(this[i])){ + // 只对比数字类型(避免非数字干扰) + max = this[i] > max ? this[i] : max; + } + } + return max; + } + + document.write(`最大值为${arr1.maxArray()}
`) +``` +## 练习3 +```js + //训练3——获取指定元素 + let arr2 = [1,2,3,4,5,6] + document.write(`数组获取到的值是${arr2}
`) + document.write(`数组获取到指定的值是${arr2.slice(1,5)}
`) +``` +## 综合练习1 +```js + //综合练习1 + let site = ['长春','昌图西','铁岭西','沈阳北','绥中北','北京']; + document.write("途径站:"+site.join(' ')+"
"); + document.write("反向站:"+site.reverse().join(' ')+'
'); +``` +## 综合练习2 +```js + + //综合练习2 + let arr = new Map([ + ["vivo", 19.2], + ["OPPO", 17.5], + ["小米", 13.9], + ["iPhone", 18], + ["荣耀", 16.7] + ]); + let sortedArr = Array.from(arr).sort((a, b) => { + return b[1] - a[1]; + }); + document.write(''); + document.write(''); + let rank = 1; + for (let [brand, share] of sortedArr) { + document.write(''); + document.write(``); + document.write(``); + document.write(``); + document.write(''); + rank++; + } + document.write('
排名品牌市场份额
${rank}${brand}${share}%
'); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/\351\203\255\345\260\217\344\270\234/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 0000000000000000000000000000000000000000..aba9d96ce9e67ed172ff757d40ae1144e653e00f --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251126-\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,140 @@ +# 笔记 +## 正则表达式 + 正则表达式描述了一种字符串的匹配模式,即通过使用一系列普通字符串和特殊字符串来构建能够明确描述文本字符串的匹配模式,可以用来检查一个字符串是否含有某个字符串、将匹配的字符串替换或者从某个字符串中去除某个符合条件的字符串等。 + +## 正则表达式基本结构 +```js + /匹配对象的模式/ +``` + +## 正则表达式的作用 + + 1. 测试字符串的某个模式 + 2. 替换文本 + 3. 根据模式匹配 + +## 正则表达式语法 +书130~132 + +# 练习 +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161829196.gif) +## 练习1 + +```js + //训练1 + let books = new Array("《雪山飞狐》", "《连城诀》", "《天龙八部》", "《射雕英雄传》", "《鹿鼎记》", "《笑傲江湖》", "《书剑恩仇录》", "《神雕侠侣》", "《倚天屠龙记》", "《碧血剑》"); + let fourBookName = ""; + for (let i = 0; i < books.length - 1; i++) { + if (books[i].length === 6) { + fourBookName += books[i] + ""; + } + } + document.write("4字小说:" + fourBookName + '
'); + +``` +## 练习2 +```js + //训练2 + let mobileNumber = new Array("1330431****", "1567766****", "1304316****", "1526567****", "139****0431"); + let number0431 = ""; + for (let i = 0; i < mobileNumber.length; i++) { + if (mobileNumber[i].includes("0431")) { + number0431 += mobileNumber[i] + "、"; + } + } + document.write(`电话号包含0431有:${number0431}
`); + +``` +## 练习3 +```js + //训练3 + let qqEmail = ["4006****66@qq.com", "1234****45@qq.com", "4567****89@qq.com"]; + let getEmail = ""; + for (let i = 0; i < qqEmail.length; i++) { + if (qqEmail[i].substr(0, 4) == "4006") { + getEmail += qqEmail[i] + " "; + } + } + document.write(`获取到的QQ邮箱:${getEmail}
`); + + +``` +## 综合练习1 +```js + //综合练习1 + function isEmailValid(email) { + // 判断是否包含@,且@的位置不在开头和结尾 + let atIndex = email.indexOf('@'); + if (atIndex === -1 || atIndex === 0 || atIndex === email.length - 1) { + return false; + } + + // 判断@之后是否包含.,且.不在@的下一位、不在结尾 + let dotIndexAfterAt = email.indexOf('.', atIndex + 1); + if (dotIndexAfterAt === -1 || dotIndexAfterAt === atIndex + 1 || dotIndexAfterAt === email.length - 1) { + return false; + } + + return true; + } + + // 测试abc@sina.com + let testEmail = "abc@sina.com"; + if (isEmailValid(testEmail) === true) { + // alert(`注册邮箱符合要求`); + } else { + alert(`注册邮箱不符合要求`); + } +``` +## 综合练习2 +```js + //综合练习2 + function randomNum(Num) { + //定义需要的字符 + let Number = "0123456789ABCDEFG"; + // 用split拆分为字符数 组 + let splitNumber = Number.split(""); + let result = ""; + for (let i = 0; i < Num; i++) { + let randomIndex = Math.floor(Math.random() * splitNumber.length) + result += splitNumber[randomIndex]; + } + alert(result); + } + randomNum(6); +``` +## 综合练习3 +```js + //综合练习3 + function formatNumber(num) { + //方法1 + // const numStr = num.toString(); + // let reversed = numStr.split('').reverse().join(''); // 反转字符串:"66952631" + // let result = []; + + // // 每3位分割 + // for (let i = 0; i < reversed.length; i += 3) { + // result.push(reversed.slice(i, i + 3)); // ["669", "526", "31"] + // } + + // // 拼接逗号后反转回原顺序 + // return result.join(',').split('').reverse().join(''); // "13,625,966" + + //方法2 + // return new Intl.NumberFormat('en-US').format(num); + + //方法3 + let newStr = ""; + let numStr = num.toString(); + let d = 0; + for (let i = numStr.length - 1; i >= 0; i--) { + newStr = numStr[i] + newStr; + d++ + if (i != 0 && d % 3 == 0){ + newStr = "," + newStr; + } + } + return newStr; + } + document.write(`效果:${formatNumber(13625966)}`); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" "b/\351\203\255\345\260\217\344\270\234/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..3deaf283e8a2085432aa1b92b45e6a448cb1b739 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251127-\345\274\202\345\270\270\345\244\204\347\220\206.md" @@ -0,0 +1,132 @@ +# 笔记 + +## 异常处理 + +### 异常处理用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: +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161355398.gif) +```js + try{ + let str = "我喜欢JavaScript"; + let sub1 = str.substr(a,5); + }catch(error){ + alert(`对象不支持此方法`); + }finally{ + + } +``` +## 练习2: +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161355398.gif) +```js + try{ + let str = "我喜欢JavaScript"; + let sub1 = str.substr(a,5); + }catch(error){ + alert(`错误类型:${error.name}\n错误信息:${error.message}`); + }finally{ + + } +``` +## 综合练习1 +实例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161144674.gif) +```js +let arrNum = ["A","B","C","D","E"]; + const btn = document.getElementById("btn"); + + btn.onclick = function(e){ + e.preventDefault(); + let num = Number(document.getElementById("numInput").value.trim()); + if(!Number.isInteger(num) || isNaN(num) || num < 1 || num > 5){ + alert("输入1~5的数字"); + return ; + } + document.getElementById("resInput").value = arrNum[num - 1]; + } +``` +## 综合练习2 +实例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161459508.gif) +```js +let testBtn = document.getElementById("testBtn"); + testBtn.onclick = function(){ + try{ + let userName = document.getElementById("userName").value.trim(); + let passWord = document.getElementById("passWord").value.trim(); + + if(!passWord || !userName ){ + alert(`用户名和密码不能为空`); + } + let userNamereg = /^[a-zA-Z0-9_]{3,10}$/; + if(!userNamereg.test(userName)){ + throw new Error("用户名不符合要求(3-10位,仅字母/数字/下划线)"); + } + if(passWord == "123" && userName == "123"){ + alert(`登入成功`); + }else{ + alert(`用户名或密码错误`); + } + + }catch(error){ + alert(error.message); + } + } +``` +## 回车事件 +实例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130161555006.gif) +```js +let enterInput = document.getElementById("enter"); + enterInput.addEventListener("keydown",function(e){ + if(e.keyCode === 13){ + e.preventDefault(); + let inputValue = this.value.trim(); + if(!inputValue){ + alert(`输入内容不能为空!`); + return; + } + alert(`输入的内容是${inputValue}`); + + this.value = ""; + } + }); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\351\203\255\345\260\217\344\270\234/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..b2a3af543f1219c6f4049edf78b61b58225f630c --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251128-\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,161 @@ +# 笔记 + +## 事件事件 + +### 概述 + + 1. 事件处理过程分为3步:1、发生事件;2、启动事件处理方程;3、事件处理程序做出反应。 + 2. 通常,事件处理器的命名原则是在事件名称加前缀欧尼,例如对于click事件,其处理器为onclick。 + +### 常用事件 + + 1. onclick——单击事件 + +### DOM事件模型——取消事件传递和默认处理 +```js +//取消游览器的事件传递 +function someHandle(event){ + event.stopPropagation(); +} +//取消事件传递后的默认处理 +function someHandle(event){ + event.preventDefault(); +} +``` + +# 练习 +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160119095.gif) +## 练习1 +```js +// 训练1 +
+ + function visible(cursor, i) { + if (i == 0) { + cursor.style.border = "none" + } else { + cursor.style.border = "5px solid black" + } + } +``` +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160250823.gif) +## 练习2 +```js +// 训练2 + function choose(event) { + if (event.key == "C") { + alert(`正确`); + } else { + alert(`错误`); + } + } + document.onkeydown = choose; + +

中国的“国球”是( )

+
+
A.篮球
+
B.排球
+
C.乒乓球
+
D.羽毛球
+
+``` +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160531570.gif) +## 练习3 +```js +// 训练3 + function getTime() { + let now = new Date(); + alert(now); + } +``` +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160531570.gif) +## 练习4 +```js +// 训练4 + function getWindowSize() { + let width = window.innerWidth; + let height = window.innerHeight; + alert(`窗口宽度:${width}px\n窗口高度:${height}px`) + } +``` +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160649395.gif) +## 练习5 +```js +// 训练5 + function color(event) { + let obj = event.target; + obj.style.background = "red"; + obj.onblur = function () { + obj.style.background = "blue"; + }; + } +``` +## 示例图: +![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251130160752359.gif) +## 练习6和训练7 +```js +// 训练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; + } + +
+ + + + + + + + + +
+
+``` + + diff --git "a/\351\203\255\345\260\217\344\270\234/20251201-\344\272\213\344\273\266\345\244\204\347\220\206.md" "b/\351\203\255\345\260\217\344\270\234/20251201-\344\272\213\344\273\266\345\244\204\347\220\206.md" new file mode 100644 index 0000000000000000000000000000000000000000..dbdc5f8b6502c79f6cba2280105a3704d44164d7 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251201-\344\272\213\344\273\266\345\244\204\347\220\206.md" @@ -0,0 +1,431 @@ +# 笔记 +## 一、事件处理核心概念 +### 1. 事件与事件流 +- **事件**:浏览器或用户在页面上触发的行为(如点击、鼠标移动、键盘输入、页面加载完成),是 JS 实现交互的核心。 +- **事件流**:事件触发后在 DOM 树中的传播过程,分为三个阶段: + 1. **捕获阶段(Capture Phase)**:事件从 `window` 向下传播到目标元素; + 2. **目标阶段(Target Phase)**:事件到达触发的目标元素; + 3. **冒泡阶段(Bubble Phase)**:事件从目标元素向上传播回 `window`。 + +### 2. 事件类型分类 +| 类别 | 常见事件 | 说明 | +|------|----------|------| +| 鼠标事件 | `click`、`dblclick`、`mouseover`、`mouseout`、`mousemove`、`mousedown`、`mouseup` | 鼠标相关操作 | +| 键盘事件 | `keydown`、`keyup`、`keypress`(已废弃) | 键盘按键操作 | +| 表单事件 | `submit`、`change`、`input`、`focus`、`blur` | 表单元素交互 | +| 文档/窗口事件 | `DOMContentLoaded`、`load`、`resize`、`scroll` | 文档加载、窗口尺寸变化/滚动 | +| 触摸事件 | `touchstart`、`touchmove`、`touchend` | 移动端触摸操作 | + +## 二、事件绑定方式(优先级从低到高) +### 1. HTML 内联绑定(不推荐) +直接在 HTML 标签中通过 `onxxx` 属性绑定,耦合度高,不利于维护,且存在 XSS 风险。 +```html + + + +``` + +### 2. DOM 元素属性绑定 +通过 JS 给元素的 `onxxx` 属性赋值,缺点是一个事件只能绑定一个处理函数(覆盖式)。 +```javascript +const btn = document.querySelector("button"); + +// 绑定事件 +btn.onclick = function() { + console.log("点击事件1"); +}; + +// 覆盖原有事件 +btn.onclick = function() { + console.log("点击事件2"); +}; + +// 移除事件 +btn.onclick = null; +``` + +### 3. addEventListener(推荐) +标准事件绑定方式,支持绑定多个事件处理函数,可控制事件传播阶段。 +#### 语法 +```javascript +element.addEventListener(eventName, handler, options/capture); +``` +- `eventName`:事件名(不含 `on`,如 `click` 而非 `onclick`); +- `handler`:事件处理函数(可传普通函数/箭头函数,注意 `this` 指向); +- `options/capture`:可选,布尔值(`true` 表示捕获阶段触发,`false` 冒泡阶段,默认 `false`)或配置对象: + - `capture`:同上; + - `once`:布尔值,事件触发一次后自动移除; + - `passive`:布尔值,声明事件处理函数不会调用 `preventDefault()`(优化移动端滚动性能)。 + +#### 示例 +```javascript +const btn = document.querySelector("button"); + +// 绑定多个事件处理函数 +function handleClick1() { + console.log("点击事件1", this); // this 指向触发事件的元素 +} +const handleClick2 = () => { + console.log("点击事件2", this); // 箭头函数 this 指向外层作用域(如 window) +}; + +btn.addEventListener("click", handleClick1); +btn.addEventListener("click", handleClick2, { once: true }); // 仅触发一次 + +// 移除事件(必须传绑定的同一个函数引用) +btn.removeEventListener("click", handleClick1); +``` + +### 三种方式对比 +| 绑定方式 | 优点 | 缺点 | +|----------|------|------| +| HTML 内联 | 简单直观 | 耦合高、可维护性差、易 XSS | +| DOM 属性 | 比内联解耦 | 只能绑定一个处理函数、无阶段控制 | +| addEventListener | 支持多函数、阶段控制、配置灵活 | 语法稍复杂、移除需相同函数引用 | + +## 三、事件对象(Event) +事件触发时,处理函数会自动接收一个 `Event` 对象,包含事件的详细信息和核心方法。 +### 1. 核心属性 +| 属性 | 说明 | +|------|------| +| `e.target` | 触发事件的**原始目标元素**(事件流中的目标节点) | +| `e.currentTarget` | 绑定事件的**当前元素**(即 `addEventListener` 的调用者) | +| `e.type` | 事件类型(如 `click`、`keydown`) | +| `e.clientX / e.clientY` | 鼠标相对于视口的坐标(鼠标事件) | +| `e.key` | 按下的键盘按键(键盘事件,如 `Enter`、`a`) | +| `e.code` | 键盘按键的物理编码(如 `KeyA`、`Enter`) | +| `e.preventDefault` | 方法:阻止事件的默认行为(如表单提交、链接跳转) | +| `e.stopPropagation` | 方法:阻止事件继续传播(捕获/冒泡) | +| `e.stopImmediatePropagation` | 方法:阻止事件传播 + 阻止当前元素后续事件处理函数执行 | + +### 2. 常用示例 +```javascript +// 阻止默认行为 +const link = document.querySelector("a"); +link.addEventListener("click", (e) => { + e.preventDefault(); // 阻止链接跳转 + console.log("链接被点击,不跳转"); +}); + +// 区分 target 和 currentTarget(事件委托场景) +document.addEventListener("click", (e) => { + console.log("触发元素:", e.target); // 点击的具体元素(如按钮) + console.log("绑定元素:", e.currentTarget); // document +}); + +// 键盘事件 +document.addEventListener("keydown", (e) => { + if (e.key === "Escape") { + console.log("ESC 键被按下"); + } +}); + +// 阻止事件冒泡 +const parent = document.querySelector(".parent"); +const child = document.querySelector(".child"); + +parent.addEventListener("click", () => console.log("父元素点击")); +child.addEventListener("click", (e) => { + e.stopPropagation(); // 阻止冒泡到父元素 + console.log("子元素点击"); +}); +``` + +## 四、事件委托(事件代理) +### 1. 核心原理 +利用事件冒泡机制,将子元素的事件绑定到父元素(甚至 `document`)上,通过 `e.target` 判断触发的子元素,实现批量元素的事件处理。 +### 2. 优势 +- 减少事件绑定次数,降低内存消耗; +- 支持动态添加的子元素(无需重新绑定事件)。 +### 3. 示例 +```html + + +``` + +```javascript +const list = document.getElementById("list"); +const addItem = document.getElementById("addItem"); + +// 事件委托:绑定到父元素 ul +list.addEventListener("click", (e) => { + // 判断是否点击了目标子元素 + if (e.target.classList.contains("item")) { + console.log("点击了项目:", e.target.textContent); + } +}); + +// 动态添加子元素(无需重新绑定事件) +addItem.addEventListener("click", () => { + const newLi = document.createElement("li"); + newLi.className = "item"; + newLi.textContent = `项目${list.children.length + 1}`; + list.appendChild(newLi); +}); +``` + +## 五、自定义事件 +除了浏览器内置事件,可手动创建自定义事件并触发,适用于组件通信、自定义交互逻辑。 +### 1. 创建并触发自定义事件 +```javascript +// 方式1:基础自定义事件 +const customEvent = new Event("myEvent", { + bubbles: true, // 是否冒泡 + cancelable: true // 是否可取消默认行为 +}); + +// 方式2:带自定义数据的事件(推荐) +const customEventWithData = new CustomEvent("myEventWithData", { + bubbles: true, + detail: { id: 123, msg: "自定义数据" } // 自定义数据 +}); + +// 绑定自定义事件 +const box = document.getElementById("box"); +box.addEventListener("myEventWithData", (e) => { + console.log("自定义事件触发", e.detail); // 输出 { id: 123, msg: "自定义数据" } +}); + +// 触发事件 +box.dispatchEvent(customEventWithData); +``` + +### 2. 全局自定义事件(跨组件) +```javascript +// 全局绑定 +document.addEventListener("globalEvent", (e) => { + console.log("全局自定义事件", e.detail); +}); + +// 任意位置触发 +document.dispatchEvent(new CustomEvent("globalEvent", { + detail: "全局数据" +})); +``` + +## 六、事件优化与注意事项 +### 1. 性能优化 +- **事件委托**:批量元素事件绑定到父元素,减少绑定次数; +- **防抖(Debounce)**:高频事件(如 `resize`、`scroll`、`input`)触发后延迟执行,避免频繁调用: + ```javascript + function debounce(fn, delay = 300) { + let timer = null; + return (...args) => { + clearTimeout(timer); + timer = setTimeout(() => fn.apply(this, args), delay); + }; + } + + // 使用防抖处理窗口缩放 + window.addEventListener("resize", debounce(() => { + console.log("窗口尺寸稳定后执行"); + }, 500)); + ``` +- **节流(Throttle)**:限制高频事件在指定时间内仅执行一次: + ```javascript + function throttle(fn, interval = 300) { + let lastTime = 0; + return (...args) => { + const now = Date.now(); + if (now - lastTime >= interval) { + fn.apply(this, args); + lastTime = now; + } + }; + } + + // 使用节流处理鼠标移动 + document.addEventListener("mousemove", throttle(() => { + console.log("鼠标移动(每秒最多3次)"); + }, 333)); + ``` +- **被动事件(passive)**:移动端触摸/滚动事件添加 `passive: true`,避免浏览器等待 `preventDefault()`,提升滚动流畅度: + ```javascript + document.addEventListener("touchmove", (e) => { + // 无需阻止默认行为时,passive 提升性能 + }, { passive: true }); + ``` + +### 2. 注意事项 +1. **this 指向**: + - 普通函数作为事件处理函数,`this` 指向触发事件的元素; + - 箭头函数的 `this` 指向外层作用域(如 `window`),如需访问元素可通过 `e.target`。 +2. **事件移除**: + - 使用 `addEventListener` 绑定的事件,必须用 `removeEventListener` 移除,且需传入同一个函数引用; + - 页面卸载前移除不必要的事件,避免内存泄漏(如监听 `window`/`document` 的事件)。 +3. **默认行为阻止**: + - 仅在需要时使用 `e.preventDefault()`,滥用会破坏原生交互(如表单提交、滚动); + - `passive: true` 时,`e.preventDefault()` 会失效,控制台会警告。 +4. **事件冒泡/捕获**: + - 大部分场景使用冒泡阶段(默认 `false`); + - 捕获阶段适用于需要优先处理父元素事件的场景(如事件拦截)。 + +## 七、常见场景示例 +### 1. 表单提交阻止默认行为 +```javascript +const form = document.querySelector("form"); +form.addEventListener("submit", (e) => { + e.preventDefault(); // 阻止表单默认提交 + // 手动处理表单数据 + const formData = new FormData(form); + console.log("表单数据:", Object.fromEntries(formData)); +}); +``` + +### 2. 鼠标右键自定义菜单 +```javascript +document.addEventListener("contextmenu", (e) => { + e.preventDefault(); // 阻止默认右键菜单 + const menu = document.getElementById("custom-menu"); + menu.style.left = `${e.clientX}px`; + menu.style.top = `${e.clientY}px`; + menu.style.display = "block"; +}); + +// 点击空白处关闭菜单 +document.addEventListener("click", () => { + document.getElementById("custom-menu").style.display = "none"; +}); +``` + +### 3. 移动端触摸滑动 +```javascript +let startX = 0; +document.addEventListener("touchstart", (e) => { + startX = e.touches[0].clientX; // 记录触摸起始位置 +}); + +document.addEventListener("touchmove", (e) => { + const moveX = e.touches[0].clientX - startX; + if (Math.abs(moveX) > 50) { + console.log(moveX > 0 ? "右滑" : "左滑"); + } +}, { passive: true }); +``` + +## 八、总结 +JS 事件处理是前端交互的核心,核心要点可归纳为: +1. **绑定方式**:优先使用 `addEventListener`,避免内联和 DOM 属性绑定; +2. **事件流**:理解捕获、目标、冒泡三阶段,灵活运用 `stopPropagation` 控制传播; +3. **事件对象**:熟练使用 `e.target`、`preventDefault`、`detail` 等核心属性/方法; +4. **性能优化**:事件委托、防抖/节流、被动事件提升交互体验; +5. **扩展能力**:自定义事件实现组件通信,满足复杂业务场景。 + +# 练习 +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207195843522.gif) +## 训练8 +```js +
+
+ +
+
+
+ //练习8 + let img = document.getElementById("img"); + let eventTexts = { + dragover: " 1", + dragleave: " 2", + drop: " 3" + }; + let originalTitle = document.title; + function dragover(e) { + document.title = eventTexts.dragover; + e.preventDefault(); + } + function dragleave(e) { + e.preventDefault(); + // 更新标题为dragleave事件描述 + document.title = eventTexts.dragleave; + // 可选:延迟1秒恢复原标题(避免频繁切换) + setTimeout(() => { + if (document.title === eventTexts.dragleave) { + document.title = originalTitle; + } + }, 1000); + } + function drop(e) { + e.preventDefault(); + // const target = e.target.tagName === 'IMG' ? e.target.parentElement : e.target; + e.target.appendChild(img); + document.title = eventTexts.drop; + setTimeout(() => { + document.title = originalTitle; + }, 2000); + + } + document.body.addEventListener('dragleave', dragleave); +``` + +## 训练9 +```js +
+
+
123
+
+
+
+ let text = document.getElementById("text"); + function dropText(e) { + e.preventDefault(); + // const target = e.target.tagName === 'TABLE' ? e.target.parentElement : e.target; + e.target.appendChild(text); + } +``` + +## 综合练习1 +```js +
+ 欢迎购买明日科技图书 +
+ //综合练习1 + function enlarge(el, isHover) { + if (isHover) { + el.style.color = "red"; + el.style.transform = "scale(1.5)"; + el.style.transition = "all 0.3s"; + } else { + el.style.color = ""; + el.style.transform = ""; + el.style.transition = ""; + } + } +``` + +## 综合练习2 +```js + + //综合练习2 + function switchLamp() { + // document.body.style.background = "black"; + let body = document.body; + body.style.background = body.style.background == "black" ? "white" : "black"; + + let btn1 = document.getElementById("btn1"); + btn1.value = btn1.value == "关灯" ? "开灯" : "关灯"; + } +``` + +## 综合练习3 +```js + + //综合练习3 + function btnTest1() { + let btn2 = document.getElementById("btn2"); + btn2.style.backgroundColor = "green" + btn2.style.color = "white"; + } + function btnTest2() { + let btn2 = document.getElementById("btn2"); + btn2.style.backgroundColor = "" + btn2.style.color = ""; + } +``` diff --git "a/\351\203\255\345\260\217\344\270\234/20251203-Document\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251203-Document\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..899b1ee0cd196e11545b190d8a9e7e086bbb2392 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251203-Document\345\257\271\350\261\241.md" @@ -0,0 +1,350 @@ +# 笔记 +## 一、Document 对象概述 +### 1. 核心概念 +`document` 是 JavaScript 中操作 HTML 文档的核心对象,属于 BOM(浏览器对象模型)的一部分,同时也是 DOM(文档对象模型)的根节点,代表整个 HTML/XML 文档。 + +- 它是 `window` 对象的属性,可通过 `window.document` 或直接 `document` 访问。 +- 所有页面元素(如 `
`、``)都是 `document` 的子节点,通过它可实现对页面内容的查询、创建、修改、删除。 + +### 2. 核心作用 +- 查找/获取页面元素(DOM 节点)。 +- 创建新的 DOM 节点并插入页面。 +- 修改页面元素的内容、属性、样式。 +- 监听/触发文档级别的事件(如加载完成、点击)。 +- 操作文档的元信息(标题、Cookie、URL 等)。 + +## 二、Document 对象核心属性 +| 属性名 | 说明 | 示例 | +|--------|------|------| +| `document.documentElement` | 获取文档的根节点(`` 元素) | `const html = document.documentElement;` | +| `document.body` | 获取 `` 元素 | `document.body.style.backgroundColor = "red";` | +| `document.head` | 获取 `` 元素 | `const meta = document.head.querySelector("meta[name='viewport']");` | +| `document.title` | 获取/设置文档标题(`` 内容) | `document.title = "新标题";` | +| `document.URL` | 返回当前文档的完整 URL(只读) | `console.log(document.URL);` | +| `document.domain` | 返回当前文档的域名(只读) | `console.log(document.domain); // 如 "www.baidu.com"` | +| `document.cookie` | 获取/设置当前文档的 Cookie | `document.cookie = "username=zhangsan; expires=Fri, 31 Dec 2025 23:59:59 GMT; path=/";` | +| `document.readyState` | 返回文档加载状态:<br>- `loading`:加载中<br>- `interactive`:可交互(DOM 加载完成)<br>- `complete`:完全加载(资源也完成) | `if (document.readyState === "complete") { /* 执行操作 */ }` | +| `document.activeElement` | 获取当前获得焦点的元素 | `console.log(document.activeElement); // 如 <input>` | + +## 三、获取 DOM 元素(高频方法) +### 1. 通过 ID 获取(唯一) +```javascript +// 获取 id 为 "box" 的元素,返回单个元素(无则 null) +const box = document.getElementById("box"); +``` + +### 2. 通过类名获取 +```javascript +// 获取所有 class 为 "item" 的元素,返回 HTMLCollection(伪数组) +const items = document.getElementsByClassName("item"); +// 转换为真数组 +const itemsArr = Array.from(items); +``` + +### 3. 通过标签名获取 +```javascript +// 获取所有 <div> 元素,返回 HTMLCollection +const divs = document.getElementsByTagName("div"); +``` + +### 4. 通过选择器获取(灵活) +#### 4.1 获取单个元素 +```javascript +// 匹配第一个符合选择器的元素,无则 null +const firstItem = document.querySelector(".item"); +const btn = document.querySelector("#btn"); +const link = document.querySelector("a[href='https://baidu.com']"); +``` + +#### 4.2 获取所有匹配元素 +```javascript +// 匹配所有符合选择器的元素,返回 NodeList(伪数组) +const allItems = document.querySelectorAll(".item"); +// 遍历 NodeList +allItems.forEach(item => { + console.log(item); +}); +``` + +### 方法对比 +| 方法 | 返回值 | 动态/静态 | 特点 | +|------|--------|-----------|------| +| `getElementById` | 单个元素 | - | 最快,仅匹配 ID | +| `getElementsByClassName` | HTMLCollection | 动态(DOM 变化自动更新) | 按类名匹配,伪数组 | +| `getElementsByTagName` | HTMLCollection | 动态 | 按标签名匹配 | +| `querySelector` | 单个元素 | 静态 | 支持 CSS 选择器,灵活 | +| `querySelectorAll` | NodeList | 静态 | 支持 CSS 选择器,批量匹配 | + +## 四、创建/插入/删除 DOM 节点 +### 1. 创建节点 +```javascript +// 创建元素节点(如 <div>) +const newDiv = document.createElement("div"); +// 设置内容和样式 +newDiv.textContent = "新创建的div"; +newDiv.className = "new-item"; + +// 创建文本节点(较少单独使用) +const textNode = document.createTextNode("纯文本内容"); + +// 创建属性节点(可直接用 setAttribute 替代) +const attrNode = document.createAttribute("data-id"); +attrNode.value = "123"; +newDiv.setAttributeNode(attrNode); +``` + +### 2. 插入节点 +| 方法 | 说明 | 示例 | +|------|------|------| +| `parent.appendChild(child)` | 将子节点添加到父节点的末尾 | `document.body.appendChild(newDiv);` | +| `parent.insertBefore(newNode, refNode)` | 将新节点插入到参考节点之前 | `const box = document.getElementById("box");`<br>`box.insertBefore(newDiv, box.firstChild);` | +| `element.replaceChild(newNode, oldNode)` | 替换节点 | `box.replaceChild(newDiv, box.children[0]);` | + +### 3. 删除节点 +```javascript +// 方式1:父节点删除子节点 +const box = document.getElementById("box"); +box.removeChild(box.children[0]); + +// 方式2:节点自身删除(ES6+) +const item = document.querySelector(".item"); +item.remove(); +``` + +### 4. 克隆节点 +```javascript +// 克隆节点:true 表示深克隆(包含子节点),false 仅克隆自身 +const cloneDiv = newDiv.cloneNode(true); +document.body.appendChild(cloneDiv); +``` + +## 五、操作文档内容 +### 1. 文本/HTML 内容 +```javascript +const box = document.getElementById("box"); + +// 设置/获取纯文本(推荐,避免 XSS) +box.textContent = "Hello World"; +console.log(box.textContent); // 输出 "Hello World" + +// 设置/获取 HTML 内容(有 XSS 风险,谨慎使用) +box.innerHTML = "<h1>Hello World</h1>"; +console.log(box.innerHTML); // 输出 "<h1>Hello World</h1>" +``` + +### 2. 属性操作 +```javascript +const input = document.querySelector("input"); + +// 设置属性 +input.setAttribute("type", "password"); +input.setAttribute("placeholder", "请输入密码"); + +// 获取属性 +const type = input.getAttribute("type"); // "password" + +// 判断是否存在属性 +if (input.hasAttribute("disabled")) { + input.removeAttribute("disabled"); +} + +// 自定义属性(data-*) +input.dataset.id = "456"; // 设置 data-id="456" +console.log(input.dataset.id); // "456" +``` + +## 六、文档事件 +### 1. 文档加载事件 +```javascript +// 方式1:DOM 加载完成(DOMContentLoaded)—— 无需等待资源加载 +document.addEventListener("DOMContentLoaded", () => { + console.log("DOM 已加载完成,可操作元素"); +}); + +// 方式2:页面完全加载(包括图片、样式等资源) +window.onload = () => { + console.log("页面所有资源加载完成"); +}; +``` + +### 2. 其他常用文档事件 +```javascript +// 点击事件(文档级别委托) +document.addEventListener("click", (e) => { + // 事件委托:判断点击的目标元素 + if (e.target.classList.contains("btn")) { + console.log("按钮被点击"); + } +}); + +// 键盘事件 +document.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + console.log("回车键被按下"); + } +}); +``` + +## 七、常用工具方法 +| 方法 | 说明 | 示例 | +|------|------|------| +| `document.write()` | 直接向文档写入内容(慎用,会覆盖页面) | `document.write("<p>临时内容</p>");` | +| `document.querySelector()` | 见「获取 DOM 元素」 | - | +| `document.createElement()` | 见「创建节点」 | - | +| `document.getElementById()` | 见「获取 DOM 元素」 | - | +| `document.hasFocus()` | 判断文档是否获得焦点 | `console.log(document.hasFocus());` | +| `document.createElementNS()` | 创建命名空间元素(如 SVG) | `const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");` | + +## 八、注意事项 +1. **DOM 操作性能**:频繁操作 DOM 会触发重排/重绘,建议批量操作(如用 DocumentFragment 暂存节点): + ```javascript + const fragment = document.createDocumentFragment(); + for (let i = 0; i < 100; i++) { + const div = document.createElement("div"); + fragment.appendChild(div); + } + document.body.appendChild(fragment); // 仅一次重排 + ``` + +2. **空值判断**:获取元素后需先判断是否为 null,避免报错: + ```javascript + const box = document.getElementById("box"); + if (box) { // 非空才操作 + box.textContent = "内容"; + } + ``` + +3. **XSS 风险**:避免使用 `innerHTML` 插入不可信内容,优先用 `textContent`。 + +4. **动态 vs 静态集合**:`getElementsByClassName` 返回的 HTMLCollection 是动态的,遍历前建议转为数组,避免因 DOM 变化导致遍历异常。 + +## 九、总结 +`document` 对象是 JS 操作页面的核心,核心能力可归纳为: +- **查**:通过 ID、类名、选择器获取元素; +- **改**:修改元素内容、属性、样式; +- **增**:创建节点并插入文档; +- **删**:删除/替换节点; +- **监听**:处理文档加载、交互事件。 + +掌握以上内容可覆盖 90% 以上的 DOM 操作场景,实际开发中需结合性能优化(如减少 DOM 操作次数、事件委托)提升页面效率。 + +# 练习 +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207194859075.gif) +## 训练1 +```js + <div> + <input type="button" id="btn1" onclick="btnConvert()" value="交互颜色"> + 123 + </div> + //训练1 + function btnConvert() { + let body = document.body; + body.style.backgroundColor = "red"; + body.style.color = "white"; + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207194934172.png) +## 训练2 +```js + //训练2 + document.writeln("<br>当前文档的文件名称:" + document.URL); +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207195018898.gif) +## 训练3 +```js + <div> + <input type="text" id="txt"> + <input type="button" id="btn2" onclick="btnAdd()" value="添加文字"> + </div> + //训练3 + let str = '123456789'; + function btnAdd() { + let txt = document.getElementById("txt"); + // txt.value += "a"; + for (let i = 0; i < str.length; i++) { + setTimeout(() => { + txt.value = str.substring(0, i + 1); + }, i * 1000); + } + + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207195122065.gif) +## 综合练习1 +```js + <div id="box-colorTheme"> + <select name="colorTheme" id="colorTheme" onclick="chooseTheme()"> + <option value="a">请选择主题</option> + <option value="b">绿色主题</option> + </select> + <h2>标题</h2> + <span>文字</span> + <span>文字</span> + <span>文字</span> + <span>文字</span> + <span>文字</span> + </div> + //综合练习1 + function chooseTheme() { + let box = document.querySelector("#colorTheme").value; + let body = document.getElementById("box-colorTheme"); + if (box == "a") { + body.style.backgroundColor = ""; + body.style.color = ""; + } else if (box == "b") { + body.style.backgroundColor = "green"; + body.style.color = "white"; + } + } +``` + +## 综合练习2 +```js + <a href="#" id="img" onclick="openImg(event)">打开图片对话框</a> + //综合练习2 + function openImg(e) { + e.preventDefault(); + let imgDiv = document.createElement("div"); + imgDiv.style.width = "100px"; + imgDiv.style.height = "100px"; + imgDiv.style.border = "1px solid #000"; + imgDiv.style.float = "left"; + + let deleteBtn = document.createElement("input"); + deleteBtn.type = "button"; + deleteBtn.value = "X删除"; + deleteBtn.style.cssText = "float:right; border: none; background: transparent;"; + deleteBtn.onclick = () => document.body.removeChild(imgDiv); + + let img = document.createElement("img"); + img.src = "#"; + + imgDiv.appendChild(img); + imgDiv.appendChild(deleteBtn); + document.body.appendChild(imgDiv); + + } +``` + +## 综合练习3 +```js + <input type="button" id="addImg" onclick="addImg()" value="添加用户头像"> + //综合练习3 + function addImg() { + let imgDiv = document.createElement("div"); + imgDiv.style.cssText = "width:100px; height:100px; border:1px solid #000 " + imgDiv.style.float = "left"; + document.body.appendChild(imgDiv); + + let img = document.createElement("img"); + img.src = "#"; + imgDiv.appendChild(img); + + for (let i = 1; i < 3; i++) { + setTimeout(() => { + document.body.appendChild(imgDiv.cloneNode(true)); + }, i * 1000); + } + + } +``` diff --git "a/\351\203\255\345\260\217\344\270\234/20251204-DOM.md" "b/\351\203\255\345\260\217\344\270\234/20251204-DOM.md" new file mode 100644 index 0000000000000000000000000000000000000000..1994d520754299b66a7a54e753acf473298c77ff --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251204-DOM.md" @@ -0,0 +1,403 @@ +# 笔记 +## DOM概述 + + DOM是document object model 的缩写,意为文档对象模型. + +## 节点 + +### 节点种类 + + - 根节点 + - 父节点 + - 子节点 + - 兄弟节点 + - 后代 + - 叶节点 +### 节点属性 + +|属性|说明|属性|说明| +|-|-|-|-| +|nodeName|节点的名称|firstChild|返回当前节点的第一个子节点| +|nodeValue|节点的值,通常只用于文本节点|lastChild|返回当前节点的最后一个子节点| +|nodeType|节点的类型|previousSibling|返回当节点的前一个兄弟节点| +|parentNode|返回当前节点的父节点|lasnextSiblingtChild|返回当节点的后一个兄弟节点| +|childNodes|子节点列表|attribuites|元素的属性列表| + +### 创建节点 +```js +obj.appendchild(newChild); +``` +### 插入节点 +```js +obj.insertBefore(new,ref); +``` +### 复制节点 +```js +obj.cloneNode(deep); +``` +### 删除与替换节点 +```js +obj.removeChild(oldChild); +``` +## 获取文档中的指定元素 +### 通过元素的id属性获取元素 +```js +document.getElementByid("id"); +``` +### 通过元素的class属性获取元素 +```js +document.getElementByClassName("id"); +``` +## 与DHTML相对应的DOM +### innerHTML 和 innerText属性 +```js + document.getElementByid("id").innerHTML = "内容"; +``` +### outerHTML 和 outerText属性 +```js + document.getElementByid("id").outerHTML = "内容"; +``` + +# 练习 +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207192913368.gif) +## 训练1 +```js + <div id="box1"> + <input type="text" name="" id="box1-inputText"> + <select id="selectColor"> + <option value="a">选择颜色</option> + <option value="b">红色</option> + <option value="c">蓝色</option> + </select> + <input type="button" value="添加" onclick="addColor()"> + <div id="box1-1"></div> + </div> + + function addColor() { + let txt = document.getElementById("box1-inputText"); + let selectColor = document.querySelector("#selectColor"); + let color = selectColor.value; + let span = document.createElement('span'); + if (color == "a") { + span.style.color = ""; + } else if (color == "b") { + span.style.color = "red"; + } else if (color == "c") { + span.style.color = "blue"; + } + let getText = txt.value; + let txtNode = document.createTextNode(getText); + span.appendChild(txtNode); + + document.getElementById("box1-1").appendChild(span); + + txt.value = ""; + + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193119444.gif) +## 训练2、训练3 +```js + <div id="box2"> + <div id="box2-1"> + <ul id="box2-ul"> + <li>1</li> + <li>2</li> + <li>3</li> + <li>4</li> + </ul> + </div> + <div id="box2-2"> + <input type="text" id="box2-inputText"> + <input type="button" value="添加" onclick="addText()"> + <input type="button" value="删除" onclick="deleteText()"> + </div> + + </div> + // 训练2 + function addText() { + + let txt = document.getElementById('box2-inputText'); + let li = document.createElement('li'); + let ul = document.getElementById("box2-ul"); + + let getText = txt.value; + getText = getText.trim(); + let txtNode = document.createTextNode(getText); + li.appendChild(txtNode); + + + let str = ['1', '2', '3', '4', '5'] + + + if (str.includes(getText)) { + ul.appendChild(li); + } else { + alert(getText === "" ? "请输入内容" : "请输入正确内容"); + } + + + + txt.value = ""; + } + + //训练3 + function deleteText() { + let ul = document.getElementById('box2-ul'); + let txt = document.getElementById('box2-inputText'); + + + let getText = txt.value.trim(); + + let liList = ul.querySelectorAll("li"); + + for (let i = 0; i < liList.length; i++) { + let li = liList[i] + if (li.textContent.trim() === getText) { + ul.removeChild(liList[i]); + txt.value = ""; + return; + } + } + + + // let targetLi = null; + // // 5. 遍历查找匹配文本的li + // for (let li of liList) { + // // li.textContent 获取li的纯文本内容(等价于文本节点的nodeValue) + // if (li.textContent.trim() === getText) { + // targetLi = li; + // break; // 找到第一个匹配的li,停止遍历 + // } + // } + } + +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193202321.gif) +## 训练4 +```js + <div id="box4"> + <div id="box4-1"> + <ul id="vegetables"> + <li>1</li> + <li>1</li> + <li>2</li> + </ul> + <ul id="fruit"> + <li>2</li> + <li>2</li> + <li>1</li> + </ul> + </div> + <div id="box4-2"> + <input type="button" value="移动" onclick="moveFood()"> + </div> + </div> + function moveFood() { + let vegUl = document.getElementById("vegetables"); + let fruUl = document.getElementById("fruit"); + + let vegLastLi = vegUl.lastElementChild; + let fruLastLi = fruUl.lastElementChild; + + vegUl.replaceChild(fruLastLi.cloneNode(true), vegLastLi); + fruUl.replaceChild(vegLastLi.cloneNode(true), fruLastLi); + // vegUl.replaceChild(fruLastLi, vegLastLi); + // fruUl.appendChild(vegLastLi); + + + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193253854.gif) +## 训练5 +```js + <div id="box5"> + <h3>在《倚天屠龙记》中,张三丰是______派的掌门?</h3> + <div id="box5-1"> + <input type="radio" name="box5-radio" value="少林">A.少林 + <input type="radio" name="box5-radio" value="武当">B.武当 + <input type="radio" name="box5-radio" value="峨眉">C.峨眉 + <input type="radio" name="box5-radio" value="昆仑">D.昆仑 + </div> + <input type="button" value="提交答案" onclick="btnSubmit()"> + </div> + function btnSubmit() { + let radio = document.querySelectorAll('input[name="box5-radio"]'); + let radioValue = null; + for (let i = 0; i < radio.length; i++) { + //核心:判断当前单选框是否被选中 + if (radio[i].checked) { + radioValue = radio[i].value; + break; + } + } + console.log(radioValue); + + if (radioValue === "武当") { + alert("答案正确"); + + } else if (!radioValue) { + alert("请选择一个答案!"); + } else { + alert("答案错误"); + } + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193349290.gif) +## 训练6 +```js + <div id="box6"> + <a href="" id="alink">超链接:</a> + <input type="button" value="修改" onclick="btnEdit()"> + </div> + //训练6 + function btnEdit() { + let alink = document.getElementById("alink"); + alink.innerHTML = "修改后的超链接"; + alink.href = "123"; + document.getElementById("box6").appendChild(aLink); + + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193436569.gif) +## 训练7 +```js + <div id="box7"> + <div id="box7-1"></div> + <input type="button" value="添加" onclick="btnAdd()"> + </div> + //训练7 + function btnAdd() { + let img = document.getElementById("box7-1"); + img.innerHTML += "<img src='https://c-ssl.duitang.com/uploads/blog/202307/11/q4S7lZMeixNVEMj.jpg' alt='' style='height:100%; width:100%; object-fit: cover;'>"; + img.style.cssText = "height:200px; width:200px; border: 1px solid black;"; + // let addImg = img.appendChild(img); + + } +``` +示例图:![](https://gitee.com/gxdo/grade24-class1-note-h5css3/raw/master/郭小东/图片/20251207193948220.gif) +## 综合练习1 +```js + <div id="box1"> + <div id="box1-1"> + <b>医生挚爱异人</b> + </div> + <a href="#" onclick="aEdit()">将粗体改为斜体</a> + + </div> + // 综合练习1 + function aEdit() { + let bText = document.getElementById("box1-1"); + let newItext = document.createElement("i"); + newItext.textContent = bText.children[0].textContent; + bText.replaceChild(newItext, bText.children[0]); + } +``` + +## 综合练习2 +```js + <div id="box2"> + <select name="" id="year"></select> + <select name="" id="month"></select> + <select name="" id="day"></select> + </div> + function aEdit() { + let bText = document.getElementById("box1-1"); + let newItext = document.createElement("i"); + newItext.textContent = bText.children[0].textContent; + bText.replaceChild(newItext, bText.children[0]); + } + // 综合练习2 + let year = document.getElementById("year"); + let month = document.getElementById("month"); + let day = document.getElementById("day"); + + //年 + function initYear() { + let now = new Date(); + let currentYear = now.getFullYear(); + for (let i = 1990; i <= currentYear; i++) { + let option = document.createElement("option"); + option.value = i; + option.textContent = i + "年"; + year.appendChild(option); + } + year.value = currentYear; + } + + //月 + function initMonth() { + let now = new Date(); + let currenMonth = now.getMonth(); + for (let i = 1; i <= 12; i++) { + let option = document.createElement("option"); + option.value = i; + option.textContent = i + "月"; + month.appendChild(option); + } + month.value = currenMonth; + } + + //日 + function initDay() { + let selectYear = parseInt(year.value); + let selectMonth = parseInt(month.value); + let selectDay = new Date(selectYear, selectMonth, 0).getDate(); + day.innerHTML = ""; + for (let i = 1; i <= selectDay; i++) { + let option = document.createElement("option"); + option.value = i; + option.textContent = i + "日"; + day.appendChild(option); + } + let currentDay = new Date().getDate(); + day.value = currentDay > selectMonth ? selectMonth : currentDay; + } + // 联动 + year.addEventListener("change", function () { + initDay(); + }) + month.addEventListener("change", initDay); + //引用 + initYear(); + initMonth(); + initDay(); +``` + +## 综合练习3 +```js + <div id="box3"> + <b>请选择表情</b> + <select name="" id="selImg"> + <option value="1">选择表情</option> + <option value="2">龙图</option> + <option value="3">熊猫人</option> + </select> + <div id="box3-1"></div> + </div> + // 综合练习3 + function selectImg() { + let selImg = document.querySelector("#selImg")?.value; + let img = document.getElementById("box3-1"); + console.log(selImg); + console.log(img); + + + if (selImg == 2 && img) { + img.innerHTML = "<img src='https://c-ssl.duitang.com/uploads/blog/202307/11/q4S7lZMeixNVEMj.jpg' alt='' style='height:200px; width:200px; object-fit: cover;'>"; + } else if (selImg == 3 && img) { + img.innerHTML = "<img src='https://c-ssl.duitang.com/uploads/item/202003/24/20200324005850_usyfo.jpg' alt='' style='height:200px; width:300px; object-fit: cover;'>"; + } else if (img) { + img.innerHTML = ""; + } + + } + document.addEventListener("DOMContentLoaded", function () { + selectImg(); // 保留原执行逻辑 + // 新增:绑定下拉框change事件 + const selImgEle = document.querySelector("#selImg"); + if (selImgEle) { + selImgEle.addEventListener("change", selectImg); + } + }) +``` diff --git "a/\351\203\255\345\260\217\344\270\234/20251205-Window\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251205-Window\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..47461ed0aa712d0d53945afd4da7ba16138cff9a --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251205-Window\345\257\271\350\261\241.md" @@ -0,0 +1,441 @@ +# 笔记 +## 一、Window 对象概述 +### 1. 核心定位 +`window` 是 JavaScript 中 **BOM(浏览器对象模型)的顶层对象**,代表浏览器的一个窗口或标签页,是 JS 与浏览器交互的核心桥梁。 + +- 它是全局作用域的载体,所有全局变量、全局函数都会自动成为 `window` 的属性和方法。 +- 调用 `window` 的属性或方法时,可省略 `window` 前缀(如 `alert()` 等价于 `window.alert()`)。 +- 每个窗口/标签页对应一个独立的 `window` 对象,不同窗口的 `window` 互不干扰(受跨域限制)。 + +### 2. 核心作用 +- 控制浏览器窗口(打开、关闭、调整大小)。 +- 操作浏览器地址栏、历史记录。 +- 实现弹窗交互(提示、确认、输入)。 +- 管理定时器、本地存储。 +- 监听窗口级事件(加载、缩放、滚动)。 +- 承载全局变量和函数。 + +## 二、Window 核心子对象(高频) +### 1. document(DOM 桥梁) +`window.document` 是连接 BOM 与 DOM 的桥梁,代表当前页面的文档对象,用于操作页面 DOM 结构。 +```javascript +// 示例:获取页面元素(省略 window 前缀) +document.querySelector("#box"); +document.body.style.backgroundColor = "red"; +``` + +### 2. location(地址栏操作) +`window.location` 用于操作浏览器地址栏,控制页面导航和 URL 相关操作,核心属性和方法如下: +| 属性/方法 | 说明 | 示例 | +|-----------|------|------| +| `href` | 获取/设置完整 URL(常用页面跳转) | `location.href = "https://example.com";` | +| `host` | 返回域名 + 端口号 | `console.log(location.host); // 如 "www.baidu.com:80"` | +| `hostname` | 返回域名(不含端口) | `console.log(location.hostname); // "www.baidu.com"` | +| `pathname` | 返回 URL 中的路径部分 | `console.log(location.pathname); // 如 "/index.html"` | +| `search` | 返回 URL 中的查询参数(?后面部分) | `console.log(location.search); // 如 "?id=123"` | +| `hash` | 返回 URL 中的哈希值(#后面部分) | `console.log(location.hash); // 如 "#top"` | +| `reload()` | 刷新当前页面 | `location.reload(); // 强制刷新加 true:location.reload(true)` | +| `replace(url)` | 替换当前页面(不保留历史记录,无法后退) | `location.replace("https://example.com");` | + +### 3. history(历史记录管理) +`window.history` 用于操作浏览器的历史记录,实现页面前进、后退功能。 +| 方法 | 说明 | 示例 | +|------|------|------| +| `back()` | 后退到上一页(等价于浏览器“后退”按钮) | `history.back();` | +| `forward()` | 前进到下一页(等价于浏览器“前进”按钮) | `history.forward();` | +| `go(n)` | 跳转到历史记录中指定位置(n 为正数前进,负数后退) | `history.go(-2); // 后退2页` | +| `length` | 属性,返回历史记录的条数 | `console.log(history.length); // 查看当前窗口的历史记录总数` | + +### 4. navigator(浏览器/设备信息) +`window.navigator` 用于获取浏览器和当前设备的相关信息,常用属性如下: +```javascript +// 获取浏览器名称(部分浏览器会隐藏真实名称) +console.log(navigator.appName); + +// 获取浏览器版本信息 +console.log(navigator.appVersion); + +// 获取用户代理字符串(常用于判断浏览器类型和设备) +console.log(navigator.userAgent); + +// 判断是否为移动设备(通过用户代理匹配) +const isMobile = /Mobile|Android|iOS/.test(navigator.userAgent); +console.log(isMobile ? "移动设备" : "桌面设备"); + +// 获取当前浏览器支持的语言 +console.log(navigator.language); // 如 "zh-CN" +``` + +### 5. screen(屏幕信息) +`window.screen` 用于获取显示器屏幕的相关信息,常用属性如下: +```javascript +// 屏幕总宽高(包括任务栏等系统组件) +console.log(screen.width, screen.height); + +// 屏幕可用宽高(不包括任务栏,实际可显示区域) +console.log(screen.availWidth, screen.availHeight); + +// 屏幕颜色深度 +console.log(screen.colorDepth); // 通常为 24(表示真彩色) +``` + +## 三、Window 核心方法 +### 1. 窗口控制方法 +用于控制浏览器窗口的打开、关闭、移动和大小调整,**仅对通过 `open()` 打开的自定义窗口生效**(外部域名窗口受跨域限制)。 +| 方法 | 说明 | 示例 | +|------|------|------| +| `open(url, target, features)` | 打开新窗口/标签页,返回新窗口的 `window` 对象 | `const newWin = open("https://example.com", "_blank", "width=500,height=500,top=100,left=100");` | +| `close()` | 关闭指定窗口(需通过 `open()` 返回的窗口对象调用) | `newWin.close();` | +| `moveTo(x, y)` | 将窗口移动到屏幕指定坐标(x/y 为屏幕左上角起点) | `newWin.moveTo(200, 200);` | +| `resizeTo(w, h)` | 将窗口调整为指定宽高 | `newWin.resizeTo(600, 400);` | + +### 2. 弹窗交互方法 +用于与用户进行简单交互,弹出提示、确认或输入框(样式受浏览器限制,自定义程度低)。 +| 方法 | 说明 | 示例 | +|------|------|------| +| `alert(msg)` | 弹出提示框(只有“确定”按钮) | `alert("操作成功!");` | +| `confirm(msg)` | 弹出确认框(有“确定”和“取消”按钮),返回布尔值 | `const isConfirm = confirm("确定要删除吗?");` | +| `prompt(msg, defaultVal)` | 弹出输入框,返回用户输入的内容(取消则返回 null) | `const username = prompt("请输入用户名:", "默认用户名");` | + +### 3. 定时器方法 +用于延迟执行代码或定期执行代码,是前端常用的异步操作方式。 +#### 3.1 一次性定时器(setTimeout) +延迟指定时间后执行一次代码,返回定时器 ID(用于清除定时器)。 +```javascript +// 语法:setTimeout(回调函数, 延迟时间(毫秒), 传递给回调的参数) +const timer1 = setTimeout((name) => { + console.log(`Hello ${name}`); +}, 1000, "张三"); + +// 清除一次性定时器(未执行前有效) +clearTimeout(timer1); +``` + +#### 3.2 周期性定时器(setInterval) +每隔指定时间重复执行代码,返回定时器 ID。 +```javascript +// 语法:setInterval(回调函数, 间隔时间(毫秒)) +const timer2 = setInterval(() => { + console.log("每隔2秒执行一次"); +}, 2000); + +// 清除周期性定时器(必须手动清除,否则会一直执行) +clearInterval(timer2); +``` + +### 4. 本地存储方法 +用于在浏览器中存储数据(无过期时间,仅在当前域名下有效),核心有两种方式: +#### 4.1 localStorage(永久存储) +数据存储在浏览器中,除非手动删除,否则永久保留,容量约 5MB。 +```javascript +// 存储数据(键值对,值必须是字符串) +localStorage.setItem("username", "zhangsan"); +localStorage.setItem("age", 20); // 自动转为字符串 "20" + +// 获取数据 +const username = localStorage.getItem("username"); +console.log(username); // "zhangsan" + +// 删除指定数据 +localStorage.removeItem("age"); + +// 清空所有数据 +localStorage.clear(); +``` + +#### 4.2 sessionStorage(会话存储) +数据仅在当前会话(窗口/标签页)有效,关闭窗口后数据自动删除,容量约 5MB。 +```javascript +// 用法与 localStorage 一致,仅存储时效不同 +sessionStorage.setItem("token", "abc123"); +const token = sessionStorage.getItem("token"); +sessionStorage.removeItem("token"); +``` + +## 四、Window 常用事件 +### 1. 页面加载事件 +| 事件 | 说明 | 示例 | +|------|------|------| +| `load` | 页面**完全加载完成**(包括图片、样式、脚本等所有资源)后触发 | `window.onload = () => { console.log("页面全部加载完成"); }` | +| `DOMContentLoaded` | DOM 结构加载完成(无需等待图片、样式等资源)后触发,比 `load` 更早 | `document.addEventListener("DOMContentLoaded", () => { console.log("DOM 加载完成"); });` | + +### 2. 窗口尺寸事件 +```javascript +// 窗口大小发生变化时触发(如缩放浏览器) +window.addEventListener("resize", () => { + // 获取窗口可视区域宽高(常用) + const winWidth = window.innerWidth; + const winHeight = window.innerHeight; + console.log(`窗口宽:${winWidth}px,高:${winHeight}px`); +}); +``` + +### 3. 页面滚动事件 +```javascript +// 页面滚动时触发(如滚动鼠标滚轮) +window.addEventListener("scroll", () => { + // 获取页面滚动的距离(垂直方向) + const scrollTop = window.scrollY; + // 获取页面滚动的距离(水平方向) + const scrollLeft = window.scrollX; + console.log(`垂直滚动:${scrollTop}px`); +}); +``` + +### 4. 其他常用事件 +- `beforeunload`:页面关闭或刷新前触发,可提示用户确认离开。 +- `hashchange`:URL 中的哈希值(#后面部分)变化时触发,常用于单页应用路由。 + +## 五、注意事项 +1. **全局变量与 window 的关系**:用 `var` 声明的全局变量会成为 `window` 的属性,用 `let`/`const` 声明的全局变量不会(但仍在全局作用域中)。 + ```javascript + var a = 10; + console.log(window.a); // 10(var 声明会挂载到 window) + + let b = 20; + console.log(window.b); // undefined(let 声明不会挂载) + ``` + +2. **跨域限制**:不同域名的窗口,无法通过 `window` 对象相互操作(如获取对方的 `location`、调用对方的方法),浏览器会拦截跨域操作以保障安全。 + +3. **定时器清除**:周期性定时器(`setInterval`)必须手动用 `clearInterval` 清除,否则会一直执行,导致内存泄漏。 + +4. **弹窗限制**:现代浏览器对 `open()` 弹出的窗口有拦截策略,仅在用户交互(如点击事件)中调用 `open()`,才能正常弹出窗口。 + +5. **存储数据格式**:`localStorage` 和 `sessionStorage` 仅能存储字符串,存储对象/数组时需先转为 JSON 字符串,读取时再解析。 + ```javascript + // 存储对象 + const user = { name: "张三", age: 20 }; + localStorage.setItem("user", JSON.stringify(user)); + + // 读取对象 + const userData = JSON.parse(localStorage.getItem("user")); + ``` + +## 六、总结 +`window` 对象是 JS 操作浏览器的核心,核心能力可归纳为: +- **窗口控制**:打开、关闭、调整窗口大小。 +- **导航操作**:通过 `location` 跳转页面、`history` 管理历史记录。 +- **信息获取**:通过 `navigator`/`screen` 获取浏览器、设备信息。 +- **交互能力**:弹窗交互、定时器、本地存储。 +- **事件监听**:监听页面加载、窗口缩放、滚动等事件。 + +# 练习 + +## 训练1 +```html +<!-- 训练1 --> + <audio controls id="audio"> + <source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg"> + <source src="horse.ogg" type="audio/ogg"> + </audio> +``` +```js +// 训练1 +document.querySelector('#audio').addEventListener('play', () => { + alert('只有会员才能播放歌曲,请登录!'); + audio.pause(); +}) +``` +## 训练2 +```html + <!-- 训练2 --> + + <a href="#" onclick="aBtn()">退出登录</a> +``` +```js +// 训练2 +function aBtn() { + alert("您确定退出登录吗") +} +``` +## 训练3 +```html +<!-- 训练3 --> +<img id="img" onclick="imgBtn()" + src="https://ts1.tc.mm.bing.net/th/id/R-C.6f18e58bf3bacbcee226cb76dfc089a3?rik=61%2bMLnhOzFiZOg&riu=http%3a%2f%2fimages.shejidaren.com%2fwp-content%2fuploads%2f2014%2f07%2f085628m6c.jpg&ehk=v1vDvzVgPRc3irw6n%2bs5gF%2b5SEc1uCstErDhRaxqlgE%3d&risl=&pid=ImgRaw&r=0" + alt="影片封面"> +<!-- 弹窗容器 --> +<div class="modal-mask" id="modalMask"> + <div class="modal-content"> + <span class="close-btn" onclick="closeModal()">×</span> + <!-- 影片详情内容 --> + <h2>603字母节目</h2> + <p><strong>导演:</strong>wrh</p> + <p><strong>主演:</strong>wrh,lct</p> + <p><strong>剧情简介:</strong>神秘刺激的字母情节</p> + </div> +</div> +``` +```js +// 训练3 +function imgBtn() { + let modal = document.getElementById('modalMask'); + modal.style.display = 'flex'; +} +function closeModal() { + let modal = document.getElementById('modalMask'); + modal.style.display = 'none'; // 隐藏弹窗 +} +``` +## 训练4 +```html + +``` +```js +// 训练4 +let window4 = window.open("new.html", "new", "height=200,width=200"); +setTimeout(() => { + window4.close(); + +}, 5000); +``` +## 训练5 +```html +<!-- 训练5 --> +<div class="open"> + <input type="button" onclick="openBtn()" value="打开窗口"> +</div> +``` +```js +// 训练5 +function openBtn() { + let window4 = window.open("new.html", "new", "height=200,width=200"); + setTimeout(() => { + let currentX = window4.screenX; + let currentY = window4.screenY; + let targetY = currentY + 200; // 最终向下移200px + let step = 5; // 每帧移动5px(越小越平滑) + + // 逐帧移动 + let moveTimer = setInterval(() => { + currentY += step; + // 到达目标位置后停止 + if (currentY >= targetY) { + currentY = targetY; + clearInterval(moveTimer); + } + window4.moveTo(currentX, currentY); + }, 16); // 约60帧/秒,保证流畅 + }, 2000); +} +``` +## 训练6 +```html +<!-- 训练6 --> +<div> + <input type="text" id="box6-text"> + <input type="button" onclick="startTimingBtn()" value="开始计时"> + <input type="button" onclick="endTimingBtn()" value="结束计时"> +</div> +``` +```js +// 训练6 +let txt = document.getElementById("box6-text"); +let time = 1; +let timer1 = null, timer2 = null; + + +function startTimingBtn() { + timer1 = setInterval(() => { + txt.value = time; + }, 1000); + + timer2 = setInterval(() => { + time++; + return time; + }, 1000); +} +function endTimingBtn() { + clearInterval(timer1); + clearInterval(timer2); + timer1 = null; + timer2 = null; +} +``` +## 综合练习1 +```html + <!-- 综合练习1 --> + <input type="button" onclick="btnCalculate()" value="计算"> +``` +```js +// 综合练习1 +function btnCalculate() { + let num1, num2; + num1 = Math.floor(Math.random() * 10); + num2 = Math.floor(Math.random() * 10); + let correctAnswer = num1 + num2; + let answer; + let dialog1 = prompt(`${num1}+${num2}=`, answer); + if (dialog1 === null) { + alert("你取消了答题~"); + return; + } + answer = Number(dialog1); + if (answer == correctAnswer) { + let dialog2 = confirm(`回答正确是否继续答题`); + if (dialog2) { + btnCalculate(); + } else { + let dialog3 = alert(`您拒绝了继续答题`); + return; + } + } else { + alert("回答错误"); + } +} +``` +## 综合练习2 +```html + <!-- 综合练习2 --> + <input type="button" onclick="btnChoose()" value="选择"> +``` +```js +// 综合练习2 +function btnChoose() { + let correctAnswer = "D"; + let answer; + let dialog1 = prompt("2024年奥运会在那座城市举办?\n\n\nA.罗马\nB.北京\nC.伦敦\nD.巴黎", answer); + answer = String(dialog1); + console.log(answer); + + if (answer == correctAnswer) { + alert("答案正确"); + } else { + alert("答案错误"); + } +} +``` +## 综合练习3 +```html + <!-- 综合练习3 --> + <input type="button" onclick="btnAddPicture()" value="添加"> + <div id="div1"></div> +``` +```js +// 综合练习3 +function btnAddPicture() { + let img = ["./OIP-C.webp", "./OIP-C2.webp", "OIP-C3.jpg", "OIP-C4.webp", "OIP-C5.jpg"]; + let imgContainer = document.getElementById("div1"); + imgContainer.innerHTML = ""; + for (let i = 0; i < img.length; i++) { + + setTimeout(() => { + console.log(i); + let addimg = document.createElement("img"); + addimg.style.width = "100px" + // addimg.style.height = "100px" + addimg.src = img[i]; + document.getElementById("div1").appendChild(addimg); + if (i == img.length - 1) { + + setTimeout(() => { + btnAddPicture(); + }, 1000); + } + }, i * 1000); + } + + +} +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251208-\346\270\270\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\351\203\255\345\260\217\344\270\234/20251208-\346\270\270\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..d2a169bfc7a467a01773e0bbbb33dab85d920123 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251208-\346\270\270\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,292 @@ +# 笔记 + +## 一、BOM 概述 + +### 1. 定义 + +BOM(Browser Object Model,浏览器对象模型)是用于操作浏览器窗口及浏览器组件的 API 集合,**无官方统一标准**(不同浏览器略有差异),核心作用是与浏览器本身交互(而非页面内容)。 + +### 2. BOM 与 DOM 的区别 + +| 维度 | BOM(浏览器对象模型) | DOM(文档对象模型) | +| -------- | ------------------------------------ | ------------------------------------ | +| 操作对象 | 浏览器窗口、地址栏、历史记录等 | 页面 HTML/XML 文档内容(标签、文本) | +| 核心对象 | window(顶级)、location、history 等 | document(根节点)、element、node 等 | +| 标准 | 无统一标准,浏览器自定义实现 | W3C 标准化,跨浏览器兼容性好 | +| 示例操作 | 页面跳转、弹窗、获取浏览器信息 | 新增标签、修改样式、绑定事件 | + +## 二、BOM 核心对象 + +### 1. window 对象(核心) + +`window` 是 BOM 的顶级对象,代表浏览器窗口,**所有全局变量 / 函数都是 window 的属性 / 方法**(可省略 `window.` 直接调用)。 + +#### 核心属性 + +| 属性名 | 说明 | 示例 | +| ------------------------ | ----------------------------------------- | --------------------------------------- | +| `document` | 指向 DOM 的根对象,操作页面内容 | `window.document.getElementById('box')` | +| `location` | 管理当前页面 URL 信息 | `window.location.href` | +| `navigator` | 获取浏览器 / 系统信息 | `window.navigator.userAgent` | +| `history` | 管理浏览器历史记录 | `window.history.back()` | +| `screen` | 获取屏幕显示信息 | `window.screen.width` | +| `innerWidth/innerHeight` | 浏览器视口(可视区域)宽 / 高(不含边框) | `console.log(window.innerWidth)` | + +#### 核心方法 + +| 方法名 | 说明 | 示例 | +| --------------------------- | ----------------------------------------------- | ------------------------------------------------------------ | +| `alert(msg)` | 弹出提示框(无返回值) | `alert('操作成功')` | +| `confirm(msg)` | 弹出确认框(返回布尔值:确认→true,取消→false) | `let res = confirm('确定删除?');` | +| `prompt(msg, default)` | 弹出输入框(返回输入内容 /null) | `let name = prompt('请输入姓名', '张三');` | +| `open(url, name, params)` | 打开新窗口(params:宽高 / 位置等) | `window.open('https://www.baidu.com', '_blank', 'width=500,height=300')` | +| `close()` | 关闭当前窗口(仅对 `open` 打开的窗口有效) | `window.close()` | +| `setTimeout(fn, delay)` | 一次性定时器(delay:毫秒) | `let timer = setTimeout(() => {console.log('1秒后执行')}, 1000);` | +| `clearTimeout(timer)` | 清除一次性定时器 | `clearTimeout(timer)` | +| `setInterval(fn, interval)` | 循环定时器 | `let timer = setInterval(() => {console.log('每秒执行')}, 1000);` | +| `clearInterval(timer)` | 清除循环定时器 | `clearInterval(timer)` | + +### 2. location 对象 + +`window.location`(可简写为 `location`)用于管理当前页面的 URL 信息,支持跳转、刷新等操作。 + +#### 核心属性(URL 拆解示例:`https://www.baidu.com:8080/search?name=张三#top`) + +| 属性名 | 说明 | 示例值 | +| ---------- | ------------------ | ------------------------------------------------- | +| `href` | 完整 URL | `https://www.baidu.com:8080/search?name=张三#top` | +| `protocol` | 协议(含 `://`) | `https:` | +| `host` | 主机 + 端口 | `www.baidu.com:8080` | +| `hostname` | 主机(不含端口) | `www.baidu.com` | +| `port` | 端口号 | `8080` | +| `pathname` | 路径 | `/search` | +| `search` | 查询参数(含 `?`) | `?name=张三` | +| `hash` | 哈希锚点(含 `#`) | `#top` | + +#### 核心方法 + +| 方法名 | 说明 | 示例 | +| --------------- | ---------------------------------------- | ------------------------------------------- | +| `assign(url)` | 跳转到指定 URL(保留历史记录,可后退) | `location.assign('https://www.baidu.com')` | +| `replace(url)` | 替换当前 URL(无历史记录,不可后退) | `location.replace('https://www.baidu.com')` | +| `reload(force)` | 刷新页面(force=true:强制从服务器刷新) | `location.reload(true)` | + +#### 实战示例:解析 URL 查询参数 + +javascript + + + +运行 + + + + + + + + + +```javascript +// 解析 ?name=张三&age=18 为对象 {name: '张三', age: '18'} +function getUrlParams() { + const params = {}; + const search = location.search.slice(1); // 去掉?,得到name=张三&age=18 + if (!search) return params; + search.split('&').forEach(item => { + const [key, value] = item.split('='); + params[key] = decodeURIComponent(value); // 解码中文 + }); + return params; +} +console.log(getUrlParams()); // {name: '张三', age: '18'} +``` + +### 3. navigator 对象 + +`window.navigator`(可简写为 `navigator`)用于获取浏览器、操作系统、设备等信息。 + +#### 核心属性 + +| 属性名 | 说明 | 示例 | +| ----------- | ----------------------------------- | --------------------- | +| `userAgent` | 用户代理字符串(浏览器 / 系统标识) | `navigator.userAgent` | +| `language` | 浏览器默认语言(如 zh-CN) | `navigator.language` | +| `platform` | 操作系统平台(如 Win32、MacIntel) | `navigator.platform` | + +#### 实战示例:判断浏览器类型 + +javascript + + + +运行 + + + + + + + + + +```javascript +// 判断是否为 Chrome 浏览器 +function isChrome() { + return /Chrome/.test(navigator.userAgent) && !/Edge/.test(navigator.userAgent); +} +console.log(isChrome()); // true/false +``` + +### 4. history 对象 + +`window.history`(可简写为 `history`)用于管理浏览器的会话历史记录(仅能操作,无法获取具体 URL)。 + +#### 核心方法 + +| 方法名 | 说明 | 示例 | +| ----------- | --------------------------------------------------------- | ---------------------------- | +| `back()` | 后退一页(等同于浏览器后退按钮) | `history.back()` | +| `forward()` | 前进一页(等同于浏览器前进按钮) | `history.forward()` | +| `go(n)` | 跳转指定步数(n>0:前进 n 页;n<0:后退 n 页;n=0:刷新) | `history.go(-1)` // 后退一页 | + +### 5. screen 对象 + +`window.screen`(可简写为 `screen`)用于获取设备屏幕的显示信息。 + +#### 核心属性 + +| 属性名 | 说明 | 示例 | +| ------------------------ | ------------------------------------- | ------------------------------- | +| `width/height` | 屏幕总分辨率(宽 / 高) | `screen.width` // 如 1920 | +| `availWidth/availHeight` | 屏幕可用分辨率(不含任务栏 / 状态栏) | `screen.availHeight` // 如 1080 | + +## 三、BOM 常用实战场景 + +### 1. 弹窗交互(确认 + 输入) + +javascript + + + +运行 + + + + + + + + + +```javascript +// 确认删除并输入原因 +function deleteConfirm() { + const isConfirm = confirm('确定要删除这条记录吗?'); + if (isConfirm) { + const reason = prompt('请输入删除原因(选填)', ''); + if (reason !== null) { // 取消输入返回null + alert(`删除成功!原因:${reason || '无'}`); + } + } +} +deleteConfirm(); +``` + +### 2. 页面倒计时跳转 + +javascript + + + +运行 + + + + + + + + + +```javascript +// 5秒后跳转到首页 +let count = 5; +const timer = setInterval(() => { + count--; + if (count <= 0) { + clearInterval(timer); + location.href = '/index.html'; + } + console.log(`${count}秒后跳转...`); +}, 1000); +``` + +### 3. 判断移动端 / PC 端 + +javascript + + + +运行 + + + + + + + + + +```javascript +function isMobile() { + return /Mobile|Android|iOS|iPhone|iPad|iPod/.test(navigator.userAgent); +} +if (isMobile()) { + alert('当前为移动端访问'); +} else { + alert('当前为PC端访问'); +} +``` + +## 四、注意事项 + +1. **兼容性问题**:BOM 无统一标准,部分 API(如 `userAgent` 格式、`open` 方法参数)在不同浏览器(如 IE/Chrome/Firefox)中表现有差异,需做兼容处理。 + +2. 全局作用域 + + : + + - `var` 声明的全局变量 / 函数会成为 `window` 的属性; + - `let/const` 声明的全局变量不会挂载到 `window` 上。 + + javascript + + + + 运行 + + + + + + + + + + ```javascript + var a = 1; + let b = 2; + console.log(window.a); // 1 + console.log(window.b); // undefined + ``` + + + +3. **弹窗拦截**:浏览器会拦截非用户触发的 `window.open`(如直接在脚本中调用),需绑定到点击 / 触摸等用户事件中。 + +4. **定时器精度**:`setTimeout/setInterval` 受主线程阻塞影响,并非绝对精确(延迟时间≥设置值)。 + +5. **窗口操作限制**:`close` 方法仅能关闭由 `open` 打开的窗口,无法关闭用户手动打开的浏览器窗口。 + +6. **安全限制**:部分 BOM API(如 `history`、`location`)受同源策略限制,跨域无法操作。 \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251210-Style\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251210-Style\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..8f4ec689fd099a94314022d3d395146d14f22f68 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251210-Style\345\257\271\350\261\241.md" @@ -0,0 +1,336 @@ + +# 笔记 +## 一、Style 对象概述 +### 1. 定义 +Style 对象是 JavaScript 操作 DOM 元素**行内样式(inline style)** 的核心接口,对应 HTML 元素的 `style` 属性。通过 Style 对象可动态读取/修改元素的 CSS 样式,所有样式属性均为可读可写。 + +### 2. 核心特点 +| 特性 | 说明 | +|--------------|----------------------------------------------------------------------| +| 操作范围 | 仅作用于元素的行内样式(`style="xxx"`),不包含外部样式表/内嵌样式的样式 | +| 属性命名 | 驼峰命名法(对应 CSS 的短横线命名),如 `css` 的 `background-color` → `js` 的 `backgroundColor` | +| 取值格式 | 所有属性值均为字符串,且需包含单位(如 `10px`、`red`、`50%`)| +| 优先级 | 行内样式优先级最高(高于 CSS 选择器),会覆盖同名的外部/内嵌样式 | + +### 3. Style 对象 vs getComputedStyle +| 对比维度 | Style 对象 | window.getComputedStyle() | +|----------------|-------------------------------------|------------------------------------| +| 操作类型 | 读写(可修改样式)| 只读(仅获取最终生效的样式)| +| 样式范围 | 仅行内样式 | 所有样式(行内/内嵌/外部)| +| 返回值格式 | 带单位的字符串(如 `20px`)| 带单位的字符串(如 `20px`)| +| 适用场景 | 动态修改元素样式 | 获取元素最终渲染的样式值 | + +## 二、Style 对象核心用法 +### 1. 获取 Style 对象 +通过 DOM 元素的 `style` 属性直接获取,语法: +```javascript +// 获取元素 +const elem = document.getElementById("box"); +// 获取 Style 对象(可直接操作) +const elemStyle = elem.style; +``` + +### 2. 样式属性命名规则 +CSS 样式属性名含短横线的,需转为**驼峰命名**;无短横线的直接使用: + +| CSS 属性名 | Style 对象属性名 | 示例 | +|---------------------|------------------------|-------------------------------| +| `width` | `width` | `elem.style.width = "100px"` | +| `background-color` | `backgroundColor` | `elem.style.backgroundColor = "red"` | +| `font-size` | `fontSize` | `elem.style.fontSize = "16px"` | +| `border-radius` | `borderRadius` | `elem.style.borderRadius = "8px"` | +| `text-align` | `textAlign` | `elem.style.textAlign = "center"` | +| `margin-top` | `marginTop` | `elem.style.marginTop = "5px"` | + +### 3. 读取/修改样式 +#### (1)修改样式(核心) +直接给 Style 对象的属性赋值(值为带单位的字符串): +```javascript +const box = document.getElementById("box"); +// 基础样式 +box.style.width = "200px"; +box.style.height = "100px"; +box.style.backgroundColor = "#f5f5f5"; +// 复合样式(需拆分,Style 对象不支持复合写法) +// ❌ 错误:不支持 "border: 1px solid #000" 复合写法 +box.style.border = "1px solid #000"; // 部分浏览器兼容,但不推荐 +// ✅ 推荐拆分写法 +box.style.borderWidth = "1px"; +box.style.borderStyle = "solid"; +box.style.borderColor = "#000"; +// 特殊样式(如 transform) +box.style.transform = "rotate(10deg)"; +box.style.transition = "all 0.3s ease"; +``` + +#### (2)读取样式(仅行内样式) +```javascript +// 仅能读取通过 style 设置的行内样式,无行内样式则返回空字符串 +console.log(box.style.width); // "200px"(已设置) +console.log(box.style.color); // ""(未设置行内样式) +``` + +#### (3)获取最终生效的样式(含非行内) +需结合 `window.getComputedStyle()`: +```javascript +// 获取最终渲染的样式(只读) +const computedStyle = window.getComputedStyle(box); +console.log(computedStyle.width); // "200px" +console.log(computedStyle.color); // "#333"(来自外部样式表) +// 转为数字(去除单位) +const widthNum = parseInt(computedStyle.width); // 200 +const heightNum = parseFloat(computedStyle.height); // 100 +``` + +### 4. 清除样式 +#### (1)清空单个样式 +赋值为空字符串: +```javascript +box.style.backgroundColor = ""; // 清除背景色行内样式,恢复默认/外部样式 +``` + +#### (2)清空所有行内样式 +使用 `removeAttribute` 移除 `style` 属性: +```javascript +box.removeAttribute("style"); // 清空所有行内样式 +``` + +## 三、Style 对象常用属性分类 +### 1. 布局相关属性 +| Style 属性名 | 说明 | 示例值 | +|--------------------|--------------------|-----------------------| +| `width/height` | 宽/高 | `"100px"`、`"50%"` | +| `minWidth/minHeight` | 最小宽/高 | `"50px"` | +| `maxWidth/maxHeight` | 最大宽/高 | `"300px"` | +| `margin/marginTop/marginRight/marginBottom/marginLeft` | 外边距 | `"10px"`、`"5px 10px"` | +| `padding/paddingTop/paddingRight/paddingBottom/paddingLeft` | 内边距 | `"8px"` | +| `display` | 显示方式 | `"block"`、`"none"`、`"flex"`、`"inline-block"` | +| `position` | 定位方式 | `"static"`、`"relative"`、`"absolute"`、`"fixed"`、`"sticky"` | +| `top/left/right/bottom` | 定位偏移量 | `"20px"`、`"0"` | +| `zIndex` | 层级 | `"999"`、`"1"` | +| `float` | 浮动 | `"left"`、`"right"`、`"none"` | +| `clear` | 清除浮动 | `"both"`、`"left"` | + +### 2. 视觉样式属性 +| Style 属性名 | 说明 | 示例值 | +|--------------------|--------------------|-----------------------| +| `backgroundColor` | 背景色 | `"red"`、`"#fff"`、`"rgba(0,0,0,0.5)"` | +| `backgroundImage` | 背景图 | `"url('bg.jpg')"` | +| `color` | 文字颜色 | `"#333"`、`"white"` | +| `border` | 边框(复合)| `"1px solid #000"` | +| `borderRadius` | 圆角 | `"8px"`、`"50%"`(圆形) | +| `boxShadow` | 盒子阴影 | `"0 2px 8px rgba(0,0,0,0.2)"` | +| `opacity` | 透明度(0-1)| `"0.8"` | +| `cursor` | 鼠标光标 | `"pointer"`、`"move"`、`"default"` | + +### 3. 文字/字体属性 +| Style 属性名 | 说明 | 示例值 | +|--------------------|--------------------|-----------------------| +| `fontSize` | 字体大小 | `"14px"`、`"1.2rem"` | +| `fontWeight` | 字体粗细 | `"normal"`、`"bold"`、`"600"` | +| `fontFamily` | 字体 | `"微软雅黑, sans-serif"` | +| `textAlign` | 文字对齐 | `"left"`、`"center"`、`"right"` | +| `textDecoration` | 文字装饰 | `"none"`、`"underline"`、`"line-through"` | +| `lineHeight` | 行高 | `"20px"`、`"1.5"` | + +### 4. 变换/过渡属性 +| Style 属性名 | 说明 | 示例值 | +|--------------------|--------------------|-----------------------| +| `transform` | 变换 | `"rotate(10deg)"`、`"scale(1.2)"`、`"translateX(20px)"` | +| `transition` | 过渡 | `"all 0.3s ease"`、`"backgroundColor 0.5s"` | +| `animation` | 动画 | `"fade 1s infinite"` | + +## 四、实战示例 +### 1. 动态修改元素样式(鼠标悬浮效果) +```javascript +const btn = document.getElementById("btn"); +// 鼠标悬浮 +btn.addEventListener("mouseover", () => { + btn.style.backgroundColor = "#007bff"; + btn.style.color = "white"; + btn.style.cursor = "pointer"; + btn.style.transform = "scale(1.05)"; +}); +// 鼠标离开 +btn.addEventListener("mouseout", () => { + btn.style.backgroundColor = ""; + btn.style.color = ""; + btn.style.transform = ""; +}); +``` + +### 2. 批量设置列表项样式 +```javascript +const liItems = document.querySelectorAll("li"); +liItems.forEach((li, index) => { + // 基础样式 + li.style.paddingLeft = "10px"; + li.style.margin = "5px 0"; + li.style.borderRadius = "0 10px 10px 0"; + // 交替背景色 + li.style.backgroundColor = index % 2 === 0 ? "#f0f0f0" : "#fff"; +}); +``` + +### 3. 获取元素最终样式并计算偏移 +```javascript +const box = document.getElementById("box"); +// 获取最终样式 +const computed = window.getComputedStyle(box); +// 计算元素实际宽度(含内边距,不含边框) +const innerWidth = parseInt(computed.width); +const paddingLeft = parseInt(computed.paddingLeft); +const paddingRight = parseInt(computed.paddingRight); +const actualWidth = innerWidth + paddingLeft + paddingRight; +console.log(`元素实际内容宽度:${actualWidth}px`); +``` + +### 4. 动态调整文本框高度 +```javascript +const textarea = document.getElementById("textarea"); +const increaseBtn = document.getElementById("increaseBtn"); +// 增高按钮 +increaseBtn.addEventListener("click", () => { + const currentHeight = parseInt(window.getComputedStyle(textarea).height); + textarea.style.height = (currentHeight + 50) + "px"; +}); +``` + +## 五、注意事项 +1. **单位必须加**:所有数值型样式(如 width、margin)必须带单位(px/%/rem 等),否则无效: + ```javascript + box.style.width = 100; // ❌ 无效(无单位) + box.style.width = "100px"; // ✅ 有效 + ``` +2. **复合样式慎用**:Style 对象对 `border`、`background` 等复合样式的支持不一致,推荐拆分为单个属性(如 `borderWidth`、`borderColor`)。 +3. **优先级问题**:行内样式优先级最高,若需覆盖 Style 对象设置的样式,需在 CSS 中使用 `!important`,或直接清空行内样式。 +4. **CSS 变量操作**:可通过 `style.setProperty`/`style.getPropertyValue` 操作 CSS 变量: + ```javascript + // 设置 CSS 变量 + box.style.setProperty("--main-color", "blue"); + // 读取 CSS 变量 + const mainColor = box.style.getPropertyValue("--main-color"); // "blue" + ``` +5. **兼容性**: + - 部分属性(如 `transform`)在旧版浏览器需加前缀(`webkitTransform`、`mozTransform`); + - `getComputedStyle` 不支持 IE8 及以下,需用 `elem.currentStyle` 兼容。 +6. **空值处理**:读取未设置的行内样式会返回空字符串,需先判断再使用: + ```javascript + const color = box.style.color || "#333"; // 兜底默认值 + ```const color = box.style.color || "#333"; // 兜底默认值 + + +# 练习 + +## 训练1 +```html + +<input type="button" value="放大" onclick="btnEnlarge()"> + <div> + <span id="txt">鸡你太美</span> + </div> +``` +```js +function btnEnlarge() { + let size = 2; + let txt = document.getElementById("txt"); + let currentFontSize = window.getComputedStyle(txt).fontSize; + let fontSizeNum = parseFloat(currentFontSize); + let newFontSize = (fontSizeNum + size) + "px"; + txt.style.fontSize = newFontSize; + + let clior = getComputedStyle(txt).clior; + + + let random1 = Math.floor(Math.random() * 256); + let random2 = Math.floor(Math.random() * 256); + let random3 = Math.floor(Math.random() * 256); + txt.style.clior = `rgb(${random1},${random2},${random3})`; + conslie.log(clior); +} +``` + +## 训练2 +```html + <div id="box2"></div> + +``` +```js +// 训练2 +function cssImg() { + let img = document.createElement('img'); + img.src = "../20251205/OIP-C5.jpg"; + img.style.width = "100px"; + document.getElementById("box2").appendChild(img); + + img.addEventListener('mouseover', function () { + this.style.border = "5px double blue"; + this.style.boxSizing = "border-box"; + }) + + img.addEventListener('mouseout', function () { + this.style.border = 'none'; + }) +} +``` + +## 综合练习1 +```html +<div id="box3"> + <ul id="box3-ul"> + <li>HTML/CSS讨论区</li> + <li>JavaScript讨论区</li> + <li>C语言讨论区</li> + <li>Java讨论区</li> + <li>Android讨论区</li> + <li>Python讨论区</li> + </ul> +</div> +``` +```js +// 训练1 +function btnEnlarge() { + let size = 2; + let txt = document.getElementById("txt"); + let currentFontSize = window.getComputedStyle(txt).fontSize; + let fontSizeNum = parseFloat(currentFontSize); + let newFontSize = (fontSizeNum + size) + "px"; + txt.style.fontSize = newFontSize; + + let clior = getComputedStyle(txt).clior; + + + let random1 = Math.floor(Math.random() * 256); + let random2 = Math.floor(Math.random() * 256); + let random3 = Math.floor(Math.random() * 256); + txt.style.clior = `rgb(${random1},${random2},${random3})`; + conslie.log(clior); +} +``` +## 综合练习2 +```html +<div id="box4"> + <img src="../20251205/OIP-C2.webp" alt="" class="box4-img"> + <img src="../20251205/OIP-C3.jpg" alt="" class="box4-img"> + <img src="../20251205/OIP-C4.webp" alt="" class="box4-img"> + +</div> +``` +```js +// 训练2 +function cssImg() { + let img = document.createElement('img'); + img.src = "../20251205/OIP-C5.jpg"; + img.style.width = "100px"; + document.getElementById("box2").appendChild(img); + + img.addEventListener('mouseover', function () { + this.style.border = "5px double blue"; + this.style.boxSizing = "border-box"; + }) + + img.addEventListener('mouseout', function () { + this.style.border = 'none'; + }) +} +``` diff --git "a/\351\203\255\345\260\217\344\270\234/20251211-Form\345\257\271\350\261\241.md" "b/\351\203\255\345\260\217\344\270\234/20251211-Form\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..0624a059c87e1bf5f95b1768fa40a58935c84ec6 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251211-Form\345\257\271\350\261\241.md" @@ -0,0 +1,588 @@ +# 笔记 +## 一、Form 对象概述 +### 1. 定义 +Form 对象是 JavaScript 操作 HTML 表单(`<form>`)的核心接口,对应页面中的 `<form>` 元素,用于读取/修改表单控件(输入框、单选框、复选框等)的值、监听表单提交事件、验证表单数据等。 + +### 2. 核心特点 +| 特性 | 说明 | +|--------------|----------------------------------------------------------------------| +| 关联元素 | 包含 `<input>`、`<select>`、`<textarea>`、`<button>` 等表单控件 | +| 获取方式 | 可通过 `document.forms`、`getElementById`、`querySelector` 等获取 | +| 控件访问 | 可通过 `form.控件name` 或 `form.elements[控件name/index]` 访问子控件 | +| 核心行为 | 支持表单提交、重置、数据验证等操作 | + +### 3. Form 对象 vs 普通 DOM 元素 +Form 对象继承自普通 DOM 元素,除了拥有 DOM 元素的所有属性/方法外,还新增了表单专属的属性(如 `action`、`method`)和方法(如 `submit()`、`reset()`)。 + +## 二、Form 对象的获取方式 +### 1. 常用获取方法 +```javascript +// 方式1:通过 id 获取(推荐,精准) +const form1 = document.getElementById("myForm"); + +// 方式2:通过 document.forms(按索引/name) +const form2 = document.forms[0]; // 获取页面第一个<form> +const form3 = document.forms["formName"]; // 通过<form>的name属性获取 + +// 方式3:通过 querySelector +const form4 = document.querySelector("form"); // 获取第一个<form> +const form5 = document.querySelector("#myForm"); // 通过id +``` + +### 2. 表单控件的获取 +Form 对象可直接通过「控件 name 属性」或 `elements` 集合访问子控件: +```html +<form id="myForm"> + <input type="text" name="username" id="username"> + <input type="password" name="pwd" id="pwd"> + <input type="checkbox" name="agree" id="agree"> +</form> +``` +```javascript +const form = document.getElementById("myForm"); + +// 方式1:form.控件name(最简洁) +const usernameInput = form.username; +const pwdInput = form.pwd; + +// 方式2:form.elements[控件name/index] +const agreeInput = form.elements["agree"]; +const firstInput = form.elements[0]; // 第一个控件(username) + +// 方式3:普通DOM获取(兼容所有场景) +const usernameInput2 = document.getElementById("username"); +``` + +## 三、Form 对象核心属性 +### 1. 表单本身属性 +| 属性名 | 说明 | 示例 | +|--------------|----------------------------------------|-------------------------------| +| `action` | 表单提交的目标 URL | `form.action = "/api/submit"` | +| `method` | 提交方式(GET/POST,默认GET)| `form.method = "POST"` | +| `enctype` | 表单数据编码方式(如 multipart/form-data 用于文件上传) | `form.enctype = "application/x-www-form-urlencoded"` | +| `target` | 提交后响应的打开方式(_self/_blank/_parent) | `form.target = "_self"` | +| `elements` | 表单内所有控件的集合(HTMLCollection) | `form.elements.length` // 控件数量 | +| `autocomplete` | 是否开启自动补全(on/off)| `form.autocomplete = "off"` | + +### 2. 表单控件通用属性(核心) +所有表单控件(input/select/textarea)均支持以下核心属性: +| 属性名 | 说明 | 适用控件 | +|--------------|----------------------------------------|-------------------------------| +| `value` | 控件的值(读写)| 所有input、select、textarea | +| `checked` | 是否选中(布尔值,读写)| 单选框(radio)、复选框(checkbox) | +| `selected` | 是否选中(布尔值,读写)| select的option选项 | +| `disabled` | 是否禁用(布尔值,读写)| 所有控件 | +| `readonly` | 是否只读(布尔值,读写)| 输入框、文本域 | +| `name` | 控件名称(只读)| 所有控件 | +| `type` | 控件类型(如 text/radio/checkbox)| input控件 | + +## 四、Form 对象核心方法 +### 1. 表单操作方法 +| 方法名 | 说明 | 示例 | +|--------------|----------------------------------------|-------------------------------| +| `submit()` | 提交表单(等同于点击[type="submit"]按钮) | `form.submit()` | +| `reset()` | 重置表单(恢复所有控件默认值)| `form.reset()` | + +### 2. 控件值操作方法 +#### (1)输入框/文本域 +```javascript +// 读取值 +const username = form.username.value; +const desc = form.desc.value; // textarea的值 + +// 修改值 +form.username.value = "默认用户名"; +form.desc.value = "请输入描述..."; + +// 清空值 +form.username.value = ""; +``` + +#### (2)单选框(radio) +```html +<form id="myForm"> + <input type="radio" name="gender" value="male">男 + <input type="radio" name="gender" value="female">女 +</form> +``` +```javascript +const form = document.getElementById("myForm"); +// 读取选中值 +function getRadioValue(name) { + const radios = form.elements[name]; + for (let i = 0; i < radios.length; i++) { + if (radios[i].checked) { + return radios[i].value; + } + } + return ""; // 未选中返回空 +} +console.log(getRadioValue("gender")); // "male"/"female"/"" + +// 设置选中值 +function setRadioValue(name, value) { + const radios = form.elements[name]; + for (let i = 0; i < radios.length; i++) { + radios[i].checked = (radios[i].value === value); + } +} +setRadioValue("gender", "female"); // 选中“女” +``` + +#### (3)复选框(checkbox) +```html +<form id="myForm"> + <input type="checkbox" name="hobby" value="book">读书 + <input type="checkbox" name="hobby" value="sport">运动 + <input type="checkbox" name="hobby" value="music">音乐 +</form> +``` +```javascript +const form = document.getElementById("myForm"); +// 读取所有选中值 +function getCheckboxValues(name) { + const checkboxes = form.elements[name]; + const values = []; + for (let i = 0; i < checkboxes.length; i++) { + if (checkboxes[i].checked) { + values.push(checkboxes[i].value); + } + } + return values; +} +console.log(getCheckboxValues("hobby")); // ["book", "sport"] + +// 设置选中值(批量) +function setCheckboxValues(name, values) { + const checkboxes = form.elements[name]; + for (let i = 0; i < checkboxes.length; i++) { + checkboxes[i].checked = values.includes(checkboxes[i].value); + } +} +setCheckboxValues("hobby", ["book", "music"]); // 选中“读书”“音乐” +``` + +#### (4)下拉框(select) +```html +<form id="myForm"> + <select name="city" id="city"> + <option value="beijing">北京</option> + <option value="shanghai">上海</option> + <option value="guangzhou">广州</option> + </select> +</form> +``` +```javascript +const form = document.getElementById("myForm"); +// 读取选中值 +const cityValue = form.city.value; // "beijing"/"shanghai" +// 读取选中文本 +const cityText = form.city.options[form.city.selectedIndex].text; // "北京" + +// 设置选中值 +form.city.value = "shanghai"; // 选中“上海” + +// 动态添加选项 +const option = document.createElement("option"); +option.value = "shenzhen"; +option.text = "深圳"; +form.city.appendChild(option); +``` + +## 五、表单事件处理 +### 1. 核心事件 +| 事件名 | 触发时机 | 常用场景 | +|--------------|----------------------------------------|-------------------------------| +| `submit` | 表单提交时(点击submit按钮/按回车)| 表单验证、阻止默认提交 | +| `reset` | 表单重置时 | 确认重置、阻止默认重置 | +| `change` | 控件值改变且失去焦点时(如输入框、下拉框) | 实时验证、联动更新 | +| `input` | 控件值实时改变时(输入框/文本域)| 实时搜索、字数统计 | +| `focus` | 控件获取焦点时 | 提示输入规则 | +| `blur` | 控件失去焦点时 | 验证输入内容 | + +### 2. 实战:表单提交验证(阻止默认提交) +```html +<form id="loginForm"> + <div> + <label>用户名:</label> + <input type="text" name="username" placeholder="请输入用户名"> + </div> + <div> + <label>密码:</label> + <input type="password" name="pwd" placeholder="请输入密码"> + </div> + <button type="submit">登录</button> +</form> +``` +```javascript +const loginForm = document.getElementById("loginForm"); + +// 监听表单提交事件 +loginForm.addEventListener("submit", function(e) { + // 阻止默认提交行为(关键,避免页面刷新) + e.preventDefault(); + + // 1. 获取控件值 + const username = this.username.value.trim(); + const pwd = this.pwd.value.trim(); + + // 2. 表单验证 + if (!username) { + alert("请输入用户名!"); + this.username.focus(); // 聚焦到用户名输入框 + return; + } + if (!pwd || pwd.length < 6) { + alert("密码不能为空且长度不少于6位!"); + this.pwd.focus(); + return; + } + + // 3. 验证通过,执行提交逻辑(如AJAX请求) + console.log("提交数据:", { username, pwd }); + // 模拟AJAX提交 + // fetch("/api/login", { + // method: "POST", + // body: JSON.stringify({ username, pwd }) + // }).then(res => res.json()).then(data => { + // console.log("登录结果:", data); + // }); +}); +``` + +### 3. 实战:实时输入验证(input事件) +```html +<form id="registerForm"> + <div> + <label>手机号:</label> + <input type="text" name="phone" placeholder="请输入11位手机号"> + <span id="phoneTip"></span> + </div> +</form> +``` +```javascript +const registerForm = document.getElementById("registerForm"); +const phoneInput = registerForm.phone; +const phoneTip = document.getElementById("phoneTip"); + +// 实时监听输入 +phoneInput.addEventListener("input", function() { + const phone = this.value.trim(); + const phoneReg = /^1[3-9]\d{9}$/; // 手机号正则 + + if (!phone) { + phoneTip.textContent = "请输入手机号"; + phoneTip.style.color = "#999"; + } else if (!phoneReg.test(phone)) { + phoneTip.textContent = "手机号格式错误"; + phoneTip.style.color = "red"; + } else { + phoneTip.textContent = "手机号格式正确"; + phoneTip.style.color = "green"; + } +}); +``` + +## 六、实战示例 +### 1. 全选/全不选/反选复选框 +```html +<form id="hobbyForm"> + <input type="checkbox" name="hobby" value="1">游泳 + <input type="checkbox" name="hobby" value="2">跑步 + <input type="checkbox" name="hobby" value="3">健身 + <br> + <button type="button" onclick="selectAll()">全选</button> + <button type="button" onclick="selectNone()">全不选</button> + <button type="button" onclick="selectOpposite()">反选</button> +</form> +``` +```javascript +const hobbyForm = document.getElementById("hobbyForm"); +const hobbies = hobbyForm.elements["hobby"]; + +// 全选 +function selectAll() { + for (let i = 0; i < hobbies.length; i++) { + hobbies[i].checked = true; + } +} + +// 全不选 +function selectNone() { + for (let i = 0; i < hobbies.length; i++) { + hobbies[i].checked = false; + } +} + +// 反选 +function selectOpposite() { + for (let i = 0; i < hobbies.length; i++) { + hobbies[i].checked = !hobbies[i].checked; + } +} +``` + +### 2. 省市二级联动下拉框 +```html +<form id="addressForm"> + <label>省份:</label> + <select name="province" id="province"></select> + <label>城市:</label> + <select name="city" id="city"></select> +</form> +``` +```javascript +const addressForm = document.getElementById("addressForm"); +// 省市数据 +const provinceCityData = { + "请选择省份": [], + "北京市": ["东城区", "西城区", "朝阳区"], + "上海市": ["黄浦区", "徐汇区", "长宁区"], + "广东省": ["广州市", "深圳市", "东莞市"] +}; + +// 初始化省份下拉框 +function initProvince() { + const provinceSelect = addressForm.province; + for (let p in provinceCityData) { + const option = document.createElement("option"); + option.value = p; + option.text = p; + provinceSelect.appendChild(option); + } +} + +// 监听省份变化,更新城市 +addressForm.province.addEventListener("change", function() { + const citySelect = addressForm.city; + citySelect.innerHTML = ""; // 清空原有选项 + const cities = provinceCityData[this.value]; + cities.forEach(city => { + const option = document.createElement("option"); + option.value = city; + option.text = city; + citySelect.appendChild(option); + }); +}); + +// 初始化 +initProvince(); +``` + +## 七、注意事项 +1. **表单提交阻止默认行为**:监听 `submit` 事件时,必须调用 `e.preventDefault()` 阻止页面刷新,否则无法执行自定义提交逻辑(如AJAX)。 +2. **控件name属性**:通过 `form.控件name` 访问控件时,`name` 属性是关键(id可选),且同一组单选框/复选框需共用一个 `name`。 +3. **空值处理**:读取输入框值时,建议用 `trim()` 去除首尾空格,避免空字符串干扰验证。 +4. **禁用控件值**:禁用(`disabled=true`)的控件,其值不会随表单提交(无论手动提交还是默认提交)。 +5. **文件上传**:表单包含 `<input type="file">` 时,需设置 `form.enctype = "multipart/form-data"` 且提交方式为 `POST`。 +6. **兼容性**: + - 旧版IE中,`form.elements` 集合的遍历方式需注意(需用 `for` 循环,而非 `forEach`); + - `input` 事件在IE9以下不支持,可改用 `keyup` 事件兼容。 +7. **安全验证**:前端表单验证仅为用户体验优化,**后端必须重新验证**所有数据,防止恶意提交。 + + +# 练习 + +## 训练1 +```html +<!-- 训练1 --> +<div id="box1"> + <input type="text" id="box1-txt" value="" placeholder="99632570063166"> + <input type="button" value="验证" onclick="btnVerify()"> +</div> +``` +```js +// 训练1 +function btnVerify() { + let txt = document.getElementById("box1-txt").value; + let movieTicket = 99632570063166; + console.log(txt); + if (txt == "") { + alert("请输入兑换码") + } else if (txt == movieTicket) { + alert("取票成功"); + } else { + alert("兑换码错误"); + } +} +``` +## 训练2 +```html +<!-- 训练2 --> +<div id="box2"> + <input type="button" onclick="btnIncrease()" value="增加"> + <input type="button" onclick="btnReduce()" value="减少"> + <textarea name="" id="box2-txt"></textarea> +</div> +``` +```js +// 训练2 +let textarea = document.getElementById('box2-txt'); +let addHeight = 50; +function btnIncrease() { + let currentHeight = parseInt(window.getComputedStyle(textarea).height); + textarea.style.height = (currentHeight + addHeight) + "px"; +} +function btnReduce() { + let currentHeight = parseInt(window.getComputedStyle(textarea).height); + textarea.style.height = (currentHeight - addHeight) + "px"; +} +``` +## 训练3 +```html +<!-- 训练3 --> +<div id="box3"> + <h3>请选择课程</h3> + <input type="radio" name="C语言" id="box3-radio">C语言 + <br><input type="radio" name="机械制图" id="box3-radio">机械制图 + <br><input type="radio" name="单片机" id="box3-radio">单片机 + <br><input type="radio" name="自动控制" id="box3-radio">自动控制 + <br><input type="radio" name="传感器" id="box3-radio">传感器 + <br><input type="radio" name="高等数学" id="box3-radio">高等数学 + <br><input type="radio" name="计算机基础" id="box3-radio">计算机基础 + <br><input type="radio" name="Oracle数据库" id="box3-radio">Oracle数据库 + <br><input type="radio" name="商务英语" id="box3-radio">商务英语 + <br><input type="radio" name="PLC设计基础" id="box3-radio">PLC设计基础 +</div> +``` +```js +// 训练3 +let radioList = document.querySelectorAll("#box3-radio"); +radioList.forEach(radioaa =>{ + radioaa.addEventListener("click",function(e){ + let checkedCount = document.querySelectorAll('#box3-radio:checked').length; + if(checkedCount > 6){ + e.preventDefault(); + this.checked = false; + alert('最多选6个'); + } + }) +}) +console.log(radio); +``` +## 综合练习1 +```html +<!-- 综合练习1 --> +<div id="box1"> + <h3>电影《变相怪杰》的主演是谁?</h3> + <input type="radio" name="box1-radio" value="布拉德·皮特">布拉德·皮特 + <input type="radio" name="box1-radio" value="亚当·桑德勒">亚当·桑德勒 + <input type="radio" name="box1-radio" value="金·凯瑞">金·凯瑞 + <input type="radio" name="box1-radio" value="杰夫·丹尼尔斯">杰夫·丹尼尔斯 + <br><input type="button" value="提交答案" onclick="btnSubmit()"> + <p id="txt"></p> +</div> +``` +```js +// 综合练习1 +function btnSubmit() { + let radio = document.querySelectorAll("input[name='box1-radio']"); + let radioValue = null; + for (let i = 0; i < radio.length; i++) { + //核心:判断当前单选框是否被选中 + if (radio[i].checked) { + radioValue = radio[i].value; + console.log(radio[i]); + break; + } + } + let txt = document.getElementById("txt"); + + if (radioValue === "金·凯瑞") { + txt.innerText = "答案正确"; + document.getElementById("box1").appendChild(txt); + + } else if (!radioValue) { + txt.innerText = "请选择一个答案"; + document.getElementById("box1").appendChild(txt); + } else { + txt.innerText = "答案错误"; + document.getElementById("box1").appendChild(txt); + } +} +``` +## 综合练习2 +```html +<div id="box2"> + <input type="checkbox" name="box2-radio">不想写了 + <input type="checkbox" name="box2-radio">我不想写了 + <input type="checkbox" name="box2-radio">我真不想写了 + <input type="checkbox" name="box2-radio">我真的不想写了 + <input type="checkbox" name="box2-radio">我是真的不想写了 + <input type="button" value="全选" onclick="btnSelectAll()"> + <input type="button" value="全不选" onclick="btnSelectNone()"> + <input type="button" value="反选" onclick="btnOppose()"> +</div> +``` +```js +// 综合练习2 +let getCheck = document.querySelectorAll("input[name='box2-radio']"); +function btnSelectAll() { + getCheck.forEach(checkbox => { + checkbox.checked = true; + }) +} +function btnSelectNone() { + getCheck.forEach(checkbox => { + checkbox.checked = false; + }) +} +function btnOppose() { + getCheck.forEach(checkbox => { + checkbox.checked = !checkbox.checked; + }) +} +``` +## 综合练习3 +```html +<!-- 综合练习3 --> +<select name="" id="provinceSelect"> +</select> +<select name="" id="citySelect"> +</select> +``` +```js +// 综合练习3 + +let provinceCityData = { + "请选择省份": [], // 默认空选项 + "北京市": ["东城区", "西城区", "朝阳区", "海淀区", "丰台区"], + "上海市": ["黄浦区", "徐汇区", "长宁区", "静安区", "普陀区"], + "广东省": ["广州市", "深圳市", "东莞市", "佛山市", "中山市"], + "江苏省": ["南京市", "苏州市", "无锡市", "常州市", "扬州市"], + "浙江省": ["杭州市", "宁波市", "温州市", "嘉兴市", "绍兴市"] +}; + +let provinceSelect = document.getElementById("provinceSelect"); +let citySelect = document.getElementById("citySelect"); + +function intprovince() { + for (let province in provinceCityData) { + let option = document.createElement("option"); + option.value = province; + option.textContent = province; + provinceSelect.appendChild(option); + } +} +function updateCity(province) { + citySelect.innerHTML = ""; + let cities = provinceCityData[province]; + cities.forEach(city => { + let option = document.createElement("option"); + option.value = city; + option.textContent = city; + citySelect.appendChild(option); + }) +} +provinceSelect.addEventListener("change", function () { + // 获取当前选中的省份 + let selectedProvince = this.value; + // 更新城市下拉框 + updateCity(selectedProvince); +}); + +// 6. 初始化页面(加载省份+默认显示空城市) +intprovince(); +// 初始选中“请选择省份”,城市框为空 +updateCity("请选择省份"); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251212-JSON\347\254\224\350\256\260.md" "b/\351\203\255\345\260\217\344\270\234/20251212-JSON\347\254\224\350\256\260.md" new file mode 100644 index 0000000000000000000000000000000000000000..ec6bf35adea82c4fc522a6a476775b57346aadf5 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251212-JSON\347\254\224\350\256\260.md" @@ -0,0 +1,293 @@ +# 笔记 +## 一、JSON 概述 +### 1. 定义 +JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种**轻量级、跨平台、易读易写**的数据交换格式,基于 JavaScript 对象语法,但独立于编程语言(几乎所有编程语言都支持解析和生成 JSON)。 + +### 2. 核心特点 +| 特性 | 说明 | +|--------------|----------------------------------------------------------------------| +| 数据格式 | 纯文本字符串,便于网络传输和存储 | +| 语法简洁 | 基于键值对(key-value)和数组,结构清晰易理解 | +| 跨平台兼容 | 与编程语言无关,Python/Java/PHP 等均支持解析/生成 | +| 数据类型有限 | 仅支持 6 种基础数据类型(字符串、数字、布尔值、数组、对象、null) | +| 无注释 | 标准 JSON 不支持注释(部分解析器支持非标准注释,但不推荐) | +| 键名需引号 | 键名必须用双引号包裹(单引号或无引号均不合法) | + +### 3. JSON 与 JavaScript 对象的区别 +| 对比维度 | JSON | JavaScript 对象 | +|----------------|--------------------------------|--------------------------------| +| 本质 | 文本字符串(数据交换格式) | 内存中的对象(编程语言结构) | +| 键名要求 | 必须用双引号包裹 | 可省略引号,支持单引号/双引号 | +| 数据类型 | 仅支持 6 种基础类型(无函数、日期等) | 支持函数、日期、undefined 等 | +| 语法细节 | 无尾逗号,不支持注释 | 可加尾逗号,支持注释 | +| 转换方式 | `JSON.parse()`(JSON→JS对象) | `JSON.stringify()`(JS对象→JSON) | +| 示例 | `{"name":"张三","age":20}` | `{name:"张三", age:20, say:()=>{}}` | + +## 二、JSON 语法规则(必记) +### 1. 基础语法框架 +JSON 数据要么是**键值对集合(对象)**,要么是**值的有序列表(数组)**,整体为一个完整的字符串: +```json +// 对象形式(最常用) +{ + "key1": "value1", + "key2": value2, + "key3": [value1, value2], + "key4": {"subKey": "subValue"} +} + +// 数组形式 +["value1", 123, true, {"key": "value"}] +``` + +### 2. 核心语法规则(严格遵守) +1. **键名必须用双引号**:`"name": "张三"`(正确),`name: "张三"`/`'name': "张三"`(错误); +2. **字符串值必须用双引号**:`"title": "JSON笔记"`(正确),`"title": 'JSON笔记'`(错误); +3. **数值类型无需引号**:支持整数、浮点数、负数,如 `"age": 20`、`"score": 95.5`、`"num": -10`; +4. **布尔值为小写**:仅支持 `true`/`false`(小写),`True`/`False`(错误); +5. **空值为 null**:表示空数据,`"address": null`(`undefined` 不是合法 JSON 类型); +6. **无尾逗号**:最后一个键值对/数组元素后不能加逗号,如 `{"a":1, "b":2,}`(错误); +7. **不支持复杂类型**:函数、日期、正则、undefined 均不合法(需转换为字符串/数值存储)。 + +### 3. 合法 JSON 示例 +```json +{ + "name": "张三", + "age": 25, + "isStudent": false, + "hobbies": ["读书", "运动", "编程"], + "address": { + "province": "广东省", + "city": "深圳市", + "detail": "科技园路" + }, + "score": 92.5, + "gender": null +} +``` + +### 4. 常见语法错误(避坑) +```json +// 错误1:键名无引号 +{name: "张三", "age": 20} → 修正:{"name": "张三", "age": 20} + +// 错误2:字符串用单引号 +{"title": 'JSON笔记'} → 修正:{"title": "JSON笔记"} + +// 错误3:尾逗号 +{"a": 1, "b": 2,} → 修正:{"a": 1, "b": 2} + +// 错误4:布尔值大写 +{"isOk": True} → 修正:{"isOk": true} + +// 错误5:包含函数 +{"say": function() {}} → 修正:移除函数(或转为字符串描述) +``` + +## 三、JSON 支持的数据类型 +| 数据类型 | 说明 | 示例 | +|----------|----------------------------------------|-------------------------------| +| 字符串 | 双引号包裹,支持转义字符(\\"、\\\\、\\n 等) | `"name": "张三\\n年龄20"` | +| 数字 | 整数、浮点数、负数,不支持十六进制 | `"id": 1001, "price": 99.9` | +| 布尔值 | 仅 `true`(真)/`false`(假)(小写) | `"isValid": true` | +| 数组 | 有序值集合,元素可混合不同类型 | `"tags": ["JS", 2024, true]` | +| 对象 | 无序键值对集合,可嵌套其他对象/数组 | `"user": {"name": "李四", "hobbies": []}` | +| null | 表示空值(无数据) | `"address": null` | + +### 转义字符(常用) +| 转义字符 | 含义 | 示例 | JSON 中写法 | +|----------|------------|-----------------------|-------------------| +| `\"` | 双引号 | 包含引号的字符串 | `"title": "He said \"Hello\""` | +| `\\` | 反斜杠 | 文件路径/特殊字符 | `"path": "C:\\Users\\xxx"` | +| `\n` | 换行符 | 多行文本 | `"content": "第一行\n第二行"` | +| `\t` | 制表符 | 缩进对齐 | `"info": "姓名\t年龄"` | + +## 四、JSON 核心操作(JavaScript 环境) +JavaScript 内置 `JSON` 全局对象,提供两个核心方法用于 JSON 与 JS 对象的转换(前端开发最常用)。 + +### 1. JSON.parse():JSON 字符串 → JavaScript 对象 +将 JSON 格式的字符串解析为 JS 对象/数组,语法: +```javascript +JSON.parse(jsonString, [reviver]) +``` +- `jsonString`:必填,合法的 JSON 字符串; +- `reviver`:可选,回调函数(用于解析过程中修改数据)。 + +#### 基础用法 +```javascript +// JSON 字符串 +const jsonStr = `{ + "name": "张三", + "age": 25, + "hobbies": ["读书", "编程"] +}`; + +// 解析为 JS 对象 +const user = JSON.parse(jsonStr); +console.log(user.name); // "张三"(对象属性) +console.log(user.hobbies[0]); // "读书"(数组元素) +console.log(typeof user); // "object" +``` + +#### 进阶用法(reviver 回调) +```javascript +// 解析时修改数据(如转换日期字符串为 Date 对象) +const jsonWithDate = '{"name":"李四","birth":"2000-01-01"}'; +const user2 = JSON.parse(jsonWithDate, (key, value) => { + // 若键为 birth,将字符串转为 Date 对象 + if (key === "birth") { + return new Date(value); + } + return value; // 其他键值不变 +}); +console.log(user2.birth); // Date 对象(Fri Jan 01 2000...) +``` + +### 2. JSON.stringify():JavaScript 对象 → JSON 字符串 +将 JS 对象/数组转换为 JSON 格式字符串,语法: +```javascript +JSON.stringify(value, [replacer], [space]) +``` +- `value`:必填,要转换的 JS 对象/数组; +- `replacer`:可选,过滤/修改要转换的属性(数组或函数); +- `space`:可选,格式化缩进(数字/字符串,提升可读性)。 + +#### 基础用法 +```javascript +// JS 对象 +const product = { + id: 101, + name: "手机", + price: 2999, + isStock: true, + specs: ["128G", "黑色"] +}; + +// 转换为 JSON 字符串 +const productJson = JSON.stringify(product); +console.log(productJson); +// 输出:{"id":101,"name":"手机","price":2999,"isStock":true,"specs":["128G","黑色"]} +console.log(typeof productJson); // "string" +``` + +#### 进阶用法(过滤+格式化) +```javascript +// 1. 过滤属性(只保留 name 和 price) +const json1 = JSON.stringify(product, ["name", "price"]); +console.log(json1); // {"name":"手机","price":2999} + +// 2. 函数过滤(排除价格低于 1000 的商品) +const json2 = JSON.stringify(product, (key, value) => { + if (key === "price" && value < 1000) { + return undefined; // 返回 undefined 则排除该属性 + } + return value; +}); + +// 3. 格式化缩进(4个空格,便于阅读) +const json3 = JSON.stringify(product, null, 4); +console.log(json3); +// 输出格式化后的字符串: +// { +// "id": 101, +// "name": "手机", +// "price": 2999, +// "isStock": true, +// "specs": [ +// "128G", +// "黑色" +// ] +// } +``` + +### 3. 常见转换问题(避坑) +#### (1)JS 对象中的不合法 JSON 类型处理 +JS 对象中的函数、undefined、Date 等类型,转换为 JSON 时会被忽略或转换: +```javascript +const obj = { + name: "张三", + say: () => console.log("Hello"), // 函数:转换时被忽略 + age: undefined, // undefined:转换时被忽略 + birth: new Date() // Date 对象:转换为 ISO 格式字符串 +}; + +console.log(JSON.stringify(obj)); +// 输出:{"name":"张三","birth":"2024-05-20T08:00:00.000Z"} +``` + +#### (2)循环引用报错 +若 JS 对象存在循环引用(A 包含 B,B 包含 A),转换时会报错: +```javascript +const a = { name: "A" }; +const b = { name: "B", ref: a }; +a.ref = b; // 循环引用:a → b → a + +JSON.stringify(a); // 报错:Uncaught TypeError: Converting circular structure to JSON +``` +解决:使用 `replacer` 过滤循环引用,或手动解除循环。 + +## 五、JSON 应用场景 +### 1. 网络数据传输(最核心) +前后端交互时,数据以 JSON 格式传输(替代 XML,更简洁): +- 前端 → 后端:将表单数据/请求参数转为 JSON 字符串,通过 AJAX/fetch 发送; +- 后端 → 前端:将数据库查询结果转为 JSON 字符串,返回给前端后解析为 JS 对象。 + +#### 示例:前端发送 JSON 数据 +```javascript +// 前端请求数据 +const userData = { username: "zhangsan", password: "123456" }; + +fetch("/api/login", { + method: "POST", + headers: { + "Content-Type": "application/json" // 声明数据格式为 JSON + }, + body: JSON.stringify(userData) // 转为 JSON 字符串 +}) +.then(res => res.json()) // 解析后端返回的 JSON +.then(data => console.log("登录结果:", data)); +``` + +### 2. 数据存储 +- 本地存储:`localStorage`/`sessionStorage` 仅支持字符串存储,JSON 可用于存储复杂数据(如用户配置、列表数据); +- 文件存储:配置文件(如 `package.json`)、日志文件等常用 JSON 格式(注:`package.json` 支持注释,是 JSON 的扩展格式)。 + +#### 示例:localStorage 存储 JSON 数据 +```javascript +// 存储:JS 对象 → JSON 字符串 +const userList = [{ id: 1, name: "张三" }, { id: 2, name: "李四" }]; +localStorage.setItem("userList", JSON.stringify(userList)); + +// 读取:JSON 字符串 → JS 对象 +const storedList = JSON.parse(localStorage.getItem("userList")); +console.log(storedList[0].name); // "张三" +``` + +### 3. 配置文件 +众多工具和框架使用 JSON 作为配置文件(简洁易维护): +- Node.js 项目的 `package.json`(项目依赖、脚本配置); +- 前端工程化配置(如 `tsconfig.json`、`eslintrc.json`); +- 工具配置(如 Postman 请求参数、VS Code 插件配置)。 + +#### 示例:package.json(简化版) +```json +{ + "name": "my-project", + "version": "1.0.0", + "dependencies": { + "react": "^18.2.0", + "vue": "^3.3.4" + }, + "scripts": { + "start": "node index.js", + "build": "webpack" + } +} +``` + +## 六、注意事项 +1. **语法严格性**:JSON 语法要求极严格(如双引号、无尾逗号),语法错误会导致解析失败,需仔细检查; +2. **数据类型限制**:避免在 JSON 中存储函数、日期等复杂类型,需转换为字符串/数值后再传输/存储; +3. **注释问题**:标准 JSON 不支持注释,若需添加注释,可使用 JSON5 格式(扩展支持注释、单引号等); +4. **大文件处理**:JSON 适合小/中等规模数据,超大文件(如 100MB+)建议用流处理或其他格式(如 CSV); +5. **安全问题**:前端解析未知 JSON 时,需防范 XSS 攻击(避免直接用 `innerHTML` 渲染 JSON 中的字符串); +6. **兼容性**:`JSON.parse()`/`JSON.stringify()` 支持 IE8+ 及所有现代浏览器,若需兼容更旧浏览器,需引入 `json2.js` 垫片库。 \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251215.md" "b/\351\203\255\345\260\217\344\270\234/20251215.md" new file mode 100644 index 0000000000000000000000000000000000000000..ed4028568ddc7530222958b66f72bd721a4ee503 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251215.md" @@ -0,0 +1,27 @@ +# 练习 + +```js +// jQuery 基础 + // 1 + $(document).ready(function () { + console.log("jQuery 已就绪"); + }); + // 2 + console.log('第二题'); + console.log($ === jQuery); + + // 3 + console.log('第三题'); + let div = $('#demo'); + console.log(div); + + // 4 + console.log('第四题'); + console.log("jQuery对象转DOM对象:", $("#demo")[0]); + console.log("jQuery对象转DOM对象:", $("#demo").get(0)); + console.log("DOM对象转jQuery对象:", $("#demo")); + + // 5 + console.log('第五题'); + console.log($('#box').css('color', 'red').addClass('active').fadeIn()); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251217-jQuery.md" "b/\351\203\255\345\260\217\344\270\234/20251217-jQuery.md" new file mode 100644 index 0000000000000000000000000000000000000000..a192d3a86fba592a268d61c380f432ebbbe23387 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251217-jQuery.md" @@ -0,0 +1,45 @@ +# 笔记 + +## jQuery 基础 +- 是一个js库,为了方便dom操作 +- 和js的引用一样 +- 使用`$`来使用jQuery库的能力,`$`符合实际是一个方法,当然方法在js中也是一个对象,所以其也有一些属性可以使用 +- jQuery获取到的是jQuery,和原生JS拿到的dom对象不同,但它们可以相互转换 + - let div = $('div')拿到jQuery对象 + - div[0]拿到dom对象 + - $(div[0])又可以重新转换为jQuery对象 +## jQuery 选择器与操作 +- 基础选择器 + - 标签选择器 + - 类名选择器 + - id选择器 +- 关系选择器 + - 子代选择器 + - 直接子代选择器 + - 兄弟选择器 + - 相邻兄弟选择器 +- 高级选择器 + - 属性选择器 + - 伪类选择器 + - 伪元素选择器 + +# 练习 + +```js +// jQuery 选择器与操作 + // 1 + $('.item').css('color', 'red'); + // 2 + $("li:first").css('background-color', 'blue'); + $("li:last").css('background-color', 'green'); + // 3 + $("#container").find("span").text("以修改的文本"); + // 4 + $("table tr:nth-child(even)").css("background-color", "yellow"); + // 5 + $(".item2").each(function (index) { + var content = "第" + (index + 1) + "个item"; + $(this).text(content); + }) + +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251218-jQuery.md" "b/\351\203\255\345\260\217\344\270\234/20251218-jQuery.md" new file mode 100644 index 0000000000000000000000000000000000000000..930ed1801a180c8233e62a2497d1ebdbe42a9232 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251218-jQuery.md" @@ -0,0 +1,67 @@ +# 笔记 + +## jQuery 事件处理 +- jQuery对象.on('click',function(){}) +- jQuery对象.click(function(){}) +- jQuery对象.trigger('click',function(){}) +- $(function(){}) + +## jQuery 动画与效果 +- 基础效果:显示、影藏 show()、hide()、toggle() +- 进阶效果:谈入、谈出 fadeIn()、fadeOut() +- 高级效果:animate() + +## jQuery DOM操作 +- 新增 append给拿到元素增加一个下级元素 +- 移除 remove 移除拿到的元素 +- text() 拿到文本内容 ,text('要设置的内容')可以修改纯文本内容 +- html() 拿到包含标签的内容 ,html('要设置的内容')可以修改包含标签的内容 + +# 练习 + +```js +// 事件处理 + // 1 + $("#changeBtn").click(function () { + $("#title").text("新标题"); + }) + // 2 + $("#box").hover(function () { + $(this).css("background", "skyblue"); // 悬停时背景改为天蓝色 + }, function () { + $(this).css("background", "gray"); // 离开时恢复灰色 + }); + // 3 + let itemNum = 2; + $("#addBtn").click(function () { + $("#list").append(`<li>项目${itemNum}</li>`); + itemNum++; + }) + // 4 + $(function () { + $("#myForm").on('submit', function (event) { + // 阻止表单默认提交行为(避免页面刷新) + + event.preventDefault(); + let username = $("#username").val().trim(); + if (username) { + $("#result").text(`用户名为${username}`); + } else { + $("#result").text(`请输入用户名`); + } + + $("#username").val(""); + }) + }) + // 5 + $(function () { + function btnClickHandler() { + alert("小灰灰不是人"); + } + $("#btn").on("click",btnClickHandler); + $("#removeBtn").click(function () { + alert("小灰灰真不是人"); + $("#btn").off("click",btnClickHandler); + }) + }) +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251219.md" "b/\351\203\255\345\260\217\344\270\234/20251219.md" new file mode 100644 index 0000000000000000000000000000000000000000..6d771995f93381f6616b68fee75167280e98eeea --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251219.md" @@ -0,0 +1,37 @@ +# 练习 +## 动画与效果 +```html + <!-- 1 --> + <div id="box">我是一个盒子</div> + <button id="toggleBtn">切换显示</button> + <!-- 2 --> + <img id="image" src="photo.jpg" alt="图片"> + <button id="fadeBtn">淡入淡出</button> +``` +```js + +$(function () { + // 1 + let btnclick = true; + $("#toggleBtn").click(function () { + if (btnclick) { + $("#box").hide(); + + } else { + $("#box").show(); + } + btnclick = !btnclick; + }) + //2 + $("#fadeBtn").click(function () { + + if (btnclick) { + $("image").fadeIn(); + + } else { + $("image").fadeOut(); + } + }) + }) + +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251222-API\346\216\245\345\217\243.md" "b/\351\203\255\345\260\217\344\270\234/20251222-API\346\216\245\345\217\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..6ffcd72fac5a572aa57894cf50391ca04fa477d2 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251222-API\346\216\245\345\217\243.md" @@ -0,0 +1,42 @@ +# 笔记 +## API接入 +### 一、安装 REST Client 插件 +- 打开 VSCode,点击左侧边栏的「扩展」图标(或按下 Ctrl+Shift+X / Cmd+Shift+X)。 +- 在搜索框中输入 REST Client,找到由 Huachao Mao 开发的插件(官方标识:humao.rest-client)。 +- 点击「安装」按钮,安装完成后重启 VSCode 即可生效 +### 二、使用 REST Client 调用 API +- 新建一个后缀为 .http 或 .rest 的文件(比如 test.api.http),这是 REST Client 识别的请求文件格式。 +```html +### 1. GET 请求(带参数) +GET https://api.github.com/users/octocat/repos?page=1&per_page=5 +Accept: application/json + +### 2. POST 请求(JSON 体) +POST https://jsonplaceholder.typicode.com/posts +Content-Type: application/json + +{ + "title": "foo", + "body": "bar", + "userId": 1 +} + +### 3. PUT 请求(更新数据) +PUT https://jsonplaceholder.typicode.com/posts/1 +Content-Type: application/json + +{ + "id": 1, + "title": "updated title", + "body": "updated body", + "userId": 1 +} + +### 4. DELETE 请求 +DELETE https://jsonplaceholder.typicode.com/posts/1 + +### 5. 带请求头/认证的请求(示例:Bearer Token) +GET https://api.example.com/private/data +Authorization: Bearer your_token_here +Content-Type: application/json +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251224-\345\237\272\347\241\200\346\225\260\346\215\256\347\261\273\345\236\213.md" "b/\351\203\255\345\260\217\344\270\234/20251224-\345\237\272\347\241\200\346\225\260\346\215\256\347\261\273\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..4c0e08b7728f6f3b885d8a729f33ea280307f95c --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251224-\345\237\272\347\241\200\346\225\260\346\215\256\347\261\273\345\236\213.md" @@ -0,0 +1,37 @@ +# 笔记 +```JS +// 1 +let name = "张三"; +let school = "某某职业学院"; +console.log(name); +console.log(school); + +// 2 +let value = 123; +console.log(typeof(value)); + +// 3 +let age = 18; +age = 20; +console.log(age); + +// 4 +let name = "李四"; +let age = 19; +let grade = true; +console.log(`姓名:${name},类型:${typeof(name)}`); +console.log(`年龄:${age},类型:${typeof(age)}`); +console.log(`及格:${grade},类型:${typeof(grade)}`); + +// 5 +let undefinedVar; +let nullVar = null; +console.log(`undefined 变量: ${undefinedVar}, 类型: ${typeof undefinedVar}`); +console.log(`null 变量: ${nullVar}, 类型: ${typeof nullVar}`); + +// 8 +let name = "张三"; +let age = 20; +let score = 84; +console.log(`${name}今年${age}岁,考了${score}分,${score >= 60 ? '及格' : '不及格'}`); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251225-\350\277\220\347\256\227\347\254\246\344\270\216\347\261\273\345\236\213\350\275\254\346\215\242.md" "b/\351\203\255\345\260\217\344\270\234/20251225-\350\277\220\347\256\227\347\254\246\344\270\216\347\261\273\345\236\213\350\275\254\346\215\242.md" new file mode 100644 index 0000000000000000000000000000000000000000..9db1378985413a752d31b3ab1e9d2a4f6c6dc41f --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251225-\350\277\220\347\256\227\347\254\246\344\270\216\347\261\273\345\236\213\350\275\254\346\215\242.md" @@ -0,0 +1,91 @@ +# 练习 +```js +// 1 +function calculate(a, b) { + return { + 加: a + b, + 减: a - b, + 乘: a * b, + 除: b === 0 ? '除数不能为0' : Number((a / b).toFixed(2)), + 余: b === 0 ? '除数不能为0' : a % b + } +} +console.log(calculate(10, 3)); + +// 2 +let strA = "123"; +let strB = 456; +console.log(`转换后的数字:${Number(strA)},类型:${typeof (Number(strA))}`); +console.log(`转换后的字符串:${String(strB)}, 类型:${typeof (String(strB))}`); + +// 3 +function compareSizes(a, b) { + return { + 大于: a > b, + 等于: a === b, + 不等于: a !== b + } +} +console.log(compareSizes(5, 3)); + +// 4 +function testFour(x, y, z) { + return { + 第一个: x == y, + 第二个: x === y, + 第三个: x == z, + 第四个: x === z + } +} +console.log(testFour("5", 5, "5")); + +// 5 +function testFive(age, hasLicense) { + let test = age >= 18 && age <= 60 && hasLicense; + return test ? "可以开车" : "不可以开车" +} +console.log(testFive(25, true)); + +// 6 +function testSix() { + return { + 第一个: "5" + 3, + 第二个: "5" - 3, + 第三个: true + 1, + 第四个: "10" * "2" + } +} +console.log(testSix()); +console.log("5" + 3, "5" - 3, true + 1, "10" * "2"); + +// 7 +console.log(+"123", -"45", !!"hello"); + +// 8 +function testEight() { + return { + 第一个: NaN === NaN, // false + 第二个: isNaN(NaN), // true + 第三个: Number.isNaN(NaN) // true + } +} +console.log(testEight()); + +// 9 +function testNine(){ + return { + 第一个: ~~5.8 , + 第二个: 7 & 1, + + } +} +console.log(testNine()); + +// 10 +function testTen(score,userName){ + let level = score >= 60 ? "及格" : "不及格"; + let name = userName || "游客"; + return {level,name}; +} +console.log(testTen(85,)); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251226-\346\265\201\347\250\213\346\216\247\345\210\266.md" "b/\351\203\255\345\260\217\344\270\234/20251226-\346\265\201\347\250\213\346\216\247\345\210\266.md" new file mode 100644 index 0000000000000000000000000000000000000000..d7b19d616df8a9a220dd4c90c15dbcd28ad05220 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251226-\346\265\201\347\250\213\346\216\247\345\210\266.md" @@ -0,0 +1,37 @@ +# 练习 +```js +// 1 +function sfjy(score) { + if (score >= 90) { + return "优秀"; + } else if (score >= 80) { + return "良好"; + } else if (score >= 60) { + return "及格"; + } else if (60 > score) { + return "不及格"; + } +} +console.log(sfjy(85)); + +// 2 +function mdjy(e) { + let j = 0; + for (let i = 1; i <= e; i++) { + j += i; + } + return j; +} +console.log(mdjy(100)); + +// 3 +let arr = [1, 2, 3, 4, 5, 6, 7, 8]; +let txtarr = []; +for (let i = 0; i < arr.length; i++) { + let currentNum = arr[i]; + if (currentNum % 2 === 0) { + txtarr.push(currentNum); + } +} +console.log(txtarr); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/20251229-\347\273\203\344\271\240.md" "b/\351\203\255\345\260\217\344\270\234/20251229-\347\273\203\344\271\240.md" new file mode 100644 index 0000000000000000000000000000000000000000..3bdc5689e9b4b545b299028c426507258e8e19a8 --- /dev/null +++ "b/\351\203\255\345\260\217\344\270\234/20251229-\347\273\203\344\271\240.md" @@ -0,0 +1,55 @@ +# JS练习 + +## 函数练习 + +```js +// 1 + function greet(name) { + return `你好,${name}` + } + console.log(greet('小明')); + + // 11 + function fibonacci(n) { + if (n <= 1) { + return n; + } + return fibonacci(n - 1) + fibonacci(n - 2); + } + console.log(fibonacci(7)); + + // 15 + function add(a) { + return function (b) { + return function(c){ + return a + b + c; + }; + } + } + console.log(add(3)(5)(3)); + + // 18 + function getUser({ name, age, city }) { + return { + a: name, + b: age, + c: city + } + + } + console.log(getUser({ name: "张三", age: 25, city: "北京", job: "工程师" })); + + // 7 + let sum = 0; + function abc() { + + return function () { + sum++; + return sum; + } + } + let abac = abc(); + console.log(abac()); + console.log(abac()); + console.log(abac()); +``` \ No newline at end of file diff --git "a/\351\203\255\345\260\217\344\270\234/\345\233\276\347\211\207/\345\261\217\345\271\225\346\210\252\345\233\276 2025-11-16 160043.png" "b/\351\203\255\345\260\217\344\270\234/\345\233\276\347\211\207/\345\261\217\345\271\225\346\210\252\345\233\276 2025-11-16 160043.png" new file mode 100644 index 0000000000000000000000000000000000000000..12b97f2551ead2e33f5b73340a28f95de4e91c95 Binary files /dev/null and "b/\351\203\255\345\260\217\344\270\234/\345\233\276\347\211\207/\345\261\217\345\271\225\346\210\252\345\233\276 2025-11-16 160043.png" differ