使用TypeScript写一个计算器
先搞界面
创建index.html
和calc.ts
,然后运行tsc -w calc.ts
命令,-w
选项在我们修改保存ts文件时可以实时输出js
文件,在index.html
中引入这个js
文件。
使用命令行工具进入当前目录,运行http-server -c-1
(-c-1旨在禁用缓存)。这样我们就可以使用浏览器进行预览了。
按钮部分
type reflect = {
'div': HTMLDivElement,
'span': HTMLSpanElement,
'button': HTMLButtonElement
}
class Calculator {
public container: HTMLDivElement; // 整个"计算器"的容器
public textList: Array<Array<string | number>> = [ // 二维数组,数组中的每一项是string | number
['Clear', '÷'],
[7, 8, 9, '×'],
[4, 5, 6, '-'],
[1, 2, 3, '+'],
[0, '.', '='],
]
// 创建实例的时候完成创建元素
constructor() {
this.createContainer();
this.createButtons();
}
/**
* 完成tag的创建 添加类名以及标签内容
* @param tagName 标签名
* @param className 类名
* @param eleContent 元素内容
* @returns HTMLDivElement | HTMLSpanElement | HTMLButtonElement
*/
selfCreateEle<T extends keyof reflect>(tagName: string, className?: string, eleContent?: string | number): reflect[T] {
let element = document.createElement(tagName) as reflect[T];
className && element.classList.add(className);
(eleContent || eleContent === 0) && (element.textContent = String(eleContent));
return element;
}
createContainer(): void { // void代表没有返回值
let container = this.selfCreateEle('div', 'container') as reflect['div'];
document.body.appendChild(container);
this.container = container;
}
createButtons() {
this.textList.map((arr: Array<string | number>) => {
arr.map((item: string | number) => {
this.container.appendChild(this.selfCreateEle('button', `c-${item}`, item))
})
})
}
}
let calc = new Calculator();
// 按钮部分的渲染就完成啦
显示部分
要显示两个操作数,一个操作符和一个结果,所以决定用四个标签来存放。
在类中添加以下代码:
// 为Calculator添加新的属性
public spanNum1: HTMLSpanElement;
public spanNum2: HTMLSpanElement;
public spanOperator: HTMLSpanElement;
public screenResult: HTMLDivElement;
// 在constructor中调用
createScreenElements() {
let screen = this.selfCreateEle('div', 'screen');
let [spanNum1, spanOperator, spanNum2] = [
...[1, 2, 3].map(() => { // 这里...是扩展运算符,将三个值分别赋给spanNum1, spanOperator, spanNum2
let span = this.selfCreateEle('span')
screen.appendChild(span);
return span
})
]
// 结果
let screenResult = this.selfCreateEle('div', 'output') as reflect['div'];
screen.appendChild(screenResult);
spanNum1.textContent = '0';
this.spanNum1 = spanNum1;
this.spanNum2 = spanNum2;
this.spanOperator = spanOperator;
this.screenResult = screenResult;
this.container.appendChild(screen);
}
浅浅的写一下css
button {
border: none;
margin: 4px 6px;
padding: 0;
border-radius: 4px;
}
.container {
width: 300px;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: minmax(70px, auto);
border: 4px solid grey;
border-radius: 3px;
}
.screen {
font-size: 20px;
height: 100px;
grid-column: 1 / 5;
grid-row: 1;
padding: 10px;
}
/* 对应button clear */
.c-Clear {
grid-column: 1 / 4;
}
/* 对应button 0 */
.c-0 {
grid-column: 1 / 3;
}
得到如下图的效果。
完成功能
为按钮添加功能
在类中添加以下代码:
// 为Calculator添加新的属性
public n1: string = '';
public n2: string = '';
public isResult: boolean = false;
public operator: string = '';
public result: string = '';
// 在constructor中调用
bindEvents() {
this.container.addEventListener('click', event => {
if (event.target instanceof HTMLButtonElement) {
const text = event.target.textContent as string;
if ('0123456789.'.indexOf(text) >= 0) {
// 当前已经输出结果且重新输入数字 则需要清除之前的输入和结果
if (this.isResult) clearNumAndOperator()
if (this.operator) {
this.n2 += this.dealwithZeroAndDot(text, this.n2);
this.spanNum2.textContent = this.n2;
} else {
this.result = '';
this.n1 += this.dealwithZeroAndDot(text, this.n1);
this.spanNum1.textContent = this.n1;
}
} else if ('+-×÷'.indexOf(text) >= 0) {
if (this.result) {
this.n1 = this.result;
this.result = '';
}
this.operator = text;
this.spanOperator.textContent = text
} else if ('='.indexOf(text) >= 0) {
this.isResult = true;
this.result = this.removeZero(this.getResult(this.n1, this.n2, this.operator));
this.screenResult.textContent = '=' + this.result;
} else if (text === 'Clear') {
clearNumAndOperator()
}
}
});
const clearNumAndOperator = () => {
this.n1 = '';
this.n2 = '';
this.operator = '';
this.spanNum1.textContent = '0'
this.spanNum2.textContent = ''
this.spanOperator.textContent = ''
this.screenResult.textContent = ''
this.isResult = false
}
}
/**
* 处理输入时多个小数点 和 以零开头的多个0
* @param curButtonValue 当前点击按钮的值
* @param str 之前输入的值
* @returns
*/
dealwithZeroAndDot(curButtonValue, str) {
let ZeroIndex = str.indexOf('0')
let DotIndex = str.indexOf('.')
if (curButtonValue == '0' && ZeroIndex == 0 && DotIndex == -1) return ''
if (curButtonValue == '.' && str === '') return "0" + curButtonValue
if (curButtonValue == '.' && DotIndex >= 0) return ''
return curButtonValue
}
/**
* 处理结果中结尾多余的零和小数点
* @param string 结果
* @returns 处理后的结果
*/
removeZero(string) {
return string.replace(/0+$/g, '').replace(/\.$/, ' ');
}
getResult(n1: string, n2: string, operator: string) {
let numberN1: number = parseFloat(n1);
let numberN2: number = parseFloat(n2);
if (operator === '+') {
return (numberN1 + numberN2).toPrecision(12);
} else if (operator === '-') {
return (numberN1 - numberN2).toPrecision(12);
} else if (operator === '×') {
return (numberN1 * numberN2).toPrecision(12);
} else if (operator === '÷') {
if (numberN2 === 0) {
return '除数不能为零';
} else {
return (numberN1 / numberN2).toPrecision(12);
}
}
}
一个简易的计算器就这样完成啦。