当前位置: 首页 > ai >正文

赋予网页健壮的灵魂 —— TypeScript(下)

7 DOM 操作与类型定义:赋予网页真正的交互

回到最初的目标:让网页动起来。在 TypeScript 中,我们如何安全地操作 HTML 元素并响应用户的交互呢?TypeScript 提供了内置的类型定义来描述浏览器环境中的各种对象(如 document, window, DOM 元素,事件对象等),这使得我们在操作 DOM 时也能享受到类型检查带来的便利和安全。

7.1 获取 DOM 元素及其类型

当你使用像 document.getElementById()document.querySelector() 这样的方法获取 DOM 元素时,TypeScript 会根据方法签名返回一个特定的类型。

  • document.getElementById() 返回 HTMLElement | null
  • document.querySelector() 返回 Element | null (更通用的类型)。

它们返回的可能是找到的元素类型(如果是特定标签,会有更精确的类型,比如 HTMLDivElement for <div>),或者在找不到元素时返回 null

// seventh.ts// 获取一个 div 元素
const myDiv = document.getElementById("myDiv");// myDiv 的类型是 HTMLElement | null
if (myDiv) {// 在这个 if 块中,myDiv 的类型被缩小为 HTMLElementmyDiv.textContent = "你好,DOM!";// HTMLElement 类型有通用的属性和方法console.log("Div 元素的标签名:", myDiv.tagName);
} else {console.error("找不到 id 为 myDiv 的元素");
}// 获取一个输入框元素
const myInput = document.getElementById("myInput");// myInput 的类型是 HTMLElement | null
if (myInput) {// 如果确定它是 input 元素,并且你需要访问 input 特有的属性 (如 value),// 你需要使用类型断言或者更精确的选择器方法。// 直接访问 value 会报错,因为 HTMLElement 上没有 value 属性// console.log(myInput.value); // 编译时报错// 使用类型断言const inputElement = myInput as HTMLInputElement;console.log("输入框的值 (断言):", inputElement.value);// 或者使用更精确的查询方法(如果存在)或结合类型守卫(后面会讲)// const inputElement2 = document.querySelector<HTMLInputElement>("#myInput"); // 泛型方法// if (inputElement2) {//   console.log("输入框的值 (querySelector 泛型):", inputElement2.value);// }
}

7.2 类型断言用于 DOM 元素

当你明确知道获取到的元素的具体类型时(比如你确定一个通过 ID 获取的元素就是 <canvas>),可以使用类型断言将其断言为更精确的类型,以便访问该元素特有的属性和方法。

// seventh.ts (接着上面的代码)// 假设 HTML 中有一个 <canvas id="myCanvas"></canvas>
const canvas = document.getElementById("myCanvas") as HTMLCanvasElement;// 现在 TypeScript 知道 canvas 是 HTMLCanvasElement 类型,可以安全地访问 getContext 方法
if (canvas) {const ctx = canvas.getContext("2d");if (ctx) {ctx.fillStyle = 'red';ctx.fillRect(10, 10, 50, 50);}
}

7.3 事件处理

处理用户交互依赖于事件。TypeScript 为各种事件提供了类型定义,这使得在事件处理函数中访问事件对象 (evente) 的属性时也能获得类型提示和检查。

// seventh.ts (接着上面的代码)const myButton = document.getElementById("myButton"); // 假设 HTML 中有一个 <button id="myButton">点击我</button>if (myButton) {// 添加点击事件监听器myButton.addEventListener("click", (event: MouseEvent) => {// event 参数是 MouseEvent 类型,具有 clientX, clientY 等属性console.log("按钮被点击了!");console.log("点击位置:", event.clientX, event.clientY);// event 对象是 Event 或其子类型event.preventDefault(); // 阻止默认行为});
}const myTextInput = document.getElementById("myTextInput") as HTMLInputElement; // 假设 HTML 中有一个 <input type="text" id="myTextInput">if (myTextInput) {// 添加键盘按下事件监听器myTextInput.addEventListener("keydown", (event: KeyboardEvent) => {// event 参数是 KeyboardEvent 类型,具有 key, code 等属性console.log("键盘按下:", event.key, event.code);if (event.key === 'Enter') {console.log("按下了 Enter 键,当前输入框的值:", myTextInput.value);}});
}

常见的事件类型:Event, MouseEvent, KeyboardEvent, ChangeEvent, SubmitEvent 等。

7.4 获取第三方库的类型定义 (@types)

很多流行的 JavaScript 库(如 jQuery, React, Lodash 等)最初并不是用 TypeScript 编写的。为了让 TypeScript 用户能够享受到类型检查和智能提示,社区维护了大量的类型声明文件 (.d.ts 文件)。这些文件只包含类型信息,不包含具体的实现代码。

这些类型声明文件通常发布在 @types 组织下,你可以使用 npm 或 yarn 安装它们。

例如,如果你想在 TypeScript 项目中使用 Lodash 库:

  1. 安装 Lodash: npm install lodash
  2. 安装 Lodash 的类型声明文件: npm install @types/lodash --save-dev

