明天的太阳

导航

使用TypeScript写一个计算器

先搞界面

创建index.htmlcalc.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;
}

得到如下图的效果。
image

完成功能

为按钮添加功能

在类中添加以下代码:

// 为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);
        }
    }
}

一个简易的计算器就这样完成啦。

posted on 2022-12-14 13:47  东方来客  阅读(375)  评论(0编辑  收藏  举报