TypeScript 100天 (第8天)





5.00/5 (1投票)
一个简单的基于Web的计算器展示了如何让TypeScript与网页内容交互
在上一篇博客的结尾,我说过我们将开始学习如何在网页上使用 TypeScript。在这篇文章中,我们将创建一个简单的基于 Web 的计算器,展示 TypeScript 如何与网页内容进行交互。在开发代码的过程中,我想展示如何在 TypeScript 中使用“老派”的 JavaScript 风格函数。
一如既往,本文的代码可在GitHub上找到。
设计
我想限制计算器的输入,使其按钮按下操作仅限于一组已知的输入。基本上,我希望每个按钮都能触发一个数字或某种类型的运算符。为了选择我们要使用的运算符,我决定创建一个名为 calculator.ts 的 TypeScript 文件,并在其中添加一个 Operator
枚举。我已经将此文件添加到了解决方案的根目录。
enum Operator {
add = '+',
subtract = '-',
multiply = '*',
divide = '/',
period = '.'
}
在我展示计算器 TypeScript 代码之前,先设置好 HTML 页面。
<!DOCTYPE html>
<head>
<title>100 Days of TypeScript - Calculator</title>
</head>
<body>
<table border="1">
<th colspan="4"><input id="display"></input></th>
</table>
<script src="scripts/calculator.js"></script>
</body>
这里是一个 HTML 页面,显示了一个表格,带有一个标题行,宽度为 4 列,用于显示任何计算结果。我还添加了一个 script
标签来加载计算器脚本。您会注意到,虽然计算器 TypeScript 文件的源文件在 root 文件夹中,但 src 指向的是 scripts 文件夹。为了让 TypeScript 写入此文件夹,我们需要调整 tsconfig.json 文件。我已将我的 tsconfig 文件精简至此。
{
"compilerOptions": {
"lib": [
"DOM", "ES2015"
],
"outDir": "./scripts",
"strict": true,
"noUnusedLocals": true,
}
}
这些条目中有两个非常值得关注。outDir
键是我们设置 输出 目录的地方;这就是我将 calculator.js 文件写入 scripts 目录的方式。lib
条目也很有趣,因为我在这里添加了一个 DOM 条目。当我们在 lib 中指定条目时,我们是在告诉 TypeScript 需要引入哪些库,例如 ES2015 条目会引入 ECMA 功能。我们希望计算器能够做的一件事是将输入复制到剪贴板,这是一个在 window.navigator
对象上进行的操作。为了访问 navigator,我们必须引入 DOM 库,它允许我们与浏览器文档对象模型 (Document Object Model) 进行交互。有点令人困惑的是,您不需要 DOM 库即可与窗口文档等其他标准功能进行交互。
在将计算器按钮添加到表格之前,我还可以做一些其他的设置。我知道我的表格有一个名为 display
的输入字段。我稍后想与它交互,因此我将编写一个小辅助函数,让我在处理它时更轻松。我将创建一个变量来存储对该输入的引用。由于我将绑定到此值,因此我将添加一个辅助方法,该方法将在首次访问时惰性填充此引用,并在后续调用中返回存储的版本。
let displayElement: HTMLInputElement | null = null;
function getDisplay(): HTMLInputElement {
if (!displayElement) {
displayElement = <HTMLInputElement>document.getElementById('display');
}
return displayElement;
}
这段代码的意思是,displayElement
可以是 HTMLInputElement
类型,或者可以是 null
,表示我们还没有将其连接到 display 元素。TypeScript 在这方面非常有用,我们可以强类型化我们的网页输入,因此在 JavaScript 中原本是 object
的内容可以被约束为实际类型。这很有用,因为它告诉我们有哪些属性和操作可供我们使用。为了填充 displayElement
,我们使用 document.getElementById
。这是一个标准的浏览器方法,允许我们根据 ID 选择元素(ID 在网页的实际标签中设置)。现在,document.getElementById
的返回类型是 object
,所以我们需要使用一种称为类型转换的技术将其设置为适当的类型。TypeScript 提供了几种不同的对象转换方式,但在我们的情况下,我们使用 <>
来指定适当的类型。
让我们添加表格的其余部分。
<tr>
<td colspan="2"><input type="button" onclick="clearAll()" value="Clear" /></td>
<td colspan="2"><input type="button" onclick="copyToClipboard()" value="Mem" /></td>
</tr>
<tr>
<td><input type="button" value="1" onclick="display(1)"/> </td>
<td><input type="button" value="2" onclick="display(2)"/> </td>
<td><input type="button" value="3" onclick="display(3)"/> </td>
<td><input type="button" value="/" onclick="display(Operator.divide)"/> </td>
</tr>
<tr>
<td><input type="button" value="4" onclick="display(4)"/> </td>
<td><input type="button" value="5" onclick="display(5)"/> </td>
<td><input type="button" value="6" onclick="display(6)"/> </td>
<td><input type="button" value="-" onclick="display(Operator.subtract)"/> </td>
</tr>
<tr>
<td><input type="button" value="7" onclick="display(7)"/> </td>
<td><input type="button" value="8" onclick="display(8)"/> </td>
<td><input type="button" value="9" onclick="display(9)"/> </td>
<td><input type="button" value="+" onclick="display(Operator.add)"/> </td>
</tr>
<tr>
<td><input type="button" value="." onclick="display(Operator.period)"/> </td>
<td><input type="button" value="0" onclick="display(0)"/> </td>
<td><input type="button" value="=" onclick="solve()"/> </td>
<td><input type="button" value="*" onclick="display(Operator.multiply)"/> </td>
</tr>
每个按钮根据我们想做的事情,都连接到四个函数之一。让我们从显示函数开始,该函数与我们之前添加到枚举中的数字和运算符相关联。
function display(value: number | Operator): void {
const htmlElement = getDisplay();
htmlElement.value = htmlElement.value.trim() + value;
}
此函数接受数字或运算符之一。我喜欢 TypeScript 为我们提供了联合运算符,可以使用 |
来表示值可以是其中一种类型。
在函数内部,我们使用上面编写的函数获取对输入元素的引用。一旦我们有了这个元素,我们就会从中获取值,并将数字或运算符添加到其中。我对 htmlElement.value
调用 trim()
操作,以防用户在输入末尾留有空格。
如果我想清除输入,可以使用以下方法:
function clearAll(): void {
const htmlElement = getDisplay();
htmlElement.value = '';
}
这与我们的显示函数非常相似,因为它获取 html 输入元素(事实上,我们将看到我们所有的函数都会这样做)。一旦有了引用,它就会直接与 value
交互并将其设置为空字符串。
您可能会认为 solve
函数会很复杂,需要解析我们的输入并对其进行计算。实际上,借助一个名为 eval
的标准 JavaScript 函数,它可以评估输入的结果,这个函数非常简单。
function solve(): void {
const htmlElement = getDisplay();
const output = eval(htmlElement.value);
htmlElement.value = output;
}
最后,我们来看一下将输入复制到剪贴板的代码。如前所述,我们将利用 navigator
对象,这就需要我们导入 DOM 库。
function copyToClipboard(): void {
const htmlElement = getDisplay();
navigator.clipboard.writeText(htmlElement.value);
}
您可能还记得我说过 navigator
对象位于 window.navigator
中。为了方便起见,我们的代码通常不需要指定 window 部分,因此我们可以直接访问 navigator
。
最后说明
您可能会问,为什么我选择使用 input type="button"
而不是直接使用 button
元素。我选择 input 方式是因为人们会熟悉它,而且我不需要设置按钮内的其他内容,例如显示图像。
结论
就是这样。这就是我们第一个由 TypeScript 驱动的网页。我希望您对将 TypeScript 连接到 HTML 的便捷程度感到印象深刻。在第 9 天,我们将继续深入 Web 开发的世界,学习创建一个简单的共享报告应用程序。