import { Directive, HostListener, Renderer2, ElementRef, OnInit, AfterViewChecked, ChangeDetectorRef } from '@angular/core'; import { plus, minus, times, divide, } from './precision'; import { NotifyService } from '@farris/ui-notify'; @Directive({ selector: '[farrisCalculator]' }) export class CalculatorDirective implements OnInit, AfterViewChecked { // 计算器本身 private selfEl: HTMLElement; // 操作步骤显示区 private stepEl: HTMLElement; // 计算结果显示区 private resultEl: HTMLElement; // 按钮区 private symbolEl: HTMLElement; private preEl: HTMLElement; private leftEl: HTMLElement; private rightEl: HTMLElement; private number = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; // 操作步骤缓存 private stepInputCache: any = ''; // 结果缓存 private resultInputCache: any = '0'; // 记录加减乘除的数字 private preNumber: any[] = []; // 记录加减乘除符号 private preOperator: any[] = []; // 记录能否追加运算或者数字是追加还是覆盖 private firstInputToken: boolean; private equalToken: boolean; constructor( private el: ElementRef, private rd: Renderer2, private notifyService: NotifyService, private cdr: ChangeDetectorRef ) { } ngOnInit() { this.selfEl = this.el.nativeElement; this.stepEl = this.selfEl.querySelector('#std-pre-step'); this.resultEl = this.selfEl.querySelector('#std-show-input'); this.symbolEl = this.selfEl.querySelector('#std-num-symbol'); this.preEl = this.selfEl.querySelector('.pre'); this.leftEl = this.selfEl.querySelector('.pre_left'); this.rightEl = this.selfEl.querySelector('.pre_right'); this.rd.listen(this.rightEl, 'click', () => { this.stepEl.scrollLeft += 50; }); this.rd.listen(this.leftEl, 'click', () => { this.stepEl.scrollLeft -= 50; }); } ngAfterViewChecked(): void { this.calculateWidth(); } calculateWidth() { if (this.stepEl.scrollWidth > this.preEl.offsetWidth) { this.leftEl.style.display = 'block'; this.rightEl.style.display = 'block'; } else { this.leftEl.style.display = 'none'; this.rightEl.style.display = 'none'; } } /** * @param value 设置步骤显示区的内容 */ setStepInput(value: any) { this.stepEl.innerHTML = value; } /** * * @param value 设置结果示区的内容 */ setResultInput(value: any) { this.resultEl.innerHTML = value; } /** * 步骤操作视窗中,最后显示的是否是操作符 */ stepInputEndIsOperator() { return this.stepInputCache.lastIndexOf('+') !== -1 || this.stepInputCache.lastIndexOf('-') !== -1 || this.stepInputCache.lastIndexOf('×') !== -1 || this.stepInputCache.lastIndexOf('÷') !== -1; } /** * 加减乘除运算 * @param f 第一个数字 * @param s 第二个数字 * @param o 操作符 */ calculate(f: number, s: number, o: string) { let result: number; f = Number(f); s = Number(s); switch (o) { case '+': result = plus(f, s); break; case '-': result = minus(f, s); break; case '×': result = times(f, s); break; case '÷': result = divide(f, s); break; } return result; } /** * numberClick,dotClick,operatorClick,pnClick,equalClick,ceClick,cClick,backClick等,对应着点击相关的按钮操作 * @param val */ numberClick(val: any) { if ((this.resultInputCache.indexOf('0') === 0 && this.resultInputCache.indexOf('.') === -1) || this.firstInputToken === true) { this.resultInputCache = val; } else { this.resultInputCache += val; } this.firstInputToken = false; this.equalToken = false; } dotClick(val: any) { if (this.firstInputToken === true) { this.resultInputCache = '0' + val; } else { if (this.resultInputCache.indexOf('.') === -1) { this.resultInputCache += val; } } this.firstInputToken = false; this.equalToken = false; } pnClick() { if (this.resultInputCache.indexOf('-') === -1 && this.resultInputCache !== '0') { this.resultInputCache = "-" + this.resultInputCache; } else if (this.resultInputCache.indexOf('-') > -1 && this.resultInputCache !== '0') { this.resultInputCache = this.resultInputCache.substring(1); } } operatorClick(val: any) { if (this.preNumber.length < 2 && (this.firstInputToken !== true || this.equalToken === true)) { this.resultInputCache = parseFloat(this.resultInputCache) + ''; this.stepInputCache = this.stepInputCache + ' ' + this.resultInputCache + ' ' + val; this.preNumber.push(this.resultInputCache); this.preOperator.push(val); this.firstInputToken = true; } else if (this.preNumber.length < 2 && this.stepInputEndIsOperator()) { this.stepInputCache = this.stepInputCache.substring(0, this.stepInputCache.length - 1) + '' + val; this.preOperator.push(val); } if (this.preNumber.length === 2) { const operator = this.preOperator[this.preOperator.length - 2]; if (this.preNumber[1] === '0' && operator === '÷') { this.preNumber = []; this.resultInputCache = '除数不能为零'; this.stepInputCache = ''; this.firstInputToken = true; return; } const res = this.calculate(this.preNumber[0], this.preNumber[1], operator); this.preNumber = []; this.preNumber.push(res); this.resultInputCache = res + ''; this.firstInputToken = true; } this.cdr.detectChanges(); } equalClick() { if (this.preNumber.length > 0) { const operator = this.preOperator.pop(); if (this.resultInputCache === '0' && operator === '÷') { this.preNumber = []; this.resultInputCache = '除数不能为零'; this.stepInputCache = ''; this.firstInputToken = true; this.equalToken = true; return; } const res = this.calculate(this.preNumber[0], this.resultInputCache, operator); this.preNumber = []; this.resultInputCache = res + ''; this.stepInputCache = ''; this.firstInputToken = true; this.equalToken = true; } this.cdr.detectChanges(); } ceClick() { this.resultInputCache = '0'; } cClick() { this.resultInputCache = '0'; this.stepInputCache = ''; this.firstInputToken = true; this.preNumber = []; this.preOperator = []; this.cdr.detectChanges(); } backClick() { this.resultInputCache = this.resultInputCache.length > 1 ? this.resultInputCache.substring(0, this.resultInputCache.length - 1) : '0'; } @HostListener('click', ['$event']) click(event: any) { if (!this.symbolEl.contains(event.target)) { return; } const val = event.target.innerHTML; // if (this.resultInputCache.length > 12 && this.number.includes(val) && this.firstInputToken !== true) { // this.notifyService.warning(`${this.resultInputCache}越界,该区域至多显示13位数字`); // return; // } switch (val) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': this.numberClick(val); break; case '.': this.dotClick(val); break; case '±': this.pnClick(); break; case '+': case '-': case '×': case '÷': this.operatorClick(val); break; case '=': this.equalClick(); break; case 'CE': this.ceClick(); break; case 'C': this.cClick(); break; case 'Back': this.backClick(); break; } this.setStepInput(this.stepInputCache) this.setResultInput(this.resultInputCache); } }