现在,你就可以在 TypeScript 代码中导入并使用 Lodash 了,TypeScript 会根据 @types/lodash 中的类型信息为你提供强大的类型检查和代码补全。

// seventh.ts (接着上面的代码)// 我们通过declare const _: any;告诉TypeScript全局lodash变量的存在
declare const _: any;const numbers = [1, 2, 3, 4, 5];
const sumOfNumbers = _.sum(numbers); // TypeScript 知道 _.sum 接受一个 number 数组并返回一个 number
console.log("数字总和 (lodash):", sumOfNumbers);const users = [{ 'user': 'barney', 'age': 36, 'active': true },{ 'user': 'fred',   'age': 40, 'active': false }
];const activeUsers = _.filter(users, { 'active': true }); // TypeScript 知道 filter 的用法和返回类型
console.log("活跃用户 (lodash):", activeUsers);

当你安装一个本身就是用 TypeScript 编写的库时(比如 React 的新版本、Vue 3 等),它们通常已经自带了类型声明文件,你无需额外安装 @types 包。

编译 seventh.ts

tsc seventh.ts

会生成 seventh.js 文件。然后在 HTML 中引入 seventh.js,并确保你的 HTML 中有相应的 div, input, button, canvas 元素。

<!DOCTYPE html>
<html>
<head> <title>TS DOM 操作</title> </head>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<body><div id="myDiv">这是一个 div</div><input type="text" id="myInput" value="默认值"><input type="text" id="myTextInput"><button id="myButton">点击触发事件</button><canvas id="myCanvas" width="200" height="100" style="border: 1px solid black;"></canvas><script src="dist/seventh.js"></script> </body>
</html>

小结: TypeScript 提供了丰富的内置类型来描述 DOM 和事件对象,结合类型断言和 @types 声明文件,可以让我们在进行客户端 DOM 操作和使用第三方库时,编写出类型安全、易于维护的代码。

练习:

  1. 创建一个 HTML 文件,包含一个段落 <p id="myParagraph">原始文本</p> 和一个按钮 <button id="changeTextBtn">改变文本</button>
  2. 编写 TypeScript 代码:获取段落和按钮元素,为按钮添加点击事件监听器。在事件处理函数中,获取段落元素,并将其 textContent 修改为“文本已更新!”。确保在 TypeScript 代码中使用了合适的类型。
  3. 创建一个 HTML 文件,包含一个图像元素 <img id="myImage" src="" alt="图片"> 和一个输入框 <input type="text" id="imageUrlInput" placeholder="输入图片 URL">
  4. 编写 TypeScript 代码:获取图像元素和输入框。为输入框添加 change 事件监听器(当输入框的值改变并失去焦点时触发)。在事件处理函数中,获取输入框的值,并将其设置为图像元素的 src 属性。
  5. (进阶)选择一个你感兴趣的流行 JavaScript 库(如 Moment.js),尝试使用 npm 安装它以及对应的 @types 包,然后在 TypeScript 代码中导入并使用该库的功能,体验类型提示。
http://www.xdnf.cn/news/3814.html

相关文章:

  • Circular Plot系列(五): circle plot展示单细胞互作
  • 电动调节V型球阀的作用:专为颗粒状含碱浆液介质打造的高效解决方案-耀圣
  • 第 14 届蓝桥杯 C++ 青少组省赛中 / 高级组真题解析
  • 开源项目:optimum-quanto库介绍
  • 全面掌握 Jetpack Compose 的 State 体系:核心用法与最佳实践
  • 动态规划(5)路径问题--剑指offer -珠宝的最大值
  • 7 微调 黑盒蒸馏 突破伦理限制
  • STM32外设-GPIO输入(仅数字)
  • [GESP202503 四级] 二阶矩阵c++
  • Spring AI 实战:第八章、Spring AI Tool Calling之与时俱进
  • Android Framework学习三:zygote剖析
  • 轻量化定时工具!Pt 极简界面 :定时备份 + 循环灵活关机
  • 基于springboot3+mybatis整合,使用mybatisPlus插件自动完成简单的 增删改查操作
  • LeetCode 热题 100 189. 轮转数组
  • 多语言笔记系列:Polyglot Notebooks 混合使用多语言并共享变量
  • 第三节:OpenCV 基础入门-安装与配置 OpenCV (Python/C++ 环境)
  • LeetCode 1128.等价多米诺骨牌对的数量:计数
  • 大连理工大学选修课——图形学:第五章 二维变换及二维观察
  • 多语言笔记系列:Polyglot Notebooks 多种使用方式
  • [2025]MySQL的事务机制是什么样的?redolog,undolog、binog三种日志的区别?二阶段提交是什么?ACID怎么保证的?主从复制的过程?
  • JVM happens-before 原则有哪些?
  • 利用KMP找出模式串在目标串中所有匹配位置的起始下标
  • 【25软考网工】第五章(4)ARP和RARP
  • 【Touching China】2007-2011
  • Go语言--语法基础4--基本数据类型--类型转换
  • MPI,Pthreads和OpenMP等并行实验环境配置
  • 【第三十四周】多模态大模型调研
  • Uni-app 组件使用
  • 什么是Linux中的systemd?
  • leetcode 59. 螺旋矩阵 II