diff --git "a/\346\235\216\346\231\250\346\273\224/200t.html" "b/\346\235\216\346\231\250\346\273\224/200t.html" new file mode 100644 index 0000000000000000000000000000000000000000..66b84131b28b70b71034203fb9b8e7df7d377f71 --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/200t.html" @@ -0,0 +1,22 @@ + + +
`格式化文本中才会起作用 + - 字符串拼接 + - 布尔值 boolean + - true + - false + - 空值 null + - 空的或者不存在的值 + - 未定义值 undefined + - 变量还没有赋值 + +## 常量和变量 + - 常量 + - const + - 变量 + - var + - let + - 变量命名规则 + - 以字母、下划线、$开头 + - 不能使用关键字 + - 区分大小写 + - 不能使用中文 + - 不能使用特殊字符 + - 不能使用数字开头 + +## 运算符 + +- 算术运算符 + - `+ - * / % ++ --` + - 优先级 + - `() -> ** -> * / % -> + - -> ++ --` + - 从左到右 + - 优先级相同,从左到右 + - () 优先级最高 +- 字符串运算符 + - `+` 连接两个字符 + - `+=` 连接两个字符并赋值 +- 比较运算符 + - `== != > < >= <=` + - `==` 比较值是否相等 + - `===` 比较值和类型是否相等 + - `!=` 比较值是否不相等 + - `!==` 比较值和类型是否不相等 + - `> < >= <=` 比较大小 +- 赋值运算符 + - `=` + - `+=` + - `-=` + - `*=` + - `/=` + - `%=` + +# 练习 +1. p25练习 +- +```bash + document.write('珠穆朗玛峰的高度≈8848.86m'); +``` + +- +```bash + document.write('E:\\JavaScript\\Code\\demo'); +``` + +2. p28练习 +- +```bash + let area = 17100000 + 'km' + '\u00B2'; + document.write(`俄罗斯的国土面积 ≈ ${area}`); +``` + +- +```bash + document.write('个人信息'+'姓名:郭靖'+'性别:男'+'年龄:20'+'身高:1.77m'+'武功:九阴真经、降龙十八掌'); +``` + +3. p37 +- +```bash + var depositAmount = 100000; + var annualInterestRate = 0.0275; + var depositTerm = 3; + var totalPrincipalAndInterest = depositAmount+depositAmount*annualInterestRate*depositTerm; + document.write('本息合计='+totalPrincipalAndInterest); +``` + +- +```bash + var Grade = 65; + resuit = (Grade >= 60)?"及格":"不及格"; + document.write(resuit); +``` + +- +```bash + var topBase = 30; + var base = 50; + var Height = 30; + var trapezoidArea = ((topBase+base)*Height)/2; + document.write('梯形稻田的面积为:'+trapezoidArea); +``` + +4. p39 +- +```bash + document.write(''); + document.write('他强由他强, 清风抚山岗\n' + '他横任他横, 明月照大江\n' + '他自狠来他自恶,我自一口真气足\n' +' ——《九阳神功》'); + document.write(''); +``` + +- +```bash + var monthlysalary = 6500; + var specialDeduction = 500; + var individualIncomeTaxThreshold = 5000; + var taxRate = 0.03; + var actualIncome = (monthlysalary-specialDeduction)-(monthlysalary-specialDeduction-individualIncomeTaxThreshold)*taxRate; + document.write('该员工的实际收入为' + actualIncome+'元'); +``` + +- +```bash + var year = 2024; + result = (year%4 == 0 && year%100 != 0)||(year%400 == 0)?'2月有29天':'2月有28天'; + alert(year+'年'+result); +``` \ No newline at end of file diff --git "a/\346\235\216\346\231\250\346\273\224/20251113-dmo.md" "b/\346\235\216\346\231\250\346\273\224/20251113-dmo.md" new file mode 100644 index 0000000000000000000000000000000000000000..55de0e7eb95d2ac34d992dbb7172ba0dd09b0e79 --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251113-dmo.md" @@ -0,0 +1,145 @@ +# 笔记 + +## 逻辑运算符 + - 逻辑与 && + - 两个都为真则为真 + - 逻辑或 || + - 其中有一个为真则为真 + - 逻辑非 ! + - !true + +## 条件运算符 + - 语法 + - `条件 ? 表达式1 : 表达式2` + - 如果条件为真,则执行表达式1,否则执行表达式2 + +## 其他运算符 +- 逗号运算符 + - `a = 1, b = 2` + - 则结果为最后一个 +- typeof 运算符 + - 判断数据类型 + | 数据类型 | 返回值 | 数据类型 | 返回值 | + | --------- | --------- | -------- | -------- | + | 数值 | number | null | objec | + | 字符串 | string | 对象 | object | + | 布尔值 | object | 函数 | function | + | undefined | undefined | ----- | ---- | +- new运算符 + - 对象实例名称=new 对象类型(参数) + - 对象实例名称=new 对象类型 + +## 表达式 +- 算术表达式 +- 逻辑表达式 +- 字符串表达式 + +# 练习 +1. p55 +- +```bash + let number1; + let all = 0; + for (number1 = 1; number1 <= 1000; number1++) { + if (number1 % 65 != 0) { + continue; + } + all = all + number1; + } + document.write(all); +``` + +- +```bash +let row, piece; + document.write('尚未使用的卡位:'); + for (row = 1; row <= 3; row++) { + for (piece = 1; piece <= 3; piece++) { + if (row == 1 && piece == 3) { + continue; + } + if (row == 3 && piece == 2) { + continue; + } + document.write('第' + row + '排' + '第' + piece + '个\n'); + if (row == 1 && piece == 2) { + document.write(''); + } + if (row == 2 && piece == 3) { + document.write(''); + } + } + } +``` + +2. p55实践与练习 +- +```bash + let bmi; + let bodyWeight; + let base = 2; + let manbmi= 23; + switch (base) { + case 1: + bmi = 'body<20'; + bodyWeight = '体重过轻'; + break; + case 2: + bmi = '20<=body<=25'; + bodyWeight = '体重适中'; + break; + case 3: + bmi = '25<=body<=30'; + bodyWeight = '体重过重'; + break; + case 4: + bmi = '30<=body<=35'; + bodyWeight = '肥胖'; + break; + case 5: + bmi = 'body>35'; + bodyWeight = '非常肥胖'; + break; + } + document.write('BMI:'+manbmi+''+'结果:'+bodyWeight); +``` + +- +```bash + let year; + let month; + document.write('请选择您的出生年月:'); + document.write(''); + for (year = 1999; year <= 2025; year++) { + document.write(''); + document.write(year+'年'); + document.write(''); + } + document.write(''); + document.write(''); + for(month=1;month<=12;month++){ + document.write(''); + document.write(month+'月'); + document.write(''); + } + document.write(''); +``` + +- +```bash +let row; + document.write('
'); + document.write('他强由他强, 清风抚山岗\n' + '他横任他横, 明月照大江\n' + '他自狠来他自恶,我自一口真气足\n' +' ——《九阳神功》'); + document.write('
` 标签并插入容器,计数器确保按序添加且不超界; +2. 动态添加头像案例:数组存储多张头像地址,创建 `` 时添加统一类名 `added-img` 便于样式控制,设置 `alt` 属性提升语义化。 + +## 四、下拉选择框 onchange 事件与主题切换 +### 核心知识点 +1. **select 核心事件**:`onchange`,当下拉框选中项变化时**即时触发**(无需点击按钮),是表单即时交互的常用事件。 +2. **获取选中值**:`document.getElementById('下拉框ID').value`,获取选中 `` 的 `value` 属性值。 +3. **多态主题切换**:通过 `if/else if/else` 判断选中的主题值,执行对应样式修改;默认项/未选择时,赋值空字符串恢复页面默认样式。 + +### 练习要点 +- 主题切换案例:选择“绿色/黑色主题”时修改 body 样式,选择“请选择主题”时恢复默认,核心是 `onchange` 即时响应,提升用户体验。 + +## 五、动态操作图片(创建、删除、显隐控制) +### 核心知识点 +1. **图片存在性判断**:`!document.getElementById('targetImg')`,避免重复创建同一图片。 +2. **元素删除**:`元素.remove()`,彻底删除 DOM 树上的元素(区别于隐藏)。 +3. **元素显隐控制**:`元素.style.display = 'block'`(显示)/ `'none'`(隐藏)。 +4. **悬浮按钮定位**:父容器设 `position: fixed/relative`,子按钮设 `position: absolute`,实现按钮悬浮在图片右上角。 + +### 练习要点 +- 图片对话框案例:点击链接创建图片(先判断是否已存在),删除按钮默认隐藏,图片创建后显示,删除图片后再次隐藏; +- 注意:删除元素前先判断 `if(img)`,避免执行 `remove()` 时出现“找不到元素”的错误。 + +--- + +### 总结 +1. **状态切换**:布尔变量 + `!变量` 翻转是二态交互核心,可快速实现样式/功能切换; +2. **DOM 动态操作**:`createElement` 创建、`appendChild` 添加、`remove` 删除,是动态渲染内容的基础; +3. **交互事件**:select 的 `onchange` 实现即时主题切换,计数器控制元素逐次添加,提升交互体验; +4. **健壮性**:元素存在性判断、数组边界判断,避免重复操作和代码报错。 + + +# 练习 +1. p203 +- +```bash + 是我儿子 + + +``` + +- +```bash + document.write('当前文档:'+document.URL); +``` + +- +```bash + + + +``` + +2. p204实践与练习 +- +```bash + + 请选择主题 + 绿色主题 + 黑色主题 + + 李白《行路难·其一》 + 金樽清酒斗十千,玉盘珍羞直万钱 + 金樽清酒斗十千,玉盘珍羞直万钱 + 金樽清酒斗十千,玉盘珍羞直万钱 + 金樽清酒斗十千,玉盘珍羞直万钱 + 金樽清酒斗十千,玉盘珍羞直万钱 + 金樽清酒斗十千,玉盘珍羞直万钱 + +``` + +- +```bash + + + + 打开图片对话框 + + + + + +``` + +- +```bash + + + + +``` + diff --git "a/\346\235\216\346\231\250\346\273\224/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\346\235\216\346\231\250\346\273\224/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..ffb9b91d405533866377ed90996e19b76ff90337 --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251204-\346\226\207\346\241\243\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,437 @@ +# 笔记 +歌词对比插入: + + + +年月日变化而变化: + + + +# 练习 +1. p215 +- +```bash + 1.(myselef+AI) + + + + + + 请选择添加字体颜色 + 黄色 + 绿色 + 黑色 + + + + + + 2.(myself+teacher) + + + 请选择添加字体颜色 + 黄色 + 绿色 + 黑色 + + + + +``` + +- +```bash + 输入歌名: + + 歌词: + + + + +``` + +- +```bash + 最新电影资讯 + + 1.《金蚕脱壳》两大动作巨星联手 + 2.《阿甘正传》励志而传奇的一生 + 3.《爱乐之城》爱情和梦想的交织 + 4.《头号玩家》游戏梦想照进现实 + + + 输入影片资讯编号: + + + +``` + +2. p218 +- +```bash + + 西瓜 + 蜜橘 + 萝卜 + + + 黄瓜 + 茄子 + 杧果 + + + +``` + +- +```bash + 在《倚天屠龙记》中,张三丰是___派的掌门? + A 少林 + B 武当 + C 峨眉 + D 昆仑 + + +``` + +3. p221 +- +```bash + 点我试试 + + +``` + +- +```bash + + + +``` + +4. p221实践与练习 +- +```bash + 一生只爱一个人 + 将粗体改为斜体 + +``` + +- +```bash + 1.(AI) + + + + +``` + +- +```bash + 1.(AI) + 请选择图片: + + + + +``` diff --git "a/\346\235\216\346\231\250\346\273\224/20251205-Windows\345\257\271\350\261\241.md" "b/\346\235\216\346\231\250\346\273\224/20251205-Windows\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..4b111f0517c7b84446f3d15162a2e58b54d682e7 --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251205-Windows\345\257\271\350\261\241.md" @@ -0,0 +1,1948 @@ +# 笔记 +## JavaScript Window 对象全面知识点总结 + +## 📋 目录 + +1. [Window 对象简介](#window-对象简介) +2. [对话框方法](#对话框方法) +3. [窗口的打开与关闭](#窗口的打开与关闭) +4. [控制窗口](#控制窗口) +5. [窗口事件](#窗口事件) +6. [窗口导航与历史](#窗口导航与历史) +7. [窗口尺寸与位置](#窗口尺寸与位置) +8. [定时器与动画](#定时器与动画) + +--- + +## Window 对象简介 + +### 1. Window 对象是什么? + +**知识点**:Window 对象代表浏览器窗口,是 JavaScript 的全局对象,包含所有全局变量、函数和对象。 + +```javascript +// Window 对象是全局对象 +console.log(window === this); // 在全局作用域中为 true + +// 全局变量自动成为 window 的属性 +var globalVar = "全局变量"; +console.log(window.globalVar); // "全局变量" + +// 全局函数也是 window 的方法 +function sayHello() { + return "Hello"; +} +console.log(window.sayHello()); // "Hello" +``` + +### 2. Window 对象与其他对象的关系 + +**知识点**:Window 对象包含 document、location、history、navigator 等子对象。 + +```javascript +// Window 的子对象 +console.log(window.document); // Document 对象 +console.log(window.location); // Location 对象 +console.log(window.history); // History 对象 +console.log(window.navigator); // Navigator 对象 +console.log(window.screen); // Screen 对象 +console.log(window.localStorage); // Storage 对象 + +// 访问时可以省略 window 前缀 +console.log(document === window.document); // true +console.log(location === window.location); // true +``` + +### 3. 全局作用域 + +**知识点**:在浏览器中,全局作用域就是 Window 对象。 + +```javascript +// 检查变量是否在全局作用域中 +var x = 10; +let y = 20; // let/const 声明的变量不会成为 window 的属性 +const z = 30; + +console.log(window.x); // 10 +console.log(window.y); // undefined +console.log(window.z); // undefined + +// 在严格模式下,this 在全局作用域中为 undefined +("use strict"); +console.log(this); // undefined (非严格模式下为 window) +``` + +--- + +## 对话框方法 + +### 4. alert() 方法 + +**知识点**:显示一个警告对话框,包含指定的消息和一个"确定"按钮。 + +```javascript +// 基本用法 +alert("这是一个警告信息"); + +// 显示变量值 +let userName = "张三"; +alert(`欢迎, ${userName}!`); + +// 显示对象信息 +let user = { name: "李四", age: 25 }; +alert(JSON.stringify(user, null, 2)); + +// 注意:alert 会阻塞代码执行 +console.log("这行代码在 alert 关闭后执行"); +``` + +### 5. confirm() 方法 + +**知识点**:显示一个确认对话框,包含指定的消息和"确定"/"取消"按钮,返回布尔值。 + +```javascript +// 基本用法 +let result = confirm("您确定要删除此项吗?"); +console.log("用户选择:", result); // true 或 false + +// 根据选择执行不同操作 +if (confirm("是否继续?")) { + console.log("用户选择了继续"); + // 执行继续操作 +} else { + console.log("用户选择了取消"); + // 执行取消操作 +} + +// 使用在三元表达式中 +let action = confirm("启用高级功能?") ? "启用" : "禁用"; +console.log("操作:", action); +``` + +### 6. prompt() 方法 + +**知识点**:显示一个提示对话框,包含输入框和"确定"/"取消"按钮,返回输入值或 null。 + +```javascript +// 基本用法 +let name = prompt("请输入您的姓名:"); +console.log("输入的姓名:", name); + +// 带默认值 +let age = prompt("请输入您的年龄:", "25"); +console.log("输入的年龄:", age); + +// 验证输入 +let input; +do { + input = prompt("请输入一个数字(1-10):"); +} while (input === null || isNaN(input) || input < 1 || input > 10); + +console.log("有效的输入:", input); + +// 处理取消操作 +let email = prompt("请输入邮箱:"); +if (email === null) { + console.log("用户取消了输入"); +} else if (email.trim() === "") { + console.log("用户输入了空字符串"); +} else { + console.log("用户输入:", email); +} +``` + +### 7. 自定义对话框 + +**知识点**:使用 DOM 创建更灵活的自定义对话框。 + +```javascript +// 创建自定义确认对话框 +function customConfirm(message, callback) { + // 创建对话框元素 + const dialog = document.createElement("div"); + dialog.style.cssText = ` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background: white; + padding: 20px; + border: 2px solid #333; + border-radius: 5px; + z-index: 1000; + `; + + dialog.innerHTML = ` + ${message} + 确定 + 取消 + `; + + document.body.appendChild(dialog); + + // 添加事件处理 + document.getElementById("confirmOk").onclick = function () { + document.body.removeChild(dialog); + callback(true); + }; + + document.getElementById("confirmCancel").onclick = function () { + document.body.removeChild(dialog); + callback(false); + }; +} + +// 使用自定义对话框 +customConfirm("是否确认操作?", function (result) { + console.log("用户选择:", result); +}); +``` + +--- + +## 窗口的打开与关闭 + +### 8. window.open() 方法 + +**知识点**:打开一个新的浏览器窗口或标签页。 + +```javascript +// 基本用法 - 在新标签页中打开 +const newWindow = window.open("https://www.example.com"); + +// 指定窗口名称(可用于 target 属性) +window.open("page.html", "myWindow"); + +// 在新窗口中打开(不是新标签页) +const popup = window.open("popup.html", "popup", "width=400,height=300"); + +// 控制是否显示浏览器控件 +const minimalWindow = window.open( + "minimal.html", + "minimal", + "menubar=no,toolbar=no,location=no,status=no" +); + +// 获取打开的窗口引用 +const myWindow = window.open("", "myWindow"); +if (myWindow) { + myWindow.document.write("Hello from opener!"); +} +``` + +### 9. 窗口打开参数 + +**知识点**:window.open() 的第三个参数控制窗口特性。 + +```javascript +// 完整的窗口特性参数 +const features = [ + "width=800", // 窗口宽度 + "height=600", // 窗口高度 + "left=100", // 距离屏幕左边缘 + "top=100", // 距离屏幕上边缘 + "resizable=yes", // 是否可调整大小 + "scrollbars=yes", // 是否显示滚动条 + "toolbar=no", // 是否显示工具栏 + "menubar=no", // 是否显示菜单栏 + "location=no", // 是否显示地址栏 + "status=no", // 是否显示状态栏 + "fullscreen=no", // 是否全屏(需要用户交互) +].join(","); + +const configuredWindow = window.open("config.html", "config", features); + +// 检查窗口是否成功打开 +if (!configuredWindow) { + alert("弹出窗口被浏览器阻止了!请允许弹出窗口。"); +} +``` + +### 10. window.close() 方法 + +**知识点**:关闭当前窗口或指定的窗口。 + +```javascript +// 关闭当前窗口 +function closeCurrentWindow() { + if (confirm("确定要关闭窗口吗?")) { + window.close(); + } +} + +// 关闭由 window.open() 打开的窗口 +let openedWindow = null; + +function openAndClose() { + // 打开新窗口 + openedWindow = window.open("", "testWindow", "width=400,height=300"); + + // 在新窗口中写入内容 + openedWindow.document.write("这个窗口将在5秒后关闭"); + + // 5秒后关闭窗口 + setTimeout(() => { + if (openedWindow && !openedWindow.closed) { + openedWindow.close(); + console.log("窗口已关闭"); + } + }, 5000); +} + +// 检查窗口是否已关闭 +if (openedWindow && openedWindow.closed) { + console.log("窗口已经关闭了"); +} +``` + +### 11. 窗口状态检测 + +**知识点**:检测窗口的打开和关闭状态。 + +```javascript +let childWindow = null; + +// 打开子窗口 +function openChildWindow() { + childWindow = window.open("child.html", "child", "width=400,height=300"); + + // 定期检查子窗口是否关闭 + const checkInterval = setInterval(() => { + if (childWindow.closed) { + console.log("子窗口已关闭"); + clearInterval(checkInterval); + // 执行清理操作 + childWindow = null; + } + }, 1000); +} + +// 与子窗口通信 +function sendMessageToChild() { + if (childWindow && !childWindow.closed) { + // 向子窗口传递数据 + childWindow.postMessage("Hello from parent!", "*"); + + // 调用子窗口的函数(如果同源) + try { + childWindow.someFunction(); + } catch (e) { + console.log("跨域限制或函数不存在"); + } + } else { + console.log("子窗口未打开或已关闭"); + } +} +``` + +--- + +## 控制窗口 + +### 12. 移动窗口 + +**知识点**:移动窗口到指定位置。 + +```javascript +// 移动当前窗口 +function moveWindowTo(x, y) { + // 注意:现代浏览器出于安全考虑,通常不允许脚本移动主窗口 + // 但可以移动由 window.open() 打开的窗口 + + if (window.opener) { + // 如果这是由其他窗口打开的 + window.moveTo(x, y); + } +} + +// 移动由脚本打开的窗口 +let movableWindow = null; + +function createMovableWindow() { + movableWindow = window.open("", "movable", "width=300,height=200"); + + // 添加控制按钮 + movableWindow.document.write(` + 可移动窗口 + 移动到(100,100) + 移动50像素 + `); +} + +// 相对移动 +function moveWindowRelative(dx, dy) { + if (movableWindow && !movableWindow.closed) { + movableWindow.moveBy(dx, dy); + } +} +``` + +### 13. 调整窗口大小 + +**知识点**:调整窗口的尺寸。 + +```javascript +// 调整当前窗口大小 +function resizeCurrentWindow(width, height) { + // 注意:通常不能调整主窗口大小 + // 但可以调整由 window.open() 打开的窗口 + window.resizeTo(width, height); +} + +// 调整由脚本打开的窗口 +let resizableWindow = null; + +function createResizableWindow() { + resizableWindow = window.open( + "", + "resizable", + "width=400,height=300,resizable=yes" + ); + + // 添加控制按钮 + resizableWindow.document.write(` + 可调整大小的窗口 + 调整为800x600 + 增大100像素 + 减小100像素 + `); +} + +// 检查窗口是否可以调整大小 +function checkIfResizable() { + if (resizableWindow) { + // 注意:没有直接的方法检查,但可以尝试调整 + try { + resizableWindow.resizeBy(1, 1); + resizableWindow.resizeBy(-1, -1); // 恢复 + console.log("窗口可以调整大小"); + return true; + } catch (e) { + console.log("窗口不能调整大小"); + return false; + } + } + return false; +} +``` + +### 14. 窗口滚动控制 + +**知识点**:控制窗口的滚动位置。 + +```javascript +// 滚动到指定位置 +function scrollToPosition(x, y) { + window.scrollTo(x, y); + + // 或使用选项对象 + window.scrollTo({ + top: y, + left: x, + behavior: "smooth", // 'auto' 或 'smooth' + }); +} + +// 滚动到元素 +function scrollToElement(elementId) { + const element = document.getElementById(elementId); + if (element) { + element.scrollIntoView({ + behavior: "smooth", + block: "start", // 'start', 'center', 'end', 'nearest' + }); + } +} + +// 相对滚动 +function scrollByAmount(dx, dy) { + window.scrollBy(dx, dy); + + // 平滑滚动 + window.scrollBy({ + top: dy, + left: dx, + behavior: "smooth", + }); +} + +// 获取当前滚动位置 +function getScrollPosition() { + return { + x: window.pageXOffset || document.documentElement.scrollLeft, + y: window.pageYOffset || document.documentElement.scrollTop, + }; +} + +// 滚动到页面顶部 +function scrollToTop() { + window.scrollTo({ top: 0, behavior: "smooth" }); +} + +// 滚动到页面底部 +function scrollToBottom() { + window.scrollTo({ + top: document.documentElement.scrollHeight, + behavior: "smooth", + }); +} +``` + +### 15. 窗口焦点控制 + +**知识点**:控制窗口的焦点状态。 + +```javascript +// 将焦点设置到当前窗口 +function focusWindow() { + window.focus(); + console.log("窗口已获得焦点"); +} + +// 使窗口失去焦点 +function blurWindow() { + window.blur(); + console.log("窗口已失去焦点"); +} + +// 检查窗口是否有焦点 +function checkWindowFocus() { + if (document.hasFocus()) { + console.log("当前窗口有焦点"); + return true; + } else { + console.log("当前窗口没有焦点"); + return false; + } +} + +// 焦点变化示例 +let lastFocusTime = Date.now(); + +window.addEventListener("focus", () => { + const now = Date.now(); + const awayTime = now - lastFocusTime; + console.log(`窗口重新获得焦点,离开时间:${awayTime}ms`); +}); + +window.addEventListener("blur", () => { + lastFocusTime = Date.now(); + console.log("窗口失去焦点"); +}); + +// 自动聚焦输入框 +function autoFocusInput() { + const input = document.getElementById("myInput"); + if (input) { + input.focus(); + // 选中文本(可选) + input.select(); + } +} +``` + +--- + +## 窗口事件 + +### 16. load 事件 + +**知识点**:当整个页面及所有依赖资源(如图片、样式表)已完全加载时触发。 + +```javascript +// 使用 addEventListener +window.addEventListener("load", function () { + console.log("所有资源已完全加载"); + // 可以安全地操作DOM和资源 + const images = document.getElementsByTagName("img"); + console.log(`页面包含 ${images.length} 张图片`); +}); + +// 传统方式 +window.onload = function () { + console.log("页面加载完成(传统方式)"); + // 初始化应用 + initApp(); +}; + +// 图片加载完成后执行 +const img = new Image(); +img.src = "large-image.jpg"; +img.onload = function () { + console.log("大图片加载完成"); + document.body.appendChild(img); +}; +``` + +### 17. DOMContentLoaded 事件 + +**知识点**:当初始 HTML 文档完全加载和解析完成(不等待样式表、图片等)时触发。 + +```javascript +// 推荐使用 - 比 load 事件更快 +document.addEventListener("DOMContentLoaded", function () { + console.log("DOM 已完全加载和解析"); + // DOM 已就绪,可以操作元素 + const buttons = document.querySelectorAll("button"); + console.log(`找到 ${buttons.length} 个按钮`); + + // 添加事件监听器等 + buttons.forEach((btn) => { + btn.addEventListener("click", handleClick); + }); +}); + +// 传统方式 +document.onreadystatechange = function () { + if (document.readyState === "interactive") { + console.log("DOM 准备就绪(readystatechange)"); + } +}; +``` + +### 18. beforeunload 事件 + +**知识点**:在窗口、文档即将卸载时触发,可用于提示用户保存更改。 + +```javascript +// 提示用户离开前保存数据 +window.addEventListener("beforeunload", function (event) { + // 如果有未保存的更改 + if (hasUnsavedChanges) { + // 标准方式 + event.preventDefault(); + // Chrome 需要设置 returnValue + event.returnValue = "您有未保存的更改,确定要离开吗?"; + return "您有未保存的更改,确定要离开吗?"; + } +}); + +// 传统方式 +window.onbeforeunload = function () { + if (hasUnsavedChanges) { + return "您有未保存的更改,确定要离开吗?"; + } +}; + +// 清除 beforeunload 处理程序 +function clearBeforeUnload() { + window.onbeforeunload = null; + // 或使用 removeEventListener +} +``` + +### 19. unload 事件 + +**知识点**:当文档或子资源正在被卸载时触发,用于清理操作。 + +```javascript +// 在页面卸载时执行清理 +window.addEventListener("unload", function () { + // 发送统计数据 + if (navigator.sendBeacon) { + const data = new FormData(); + data.append("event", "page_unload"); + data.append("time", Date.now()); + navigator.sendBeacon("/analytics", data); + } + + // 清理资源 + cleanupResources(); + + console.log("页面正在卸载"); +}); + +// 注意:unload 事件中不能使用同步的 alert/confirm/prompt +// 也不能阻止页面卸载 +``` + +### 20. resize 事件 + +**知识点**:当窗口大小改变时触发。 + +```javascript +// 监听窗口大小变化 +let resizeTimeout; +window.addEventListener("resize", function () { + // 防抖处理,避免频繁触发 + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { + console.log("窗口大小已改变"); + console.log("新尺寸:", window.innerWidth, "x", window.innerHeight); + + // 根据窗口大小调整布局 + adjustLayoutForScreenSize(); + }, 250); // 250ms 防抖延迟 +}); + +// 获取窗口尺寸 +function getWindowSize() { + return { + width: window.innerWidth || document.documentElement.clientWidth, + height: window.innerHeight || document.documentElement.clientHeight, + outerWidth: window.outerWidth, + outerHeight: window.outerHeight, + }; +} + +// 响应式设计检查 +function checkResponsiveBreakpoint() { + const width = window.innerWidth; + + if (width >= 1200) { + console.log("超大屏幕"); + } else if (width >= 992) { + console.log("大屏幕"); + } else if (width >= 768) { + console.log("中等屏幕"); + } else if (width >= 576) { + console.log("小屏幕"); + } else { + console.log("超小屏幕"); + } +} +``` + +### 21. scroll 事件 + +**知识点**:当窗口滚动时触发。 + +```javascript +// 监听滚动事件 +let lastScrollTop = 0; +window.addEventListener("scroll", function () { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + + // 检查滚动方向 + if (scrollTop > lastScrollTop) { + console.log("向下滚动"); + } else { + console.log("向上滚动"); + } + + lastScrollTop = scrollTop; + + // 无限滚动示例 + if (isNearBottom()) { + loadMoreContent(); + } + + // 固定导航栏 + toggleFixedNavbar(scrollTop); +}); + +// 检查是否接近底部 +function isNearBottom() { + const scrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollHeight = document.documentElement.scrollHeight; + const clientHeight = document.documentElement.clientHeight; + + // 距离底部 200px 时触发 + return scrollTop + clientHeight >= scrollHeight - 200; +} + +// 节流滚动事件(性能优化) +function throttleScroll(callback, delay) { + let isThrottled = false; + + return function () { + if (!isThrottled) { + callback(); + isThrottled = true; + setTimeout(() => { + isThrottled = false; + }, delay); + } + }; +} + +window.addEventListener( + "scroll", + throttleScroll(() => { + console.log("节流后的滚动处理"); + }, 100) +); // 每100ms最多执行一次 +``` + +### 22. focus 和 blur 事件 + +**知识点**:当窗口获得或失去焦点时触发。 + +```javascript +// 窗口获得焦点 +window.addEventListener("focus", function () { + console.log("窗口获得焦点"); + + // 恢复应用状态 + if (isAppPaused) { + resumeApp(); + } + + // 更新页面标题 + document.title = document.title.replace(" [未激活]", ""); +}); + +// 窗口失去焦点 +window.addEventListener("blur", function () { + console.log("窗口失去焦点"); + + // 暂停应用活动 + pauseApp(); + + // 更新页面标题提示 + if (!document.title.includes("[未激活]")) { + document.title += " [未激活]"; + } +}); + +// 检查当前焦点状态 +function checkFocusStatus() { + if (document.hasFocus()) { + console.log("当前窗口处于活动状态"); + return true; + } else { + console.log("当前窗口处于非活动状态"); + return false; + } +} + +// 页面可见性 API(更现代的替代方案) +document.addEventListener("visibilitychange", function () { + if (document.hidden) { + console.log("页面隐藏"); + } else { + console.log("页面可见"); + } +}); +``` + +### 23. hashchange 事件 + +**知识点**:当 URL 的哈希部分(#后面)改变时触发。 + +```javascript +// 监听哈希变化 +window.addEventListener("hashchange", function (event) { + console.log("哈希已改变"); + console.log("旧URL:", event.oldURL); + console.log("新URL:", event.newURL); + console.log("当前哈希:", window.location.hash); + + // 根据哈希更新页面内容 + const hash = window.location.hash.substring(1); // 去掉 # + if (hash) { + loadContent(hash); + } else { + loadDefaultContent(); + } +}); + +// 手动触发哈希变化 +function navigateToSection(sectionId) { + window.location.hash = sectionId; + // 或使用 history.pushState(不触发 hashchange) + // history.pushState(null, '', '#' + sectionId); +} + +// 初始化时检查哈希 +if (window.location.hash) { + const section = window.location.hash.substring(1); + loadContent(section); +} +``` + +### 24. message 事件 + +**知识点**:当窗口收到来自其他窗口的消息时触发(跨文档通信)。 + +```javascript +// 接收来自其他窗口的消息 +window.addEventListener("message", function (event) { + // 安全检查:检查消息来源 + const allowedOrigin = "https://trusted-site.com"; + if (event.origin !== allowedOrigin) { + console.warn("收到来自不受信任来源的消息:", event.origin); + return; + } + + console.log("收到消息:", event.data); + console.log("来源:", event.origin); + console.log("来源窗口:", event.source); + + // 处理消息 + if (event.data.type === "updateData") { + updateData(event.data.payload); + } + + // 可选:发送回复 + event.source.postMessage( + { + type: "acknowledge", + message: "消息已收到", + }, + event.origin + ); +}); + +// 向其他窗口发送消息 +function sendMessageToIframe() { + const iframe = document.getElementById("myIframe"); + if (iframe && iframe.contentWindow) { + iframe.contentWindow.postMessage( + { + type: "command", + action: "refresh", + }, + "https://iframe-origin.com" + ); + } +} + +// 向父窗口发送消息(如果在 iframe 中) +if (window.parent !== window) { + window.parent.postMessage( + { + type: "ready", + content: "iframe 已加载完成", + }, + "*" + ); // 注意:使用 '*' 有安全风险,生产环境应指定具体来源 +} +``` + +### 25. storage 事件 + +**知识点**:当 localStorage 或 sessionStorage 发生变化时触发(仅在同源的其他窗口中)。 + +```javascript +// 监听存储变化 +window.addEventListener("storage", function (event) { + console.log("存储发生变化:"); + console.log("键:", event.key); + console.log("旧值:", event.oldValue); + console.log("新值:", event.newValue); + console.log("URL:", event.url); + console.log("存储区域:", event.storageArea); + + // 更新应用状态 + if (event.key === "userPreferences") { + updatePreferences(JSON.parse(event.newValue)); + } +}); + +// 示例:在一个标签页中设置,在另一个标签页中监听 +function saveUserSettings(settings) { + localStorage.setItem("userPreferences", JSON.stringify(settings)); + console.log("设置已保存"); +} + +// 当前窗口的变化不会触发自己的 storage 事件 +// 只会在同源的其他窗口中触发 +``` + +--- + +## 窗口导航与历史 + +### 26. location 对象 + +**知识点**:window.location 对象包含当前 URL 的信息,并可用于导航。 + +```javascript +// 获取当前URL信息 +console.log("完整URL:", window.location.href); +console.log("协议:", window.location.protocol); // https: +console.log("主机:", window.location.host); // example.com:8080 +console.log("主机名:", window.location.hostname); // example.com +console.log("端口:", window.location.port); // 8080 +console.log("路径:", window.location.pathname); // /path/to/page +console.log("搜索参数:", window.location.search); // ?id=123 +console.log("哈希:", window.location.hash); // #section +console.log("来源:", window.location.origin); // https://example.com:8080 + +// 导航到新页面 +function navigateTo(url) { + window.location.href = url; // 最常用 + // 或 window.location = url; + // 或 window.location.assign(url); +} + +// 重定向到新页面(替换当前历史记录) +function redirectTo(url) { + window.location.replace(url); // 当前页面不会留在历史记录中 +} + +// 重新加载页面 +function reloadPage() { + window.location.reload(); // 重新加载 + // window.location.reload(true); // 强制从服务器重新加载(忽略缓存) +} + +// 获取URL参数 +function getUrlParams() { + const params = new URLSearchParams(window.location.search); + const id = params.get("id"); // 获取id参数 + const name = params.get("name"); // 获取name参数 + + console.log("ID:", id); + console.log("所有参数:", Object.fromEntries(params)); + return { id, name }; +} +``` + +### 27. history 对象 + +**知识点**:window.history 对象允许操作浏览器会话历史记录。 + +```javascript +// 前进和后退 +function goBack() { + window.history.back(); // 等同于点击后退按钮 + // 或 window.history.go(-1); +} + +function goForward() { + window.history.forward(); // 等同于点击前进按钮 + // 或 window.history.go(1); +} + +// 跳转到历史记录中的特定位置 +function goToHistory(index) { + window.history.go(index); // 正数前进,负数后退 +} + +// 添加历史记录(不会加载新页面) +function addHistoryState(state, title, url) { + window.history.pushState(state, title, url); + console.log("历史记录已添加:", url); +} + +// 替换当前历史记录 +function replaceHistoryState(state, title, url) { + window.history.replaceState(state, title, url); + console.log("历史记录已替换:", url); +} + +// 监听历史记录变化 +window.addEventListener("popstate", function (event) { + console.log("位置变化:", window.location.href); + console.log("状态:", event.state); + + // 根据状态更新页面内容 + if (event.state) { + loadContentBasedOnState(event.state); + } +}); + +// 单页应用(SPA)路由示例 +function navigateToPage(page) { + const state = { page: page, timestamp: Date.now() }; + const url = `/${page}`; + + // 添加历史记录 + history.pushState(state, "", url); + + // 加载页面内容(不刷新页面) + loadPageContent(page); +} +``` + +### 28. navigator 对象 + +**知识点**:window.navigator 对象包含有关浏览器的信息。 + +```javascript +// 浏览器信息 +console.log("用户代理:", navigator.userAgent); +console.log("平台:", navigator.platform); +console.log("语言:", navigator.language); +console.log("浏览器语言:", navigator.languages); +console.log("Cookie 启用:", navigator.cookieEnabled); +console.log("在线状态:", navigator.onLine); + +// 检测设备类型 +function detectDevice() { + const ua = navigator.userAgent; + + if (/mobile/i.test(ua)) { + return "mobile"; + } else if (/tablet/i.test(ua)) { + return "tablet"; + } else { + return "desktop"; + } +} + +// 检测浏览器 +function detectBrowser() { + const ua = navigator.userAgent; + + if (/chrome/i.test(ua) && !/edge/i.test(ua)) { + return "Chrome"; + } else if (/firefox/i.test(ua)) { + return "Firefox"; + } else if (/safari/i.test(ua) && !/chrome/i.test(ua)) { + return "Safari"; + } else if (/edge/i.test(ua)) { + return "Edge"; + } else if (/msie/i.test(ua) || /trident/i.test(ua)) { + return "IE"; + } else { + return "Unknown"; + } +} + +// 检查网络状态 +function checkNetworkStatus() { + if (navigator.onLine) { + console.log("设备在线"); + return true; + } else { + console.log("设备离线"); + return false; + } +} + +// 监听网络状态变化 +window.addEventListener("online", () => { + console.log("设备已连接到网络"); + // 重新同步数据 +}); + +window.addEventListener("offline", () => { + console.log("设备已断开网络"); + // 显示离线提示 +}); +``` + +--- + +## 窗口尺寸与位置 + +### 29. 获取窗口尺寸 + +**知识点**:获取窗口和屏幕的尺寸信息。 + +```javascript +// 获取视口尺寸(显示网页的区域) +function getViewportSize() { + return { + width: window.innerWidth, + height: window.innerHeight, + // 兼容性处理 + widthAlt: document.documentElement.clientWidth, + heightAlt: document.documentElement.clientHeight, + }; +} + +// 获取整个窗口尺寸(包括浏览器界面) +function getWindowOuterSize() { + return { + width: window.outerWidth, + height: window.outerHeight, + }; +} + +// 获取屏幕尺寸 +function getScreenSize() { + return { + width: screen.width, + height: screen.height, + availWidth: screen.availWidth, // 可用宽度(不包括任务栏等) + availHeight: screen.availHeight, // 可用高度 + colorDepth: screen.colorDepth, // 颜色深度 + pixelDepth: screen.pixelDepth, // 像素深度 + }; +} + +// 获取文档尺寸(整个页面内容) +function getDocumentSize() { + return { + width: document.documentElement.scrollWidth, + height: document.documentElement.scrollHeight, + }; +} + +// 响应式设计辅助函数 +function getBreakpoint() { + const width = window.innerWidth; + + if (width >= 1400) return "xxl"; + if (width >= 1200) return "xl"; + if (width >= 992) return "lg"; + if (width >= 768) return "md"; + if (width >= 576) return "sm"; + return "xs"; +} + +// 监听窗口尺寸变化 +function watchWindowSize(callback) { + let lastSize = getViewportSize(); + + window.addEventListener("resize", () => { + const newSize = getViewportSize(); + + if ( + newSize.width !== lastSize.width || + newSize.height !== lastSize.height + ) { + callback(newSize, lastSize); + lastSize = newSize; + } + }); +} +``` + +### 30. 获取窗口位置 + +**知识点**:获取窗口在屏幕上的位置。 + +```javascript +// 获取窗口相对于屏幕的位置 +function getWindowPosition() { + return { + screenX: window.screenX, // 窗口左上角X坐标 + screenY: window.screenY, // 窗口左上角Y坐标 + screenLeft: window.screenLeft, // 兼容性别名 + screenTop: window.screenTop, // 兼容性别名 + }; +} + +// 获取滚动位置 +function getScrollPosition() { + return { + x: window.pageXOffset || document.documentElement.scrollLeft, + y: window.pageYOffset || document.documentElement.scrollTop, + }; +} + +// 元素相对于视口的位置 +function getElementViewportPosition(element) { + const rect = element.getBoundingClientRect(); + return { + top: rect.top, + right: rect.right, + bottom: rect.bottom, + left: rect.left, + width: rect.width, + height: rect.height, + }; +} + +// 检查元素是否在视口中 +function isElementInViewport(element) { + const rect = element.getBoundingClientRect(); + const windowHeight = + window.innerHeight || document.documentElement.clientHeight; + const windowWidth = window.innerWidth || document.documentElement.clientWidth; + + return ( + rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= windowHeight && + rect.right <= windowWidth + ); +} + +// 检查元素是否部分可见 +function isElementPartiallyVisible(element) { + const rect = element.getBoundingClientRect(); + const windowHeight = + window.innerHeight || document.documentElement.clientHeight; + const windowWidth = window.innerWidth || document.documentElement.clientWidth; + + const vertInView = rect.top <= windowHeight && rect.bottom >= 0; + const horInView = rect.left <= windowWidth && rect.right >= 0; + + return vertInView && horInView; +} +``` + +--- + +## 定时器与动画 + +### 31. setTimeout() + +**知识点**:在指定的毫秒数后执行一次函数。 + +```javascript +// 基本用法 +setTimeout(() => { + console.log("3秒后执行"); +}, 3000); + +// 带参数的函数 +function greet(name) { + console.log(`Hello, ${name}!`); +} +setTimeout(greet, 2000, "张三"); + +// 清除定时器 +const timeoutId = setTimeout(() => { + console.log("这个不会执行"); +}, 5000); + +// 在2秒后清除定时器 +setTimeout(() => { + clearTimeout(timeoutId); + console.log("定时器已清除"); +}, 2000); + +// 模拟异步操作 +function simulateAsyncTask(duration) { + console.log(`任务开始,需要 ${duration}ms`); + + return new Promise((resolve) => { + setTimeout(() => { + console.log("任务完成"); + resolve("结果"); + }, duration); + }); +} +``` + +### 32. setInterval() + +**知识点**:按照指定的周期(毫秒)重复执行函数。 + +```javascript +// 基本用法 +let counter = 0; +const intervalId = setInterval(() => { + counter++; + console.log(`计数器: ${counter}`); + + if (counter >= 10) { + clearInterval(intervalId); + console.log("定时器已停止"); + } +}, 1000); // 每秒执行一次 + +// 时钟示例 +function startClock() { + const clockElement = document.getElementById("clock"); + + const updateClock = () => { + const now = new Date(); + const timeString = now.toLocaleTimeString(); + clockElement.textContent = timeString; + }; + + // 立即更新一次 + updateClock(); + + // 每秒更新一次 + return setInterval(updateClock, 1000); +} + +// 动画示例(简单实现) +function animateElement(element, duration) { + const start = Date.now(); + const startPosition = 0; + const endPosition = 300; + + const intervalId = setInterval(() => { + const elapsed = Date.now() - start; + const progress = Math.min(elapsed / duration, 1); + + // 线性动画 + const currentPosition = + startPosition + (endPosition - startPosition) * progress; + element.style.left = currentPosition + "px"; + + if (progress >= 1) { + clearInterval(intervalId); + console.log("动画完成"); + } + }, 16); // 约60fps +} + +// 轮询示例 +function pollServer() { + const pollInterval = 5000; // 5秒 + + const poll = () => { + fetch("/api/status") + .then((response) => response.json()) + .then((data) => { + console.log("服务器状态:", data); + // 处理数据 + }) + .catch((error) => { + console.error("轮询错误:", error); + }); + }; + + // 立即执行一次 + poll(); + + // 然后每5秒执行一次 + return setInterval(poll, pollInterval); +} +``` + +### 33. requestAnimationFrame() + +**知识点**:为动画优化的定时器,在浏览器重绘之前执行。 + +```javascript +// 基本用法 +function animate() { + // 动画逻辑 + updateAnimation(); + + // 请求下一帧 + requestAnimationFrame(animate); +} + +// 启动动画 +requestAnimationFrame(animate); + +// 平滑动画示例 +function smoothAnimate(element, property, startValue, endValue, duration) { + const startTime = performance.now(); + + function animateFrame(currentTime) { + const elapsed = currentTime - startTime; + const progress = Math.min(elapsed / duration, 1); + + // 使用缓动函数 + const easeProgress = easeInOutCubic(progress); + const currentValue = startValue + (endValue - startValue) * easeProgress; + + element.style[property] = currentValue + "px"; + + if (progress < 1) { + requestAnimationFrame(animateFrame); + } + } + + requestAnimationFrame(animateFrame); +} + +// 缓动函数 +function easeInOutCubic(t) { + return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; +} + +// FPS计数器 +function createFPSCounter() { + let frameCount = 0; + let lastTime = performance.now(); + let fps = 0; + + function countFrame() { + frameCount++; + const currentTime = performance.now(); + + if (currentTime - lastTime >= 1000) { + fps = frameCount; + frameCount = 0; + lastTime = currentTime; + console.log(`FPS: ${fps}`); + } + + requestAnimationFrame(countFrame); + } + + requestAnimationFrame(countFrame); +} + +// 取消动画帧 +let animationFrameId; + +function startCustomAnimation() { + let position = 0; + + function animate() { + position += 1; + element.style.left = position + "px"; + + if (position < 300) { + animationFrameId = requestAnimationFrame(animate); + } + } + + animationFrameId = requestAnimationFrame(animate); +} + +function stopAnimation() { + if (animationFrameId) { + cancelAnimationFrame(animationFrameId); + console.log("动画已停止"); + } +} +``` + +--- + +## 📌 最佳实践总结 + +### 34. 窗口操作安全注意事项 + +```javascript +// 1. 弹出窗口通常会被浏览器阻止 +function safeOpenWindow(url) { + const newWindow = window.open(url); + + if ( + !newWindow || + newWindow.closed || + typeof newWindow.closed === "undefined" + ) { + // 弹出窗口被阻止 + console.warn("弹出窗口被浏览器阻止"); + // 提供备用方案 + window.location.href = url; // 在当前窗口打开 + return null; + } + + return newWindow; +} + +// 2. 用户交互后才能打开弹出窗口 +document.getElementById("openBtn").addEventListener("click", function () { + // 只有响应用户点击事件,弹出窗口才不会被阻止 + window.open("popup.html"); +}); + +// 3. 检查是否支持某些窗口特性 +function checkWindowFeaturesSupport() { + const features = { + localStorage: !!window.localStorage, + sessionStorage: !!window.sessionStorage, + geolocation: !!navigator.geolocation, + notifications: !!window.Notification, + serviceWorker: "serviceWorker" in navigator, + webSocket: "WebSocket" in window, + }; + + console.log("浏览器特性支持:", features); + return features; +} +``` + +### 35. 性能优化建议 + +```javascript +// 1. 防抖和节流窗口事件 +function debounce(func, wait) { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +} + +// 使用防抖的resize事件 +window.addEventListener( + "resize", + debounce(() => { + console.log("窗口大小已稳定"); + }, 250) +); + +// 2. 使用requestAnimationFrame替代setTimeout做动画 +function smoothAnimation() { + let start = null; + + function step(timestamp) { + if (!start) start = timestamp; + const progress = timestamp - start; + + // 更新动画 + element.style.left = Math.min(progress / 10, 200) + "px"; + + if (progress < 2000) { + requestAnimationFrame(step); + } + } + + requestAnimationFrame(step); +} + +// 3. 清理定时器防止内存泄漏 +class TimerManager { + constructor() { + this.timers = new Set(); + } + + setTimeout(callback, delay, ...args) { + const id = setTimeout( + () => { + this.timers.delete(id); + callback(...args); + }, + delay, + ...args + ); + + this.timers.add(id); + return id; + } + + clearAll() { + this.timers.forEach((id) => clearTimeout(id)); + this.timers.clear(); + } +} +``` + +--- + +## 🎯 Window 对象核心要点速查表 + +| 类别 | 方法/属性/事件 | 描述 | +| ------------ | ------------------------- | -------------- | +| **对话框** | `alert()` | 警告对话框 | +| | `confirm()` | 确认对话框 | +| | `prompt()` | 提示输入对话框 | +| **窗口控制** | `open()` | 打开新窗口 | +| | `close()` | 关闭窗口 | +| | `resizeTo()` | 调整窗口大小 | +| | `moveTo()` | 移动窗口 | +| **事件** | `load` | 页面完全加载 | +| | `DOMContentLoaded` | DOM 加载完成 | +| | `resize` | 窗口大小改变 | +| | `scroll` | 窗口滚动 | +| | `beforeunload` | 页面卸载前 | +| **定时器** | `setTimeout()` | 延迟执行 | +| | `setInterval()` | 间隔执行 | +| | `requestAnimationFrame()` | 动画帧 | +| **导航** | `location` | URL 操作 | +| | `history` | 历史记录 | +| | `navigator` | 浏览器信息 | +| **尺寸** | `innerWidth/Height` | 视口尺寸 | +| | `outerWidth/Height` | 窗口尺寸 | +| | `screen` | 屏幕信息 | + +--- + + + +# 练习 +1. p228 +- +```bash + + +``` + +- +```bash + 退出登录 + +``` + +2. p231 +- +```bash + 影片列表 + + + + + + 星际穿越 + + + + 盗梦空间 + + + + 阿甘正传 + + + + 楚门的世界 + + + + + + 关闭 + + + + + + + 年份: + 评分: + 导演: + 主演: + 简介: + + + + + + + + +``` + +- +```bash + + +``` + +3. p235 +- +```bash + + +``` + +- +```bash + + 00:00:00 + 开始 + 重置 + + +``` + +4. p235实践与练习 +- +```bash + let num1 = Math.floor(Math.random() * 10); + let num2 = Math.floor(Math.random() * 10); + let daan = prompt(num1 + '+' + num2 + '='); + let num3 = num1 + num2; + if (daan == num3) { + let bool = confirm('正确!是否继续?'); + if(bool == true){ + location.reload(); + }else{ + window.close(); + } + } else{ + alert('回答错误,再接再厉哦!'); + window.close(); + } +``` + +- +```bash + let Elvalue = prompt('2024年奥运会在哪座城市举办?\n'+'A.罗马\n'+'B.北京\n'+'C.伦敦\n'+'D.巴黎'); + if(Elvalue =='D'){ + document.write('回答正确!'); + }else{ + document.write('回答错误!'); + } +``` + +- +```bash + + + + +``` diff --git "a/\346\235\216\346\231\250\346\273\224/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" "b/\346\235\216\346\231\250\346\273\224/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" new file mode 100644 index 0000000000000000000000000000000000000000..ff1af9e974877b55041d4ecd87b73c90ff229237 --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251208-\346\265\217\350\247\210\345\231\250\345\257\271\350\261\241\346\250\241\345\236\213.md" @@ -0,0 +1,191 @@ +# 笔记 +## 一、Location 对象(页面跳转/刷新) +Location 对象是 `window.location` 的简写,专门用于控制浏览器 URL 相关操作,是页面导航的核心工具。 + +### 核心知识点 +1. **核心方法**: + | 方法 | 作用 | + |---------------------|----------------------------------------------------------------------| + | `location.assign(URL)` | 跳转到指定 URL 地址,保留浏览器历史记录(用户可点击“返回”回到原页面) | + | `location.reload()` | 刷新当前页面,等效于浏览器的刷新按钮 | +2. **延时跳转**:结合 `setTimeout` 实现“延迟 N 秒后跳转”,提升交互体验(如“3秒后自动跳转”),语法: + ```javascript + setTimeout(() => { + location.assign("目标URL"); + }, 延迟毫秒数); // 1秒=1000毫秒,如3000表示3秒 + ``` + +### 练习要点 +- 基础跳转:点击按钮直接调用 `location.assign("https://www.baidu.com/")` 跳转到百度; +- 延时跳转:3秒后跳转,核心是 `setTimeout` 包裹跳转逻辑,确保延迟执行。 + +## 二、定时器(setTimeout/setInterval) +定时器是 JavaScript 实现“延时执行/重复执行”逻辑的核心,分为单次定时器和循环定时器。 + +### 核心知识点 +1. **两类定时器对比**: + | 定时器类型 | 执行逻辑 | 清除方法 | 适用场景 | + |------------------|---------------------------|------------------------|------------------------| + | `setTimeout()` | 延迟指定时间**执行一次** | `clearTimeout(定时器ID)` | 延时跳转、延时提示等 | + | `setInterval()` | 每隔指定时间**重复执行** | `clearInterval(定时器ID)` | 计时器、实时刷新数据等 | +2. **关键特性**: + - 定时器调用后会返回一个**定时器ID**(数字),需存储该ID才能后续清除; + - 清除定时器是必做操作:暂停/重置计时器时,必须先清除定时器,否则会导致逻辑错乱(如多个定时器同时运行)。 + +### 练习要点 +- `setTimeout` 延时跳转:回调函数用箭头函数简洁,3000毫秒(3秒)后执行跳转; +- `setInterval` 实现计时器:每秒累加秒数,是循环定时器的典型应用。 + +## 三、计时器(秒表)功能实现(综合案例) +这是定时器+状态管理+DOM操作的综合应用,核心是实现“开始/暂停/重置”的完整秒表逻辑。 + +### 核心知识点 +1. **状态管理变量**(秒表核心): + - `seconds = 0`:存储累计秒数,是计时的核心数据; + - `timerId = null`:存储 `setInterval` 返回的定时器ID,用于清除定时器; + - `isRunning = false`:布尔值标记计时器“运行/暂停”状态,切换时用 `isRunning = !isRunning` 翻转状态。 +2. **时间格式化函数**(秒数转 HH:MM:SS): + ```javascript + function formatTime(sec) { + const hours = String(Math.floor(sec / 3600)).padStart(2, '0'); // 小时:总秒数÷3600 + const minutes = String(Math.floor((sec % 3600) / 60)).padStart(2, '0'); // 分钟:剩余秒数÷60 + const secs = String(sec % 60).padStart(2, '0'); // 秒:剩余秒数取余 + return `${hours}:${minutes}:${secs}`; + } + ``` + - `Math.floor()`:向下取整(避免小数); + - `padStart(2, '0')`:补零,确保小时/分钟/秒都是两位(如 1→01,9→09)。 +3. **核心逻辑**: + - 开始/暂停:判断 `isRunning`,运行则清除定时器+改按钮文字,暂停则启动定时器+改按钮文字,最后翻转状态; + - 重置:清除定时器 → 重置秒数 → 重置状态 → 重置显示和按钮文字(四步缺一不可)。 + +### 练习要点 +- 事件绑定:用 `addEventListener` 绑定按钮点击事件,解耦 HTML 和 JS(优于标签内 `onclick`); +- 健壮性:重置时必须清除定时器,否则即使重置秒数,旧定时器仍会继续累加,导致显示错误。 + +## 四、window.open 打开新窗口 +### 核心知识点 +1. **语法**:`window.open(URL, 窗口名称, 窗口参数)`; +2. **参数详解**: + - URL:新窗口要打开的页面地址(本地 HTML 文件/外网 URL); + - 窗口名称:自定义名称(如 'new'),可省略; + - 窗口参数:字符串形式,指定新窗口的尺寸、位置,常用参数: + - `width=数值`:窗口宽度; + - `height=数值`:窗口高度; + - `left=数值`:窗口距离屏幕左侧的距离; + - `top=数值`:窗口距离屏幕顶部的距离(参数间用逗号分隔)。 +3. **注意事项**:部分浏览器会拦截弹窗,需确保 `window.open` 由用户主动触发(如点击链接/按钮),避免被拦截。 + +### 练习要点 +- 点击 `` 标签打开新窗口,窗口尺寸 500×200,左侧位置 450,参数需严格按字符串格式书写(如 `'width=500,height=200,left=450'`)。 + +--- + +### 总结 +1. **页面导航**:`location.assign()` 实现跳转(可结合 `setTimeout` 延时),`location.reload()` 刷新页面; +2. **定时器**:`setTimeout` 单次延时执行,`setInterval` 重复执行,需用 `clearXXX` 清除,避免内存泄漏; +3. **计时器功能**:布尔变量管理运行状态,`padStart` 补零格式化时间,重置需清除定时器+恢复初始值; +4. **新窗口**:`window.open` 指定 URL 和窗口参数,需用户主动触发避免被浏览器拦截。 + + +# 练习 +1. p240 +- +```bash + + + +``` + +- +```bash + + 00:00:00 + 开始 + 重置 + + +``` + +2. p243实践与练习 +- +```bash + + +``` + +- +```bash +abc + +``` + diff --git "a/\346\235\216\346\231\250\346\273\224/20251210-Style\345\257\271\350\261\241.md" "b/\346\235\216\346\231\250\346\273\224/20251210-Style\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..a6d463af8ea3994315381ef208365f4e5f244c7a --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251210-Style\345\257\271\350\261\241.md" @@ -0,0 +1,223 @@ +# 笔记 +## 一、动态修改元素样式(字体、颜色、边框、尺寸) +### 核心知识点 +1. **样式值获取的两种核心方式**: + - 内联样式获取:`element.style.属性名`(仅能获取直接写在元素 `style` 属性里的样式,无值时返回空); + - 计算样式获取:`getComputedStyle(element).属性名`(获取元素最终渲染的样式,包含CSS类、浏览器默认样式,**推荐用于获取初始样式**); + - 数值处理:用 `parseFloat()` 提取样式中的数字(如 `16px` → `16`),结合 `||` 兜底默认值(如 `parseFloat(elem.style.fontSize)||parseFloat(getComputedStyle(elem).fontSize)`)。 +2. **随机十六进制颜色生成(高频实用技巧)**: + ```javascript + // 核心公式,生成 #xxxxxx 格式的随机颜色 + const randomColor = '#' + Math.floor(Math.random()*0xffffff).toString(16).padStart(6,'0'); + ``` + - 解析: + - `Math.random()*0xffffff`:生成 0~16777215(对应十六进制 `ffffff`)的随机数; + - `Math.floor()`:向下取整,去除小数; + - `toString(16)`:转为十六进制字符串; + - `padStart(6,'0')`:补零到6位(避免随机数不足6位导致颜色值无效)。 +3. **样式重置技巧**:给 `style.属性` 赋值空字符串(如 `elem.style.border = ''`),自动回退到CSS定义的默认样式,无需手动还原初始值。 + +### 练习要点 +- 字体放大+随机颜色案例:点击按钮时,先获取文字当前字号(内联无值则取计算样式),每次+2px,同时生成随机颜色赋值给文字色; +- 图片边框交互:鼠标移入(`mouseenter`)添加蓝色双边框,移出(`mouseleave`)重置边框,利用无冒泡的鼠标事件实现精准交互。 + +## 二、CSS 过渡(transition)与鼠标交互动画 +### 核心知识点 +1. **CSS transition 实现平滑动画**: + - 语法:`transition: 过渡属性 时长 缓动函数;`(可同时指定多个属性); + - 示例:`transition: width 0.3s ease,background-color 0.3s ease;`(宽度、背景色变化均0.3秒平滑过渡); + - 缓动函数 `ease`:默认值,效果为“先慢→快→慢”,是最符合直觉的过渡效果。 +2. **批量元素事件绑定**: + - 用 `document.querySelectorAll('.类名')` 获取所有同类元素; + - 通过 `forEach` 遍历元素,批量绑定事件(避免重复写事件绑定代码)。 +3. **样式切换逻辑**:鼠标移入修改目标样式(尺寸/背景色),移出恢复初始值,结合 `transition` 让样式变化无卡顿,提升交互体验。 + +### 练习要点 +- 讨论区模块交互案例: + - CSS 定义初始样式(宽度200px、背景色#ffd700)和过渡属性; + - 鼠标移入时宽度改为220px、背景色改为#fff176,移出恢复初始值; + - 核心优势:动画由CSS `transition` 处理,JS仅需修改样式值,代码简洁且动画更流畅。 + +## 三、自定义拖拽功能实现(绝对定位+鼠标事件) +拖拽是前端高频交互需求,核心依赖**绝对定位**和**鼠标事件组合**实现。 + +### 核心知识点 +1. **基础样式前提**: + - 拖拽元素必须设置 `position: absolute`(只有绝对定位才能通过 `top/left` 自由修改位置); + - 可选:`cursor: move` 提示用户元素可拖拽,提升交互友好性。 +2. **拖拽核心三步逻辑**: + ```mermaid + graph TD + A[鼠标按下(mousedown)] -->|1.记录初始值| B(记录鼠标坐标clientX/clientY、元素初始top/left,提升z-index避免遮挡) + B --> C[鼠标移动(mousemove)] -->|2.计算偏移| D(更新元素top=初始top+Y偏移,left=初始left+X偏移) + D --> E[鼠标松开(mouseup)] -->|3.清理事件| F(移除mousemove/mouseup事件,恢复z-index) + ``` +3. **关键细节**: + - `e.preventDefault()`:阻止浏览器默认行为(如文本选中、图片默认拖拽),避免干扰; + - `getComputedStyle(elem).top/left`:获取CSS定义的初始位置(而非内联样式),确保初始值准确; + - `parseInt()`:将 `100px` 这类带单位的样式值转为数字,便于计算偏移量。 + +### 练习要点 +- 多张图片拖拽案例: + - 遍历所有拖拽图片,给每张绑定独立的拖拽逻辑; + - 拖动时提升 `z-index` 让当前图片在最上层,松开后恢复,避免遮挡; + - `transform: rotate(角度)`:给图片添加旋转效果,不影响绝对定位和拖拽逻辑,丰富视觉表现。 + +--- + +### 总结 +1. **样式操作**:`getComputedStyle` 获取最终渲染样式,`parseFloat` 处理数值,空字符串重置样式;随机颜色需掌握十六进制生成公式并补零; +2. **交互动画**:CSS `transition` 实现平滑过渡,`mouseenter/mouseleave` 实现精准的移入移出交互,批量元素用 `querySelectorAll+forEach` 绑定事件; +3. **拖拽功能**:绝对定位是基础,mousedown记录初始值、mousemove计算偏移、mouseup清理事件是核心三步,注意阻止默认行为和z-index层级管理。 + + +# 练习 +1. p262 +- +```bash + 魏老帅很师 + + +``` + +- +```bash + + +``` + +2. p262 +- +```bash + + + HTML/CSS讨论区 + JavaScript讨论区 + C语言讨论区 + Java讨论区 + Android讨论区 + Python讨论区 + +``` + +- +```bash + 1.(AI) + + + + + + + +``` diff --git "a/\346\235\216\346\231\250\346\273\224/20251211-From\345\257\271\350\261\241.md" "b/\346\235\216\346\231\250\346\273\224/20251211-From\345\257\271\350\261\241.md" new file mode 100644 index 0000000000000000000000000000000000000000..ad55f6d1419abf243eea44ef7a6cb9e71b9f1b3f --- /dev/null +++ "b/\346\235\216\346\231\250\346\273\224/20251211-From\345\257\271\350\261\241.md" @@ -0,0 +1,275 @@ +# 笔记 +## 一、表单基础元素操作(输入框/文本域) +### 核心知识点 +1. **表单元素取值方式**: + - 表单关联取值:`document.表单name.元素name.value`(如 `document.myform.textvelue.value`),适用于表单内元素快速取值,无需单独获取元素; + - ID精准取值:`document.getElementById('id').value`,通用且不受表单结构限制,是**推荐优先使用**的方式; +2. **文本域(textarea)动态尺寸修改**: + - 获取当前尺寸:`parseInt(window.getComputedStyle(textarea).height)`,提取带单位(如95px)的数值部分,便于计算; + - 修改尺寸:`textarea.style.height = `${新值}px``,直接赋值内联样式覆盖初始样式; + - 边界控制:修改前添加下限判断(如 `if (curheight > 30)`),避免尺寸无限缩小导致交互异常; +3. **文本域溢出优化**:CSS设置 `overflow: auto`,当内容超出文本域尺寸时自动显示滚动条,保证内容可查看。 + +### 练习要点 +- 电影票兑换码验证:通过表单name快速获取输入框值,与固定兑换码对比,核心体现“取值→判断→提示”的基础表单验证逻辑; +- 文本域尺寸调整:点击“增加/减少”按钮修改高度,减少操作时加下限判断(最小30px),避免尺寸异常。 + +## 二、单选框(radio)交互 +### 核心知识点 +1. **单选框核心特性**:`name` 属性相同的单选框为一组,同一时间仅能选中一个,是实现“唯一选择”的基础; +2. **选中项获取**:`document.querySelector('input[name="xxx"]:checked')`,返回当前选中的单选框元素; + - 关键注意:未选中任何选项时返回 `null`,需先判断是否存在选中项,再获取 `value`; +3. **验证逻辑三步法**: + 1. 判断是否选中(`if (!selected)`),提示用户选择; + 2. 对比选中值与正确答案; + 3. 根据对比结果给出提示。 + +### 练习要点 +- 选择题验证案例:先检查是否选中选项,再判断值是否为“C”,覆盖单选框交互的核心场景(空值判断+值对比)。 + +## 三、复选框(checkbox)交互 +### 核心知识点 +1. **复选框批量操作(全选/全不选/反选)**: + - 获取所有复选框:`document.querySelectorAll('.类名')`(返回伪数组),通过 `forEach` 遍历实现批量修改; + - 全选:`forEach(box => box.checked = true)`; + - 全不选:`forEach(box => box.checked = false)`; + - 反选:`forEach(box => box.checked = !box.checked)`(利用 `!` 翻转选中状态,极简实现); +2. **复选框数量限制**: + - 绑定 `change` 事件:选中/取消时实时触发,统计当前选中数量; + - 统计选中数:`Array.from(checkboxes).filter(cb => cb.checked).length`(伪数组转数组后过滤选中项); + - 超出限制处理:将当前复选框 `checked` 设为 `false` 阻止选中,同时弹窗提示; +3. **表单内复选框获取**:`form.elements['name']`(通过form对象按name获取复选框组),更贴合表单上下文。 + +### 练习要点 +- 兴趣爱好选择:仅需3行forEach逻辑实现全选、全不选、反选,是复选框批量操作的典型应用; +- 课程选择限制:最多选6个,在change事件中统计数量,超出则取消当前选中,解决“多选限制”的常见需求。 + +## 四、下拉选择框(select)交互(省市联动) +### 核心知识点 +1. **下拉框核心操作**: + - 初始化选项:通过 `innerHTML` 拼接 `` 标签字符串,批量生成选项; + - `Object.keys(data)`:获取对象的所有键(如省份名),快速生成省份选项; + - `map+join` 优化:`data[p].map(c => `${c}`).join('')`,遍历数组生成选项并拼接成字符串,避免多次修改innerHTML; +2. **联动核心逻辑**: + - 给省份下拉框绑定 `onchange` 事件,选中值变化时即时触发; + - 根据选中省份,从数据对象中获取对应城市列表,动态更新城市选项; + - 无省份选中时,城市下拉框恢复“请选省份”提示项; +3. **数据结构**:用对象存储省市映射(键:省份名,值:城市数组),结构清晰,便于联动取值。 + +### 练习要点 +- 省市联动案例: + - 初始化:拼接默认提示项 + 省份选项; + - 联动:省份切换时动态更新城市选项,无选中则恢复提示项,是下拉框联动的经典实战场景。 + +--- + +### 总结 +1. **表单取值**:优先用ID取值(通用精准),form对象取值适用于表单内快速操作,所有输入类元素均通过 `.value` 获取值; +2. **单选/复选框**:单选框需先判断是否选中,复选框批量操作依赖 `forEach`,数量限制需在 `change` 事件中统计并拦截; +3. **下拉框联动**:基于 `onchange` 事件,结合对象数据结构动态生成子选项,`map+join` 提升选项拼接效率; +4. **边界控制**:文本域尺寸、复选框数量等需添加边界判断,避免交互异常,提升用户体验。 + + +# 练习 +1. p275 +- +```bash +
${message}
年份:
评分:
导演:
主演:
简介:
魏老帅很师