龙空技术网

TS项目实战二:网页计算器

军军君06 121

前言:

现在兄弟们对“panelhtml”大概比较着重,同学们都需要剖析一些“panelhtml”的相关知识。那么小编同时在网上搜集了一些对于“panelhtml””的相关内容,希望朋友们能喜欢,朋友们快快来学习一下吧!

使用ts实现网页计算器工具,实现计算器相关功能,使用tsify进行项目编译,引入Browserify实现web界面中直接使用模块加载服务。

源码下载:

一.知识点tsify编译tsconfig.json配置项模块定义及导入导出类定义参数属性存取器接口定义命名空间函数重载事件处理二.效果预览三.实现思路

使用ui和逻辑控制分离的模式,实现ui绘制及计算数据的单独处理,自定义按钮、输入框等ui组件,并绘制到界面中;通过事件监听的方式实现按钮点击后对应的逻辑控制,入结果计算、结果展示等。

四.创建项目

1. 创建node项目,使用npm init命令,如下:

添加图片注释,不超过 140 字(可选)

2. 安装ts库,npm install typescript --save:

添加图片注释,不超过 140 字(可选)

3. .\node_modules\.bin\tsc --init生成ts的项目配置文件,此处注意直接用vscode的powershell运行的时候会保存,请切换到cmd命令窗口执行命令:

添加图片注释,不超过 140 字(可选)

4. 安装lite-server库,npm install lite-server,安装完毕后添加"start": "lite-server"指令,用于提供web服务:

添加图片注释,不超过 140 字(可选)

5. 安装Browserify,npm install tsify,提供浏览器环境中进行模块加载器的相关支持,具体文档参见:,可创建bs-config.js文件进行web服务的配置。

添加图片注释,不超过 140 字(可选)

6. 安装后创建build.js文件,用于进行ts代码的编译处理:

添加图片注释,不超过 140 字(可选)

7. 在package.json中添加编译指令:"build-cli": "browserify -p tsify ./src/index.ts > ./dist/index.js","build-script": "node ./build.js > ./dist/index.js",

添加图片注释,不超过 140 字(可选)

8. 创建dist文件夹,并创建index.html文件,实现web界面:

添加图片注释,不超过 140 字(可选)

9. 创建后项目目录结构如下:

添加图片注释,不超过 140 字(可选)

五.编码实现

1.tsconfig.json

{	"compilerOptions": {		/* Visit  to read more about this file */		/* Projects */		// "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */		// "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */		// "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */		// "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */		// "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */		// "disableReferencedProjectLoad": true,             /* Reduce the number of projects loaded automatically by TypeScript. */		/* Language and Environment */		"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */			// "lib": [],                                        /* Specify a set of bundled library declaration files that describe the target runtime environment. */			// "jsx": "preserve",                                /* Specify what JSX code is generated. */			// "experimentalDecorators": true,                   /* Enable experimental support for legacy experimental decorators. */			// "emitDecoratorMetadata": true,                    /* Emit design-type metadata for decorated declarations in source files. */			// "jsxFactory": "",                                 /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */			// "jsxFragmentFactory": "",                         /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */			// "jsxImportSource": "",                            /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */			// "reactNamespace": "",                             /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */			// "noLib": true,                                    /* Disable including any library files, including the default lib.d.ts. */			// "useDefineForClassFields": true,                  /* Emit ECMAScript-standard-compliant class fields. */			// "moduleDetection": "auto",                        /* Control what method is used to detect module-format JS files. */			/* Modules */			"module": "commonjs", /* Specify what module code is generated. */			"rootDir": "./", /* Specify the root folder within your source files. */			// "moduleResolution": "node10",                     /* Specify how TypeScript looks up a file from a given module specifier. */			// "baseUrl": "./",                                  /* Specify the base directory to resolve non-relative module names. */			// "paths": {},                                      /* Specify a set of entries that re-map imports to additional lookup locations. */			// "rootDirs": [],                                   /* Allow multiple folders to be treated as one when resolving modules. */			// "typeRoots": [],                                  /* Specify multiple folders that act like './node_modules/@types'. */			// "types": [],                                      /* Specify type package names to be included without being referenced in a source file. */			// "allowUmdGlobalAccess": true,                     /* Allow accessing UMD globals from modules. */			// "moduleSuffixes": [],                             /* List of file name suffixes to search when resolving a module. */			// "allowImportingTsExtensions": true,               /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */			// "resolvePackageJsonExports": true,                /* Use the package.json 'exports' field when resolving package imports. */			// "resolvePackageJsonImports": true,                /* Use the package.json 'imports' field when resolving imports. */			// "customConditions": [],                           /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */			// "resolveJsonModule": true,                        /* Enable importing .json files. */			// "allowArbitraryExtensions": true,                 /* Enable importing files with any extension, provided a declaration file is present. */			// "noResolve": true,                                /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */			/* JavaScript Support */			// "allowJs": true,                                  /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */			// "checkJs": true,                                  /* Enable error reporting in type-checked JavaScript files. */			// "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */			/* Emit */			// "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */			// "declarationMap": true,                           /* Create sourcemaps for d.ts files. */			// "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */			"sourceMap": true, /* Create source map files for emitted JavaScript files. */			// "inlineSourceMap": true,                          /* Include sourcemap files inside the emitted JavaScript. */			// "outFile": "./",                                  /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */			"outDir": "./dist", /* Specify an output folder for all emitted files. */			// "removeComments": true,                           /* Disable emitting comments. */			// "noEmit": true,                                   /* Disable emitting files from a compilation. */			// "importHelpers": true,                            /* Allow importing helper functions from tslib once per project, instead of including them per-file. */			// "importsNotUsedAsValues": "remove",               /* Specify emit/checking behavior for imports that are only used for types. */			// "downlevelIteration": true,                       /* Emit more compliant, but verbose and less performant JavaScript for iteration. */			// "sourceRoot": "",                                 /* Specify the root path for debuggers to find the reference source code. */			// "mapRoot": "",                                    /* Specify the location where debugger should locate map files instead of generated locations. */			// "inlineSources": true,                            /* Include source code in the sourcemaps inside the emitted JavaScript. */			// "emitBOM": true,                                  /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */			// "newLine": "crlf",                                /* Set the newline character for emitting files. */			// "stripInternal": true,                            /* Disable emitting declarations that have '@internal' in their JSDoc comments. */			// "noEmitHelpers": true,                            /* Disable generating custom helper functions like '__extends' in compiled output. */			// "noEmitOnError": true,                            /* Disable emitting files if any type checking errors are reported. */			// "preserveConstEnums": true,                       /* Disable erasing 'const enum' declarations in generated code. */			// "declarationDir": "./",                           /* Specify the output directory for generated declaration files. */			// "preserveValueImports": true,                     /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */			/* Interop Constraints */			// "isolatedModules": true,                          /* Ensure that each file can be safely transpiled without relying on other imports. */			// "verbatimModuleSyntax": true,                     /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */			// "allowSyntheticDefaultImports": true,             /* Allow 'import x from y' when a module doesn't have a default export. */			"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */			// "preserveSymlinks": true,                         /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */			"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */			/* Type Checking */			"strict": true, /* Enable all strict type-checking options. */			// "noImplicitAny": true,                            /* Enable error reporting for expressions and declarations with an implied 'any' type. */			// "strictNullChecks": true,                         /* When type checking, take into account 'null' and 'undefined'. */			// "strictFunctionTypes": true,                      /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */			// "strictBindCallApply": true,                      /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */			// "strictPropertyInitialization": true,             /* Check for class properties that are declared but not set in the constructor. */			// "noImplicitThis": true,                           /* Enable error reporting when 'this' is given the type 'any'. */			// "useUnknownInCatchVariables": true,               /* Default catch clause variables as 'unknown' instead of 'any'. */			// "alwaysStrict": true,                             /* Ensure 'use strict' is always emitted. */			// "noUnusedLocals": true,                           /* Enable error reporting when local variables aren't read. */			// "noUnusedParameters": true,                       /* Raise an error when a function parameter isn't read. */			// "exactOptionalPropertyTypes": true,               /* Interpret optional property types as written, rather than adding 'undefined'. */			// "noImplicitReturns": true,                        /* Enable error reporting for codepaths that do not explicitly return in a function. */			// "noFallthroughCasesInSwitch": true,               /* Enable error reporting for fallthrough cases in switch statements. */			// "noUncheckedIndexedAccess": true,                 /* Add 'undefined' to a type when accessed using an index. */			// "noImplicitOverride": true,                       /* Ensure overriding members in derived classes are marked with an override modifier. */			// "noPropertyAccessFromIndexSignature": true,       /* Enforces using indexed accessors for keys declared using an indexed type. */			// "allowUnusedLabels": true,                        /* Disable error reporting for unused labels. */			// "allowUnreachableCode": true,                     /* Disable error reporting for unreachable code. */			/* Completeness */			// "skipDefaultLibCheck": true,                      /* Skip type checking .d.ts files that are included with TypeScript. */			"skipLibCheck": true /* Skip type checking all .d.ts files. */	}}

2.package.json

{	"name": "demo2",	"version": "1.0.0",	"description": "",	"main": "./src/index.ts",	"scripts": {		"build-cli": "browserify -p tsify ./src/index.ts > ./dist/index.js",		"build-script": "node ./build.js > ./dist/index.js",		"start": "lite-server"	},	"author": "",	"license": "ISC",	"dependencies": {		"browserify": "^17.0.0",		"lite-server": "^2.6.1",		"tsify": "^5.0.4",		"typescript": "^5.3.3"	}}

3.build.js

var browserify = require('browserify');var tsify = require('tsify');browserify()	.add('./src/index.ts')	.plugin(tsify, { noImplicitAny: true })	.bundle()	.on('error', function (error) { console.error(error.toString()); })	.pipe(process.stdout);

4.bs-config.js

"use strict";module.exports = {	port: 8080,	files: ['./dist/**/*.{html,css,js}'],	server: {		baseDir: './dist'	}}

5.index.html

<!DOCTYPE html><html lang="en">	<head>		<meta charset="UTF-8">		<link rel="icon" href="/favicon.ico">		<meta name="viewport" content="width=device-width, initial-scale=1.0">		<title>计算器演示</title>		<style>			html,			body {			width: 100%;			height: 100%;			margin: 0px;			padding: 0px;			}			#app {			display: flex;			justify-content: center;			justify-items: center;			align-items: center;			height: 100vh;			}			#app .panel {			margin: 0 auto;			width: 300px;			height: 410px;			border: 1px solid #f8f8f8;			background-color: #f5f5f5;			box-shadow: 0 0 4px 4px #d7d7d7b5;			border-radius: 5px;			}			#app .panel .result {			font-size: 30px;			font-weight: bold;			text-align: right;			height: 60px;			line-height: 60px;			padding: 10px;			padding-bottom: 0px;			user-select: none;			}			#app .panel .buttons .line {			display: flex;			height: 55px;			line-height: 55px;			width: 100%;			}			#app .panel .buttons .line .btnPanel {			padding: 5px;			flex: 1;			}			#app .panel .buttons .line .btnPanel button {			width: 100%;			height: 100%;			border-radius: 5px;			border: 1px solid #eee;			cursor: pointer;			background-color: #fff;			user-select: none;			font-size: 18px;			}			#app .panel .buttons .line .btnPanel button:hover {			background-color: #00adff;			color: #fff;			}			#app .panel .buttons .line .btnPanel button.eq {			background-color: #00adff;			color: #fff;			border: 1px solid #00adff;			border-radius: 5px;			}		</style>	</head>	<body>		<div id="app"></div>		<script src="./index.js"></script>		<script>		</script>	</body></html>

6.src/index.ts

import ProcessFactory from './ProcessFactory';import UI from './ui/UI';const ui = new UI();//初始化ui.init(document.getElementById('app'), ProcessFactory);

7.src/ProcessFactory.ts

import BackProcess from './proecess/BackProcess';import BaseProcess from './proecess/BaseProcess';import CProcess from './proecess/CProcess';import EqProcess from './proecess/EqProcess';import FenProcess from './proecess/FenProcess';import NumberProcess from './proecess/NumerProcess';import OpratorProcess from './proecess/OpratorProcess';import PercentProcess from './proecess/PercentProcess';import PinFangProcess from './proecess/PinFangProcess';import PointProcess from './proecess/PointProcess';import SqtProcess from './proecess/SqtProcess';/** * 处理器的工厂函数,根据不同的字符,生成不同的处理器 */export default function getProcess(char: string): BaseProcess | null {    if (char == '0' || char == '1' || char == '2' || char == '3' || char == '4' || char == '5' || char == '6' || char == '7' || char == '8' || char == '9') {        return new NumberProcess(char);    }    if (char == '.') {        return new PointProcess(char);    }    if (char == '=') {        return new EqProcess(char);    }    if (char == '+' || char == '-' || char == '*' || char == '/') {        return new OpratorProcess(char);    }    if (char == 'C') {        return new CProcess(char);    }    if (char == '←') {        return new BackProcess(char);    }    if (char == '%') {        return new PercentProcess(char);    }    if (char == '1/x') {        return new FenProcess(char);    }    if (char == 'x^2') {        return new PinFangProcess(char);    }    if (char == '根号') {        return new SqtProcess(char);    }    return null;}

8.src/ui/UI.ts

/** * 根容器 */const rootPanel: HTMLDivElement = document.createElement('div');//展示结果const resultPanel: HTMLDivElement = document.createElement('div');//按钮容器const buttonPanel: HTMLDivElement = document.createElement('div');//按钮const btns: string[][] = [    ['%', 'CE', 'C', '←'],    ['1/x', 'x^2', '根号', '/'],    ['7', '8', '9', '*'],    ['4', '5', '6', '-'],    ['1', '2', '3', '+'],    ['0', '.', '=']];//计算结果let result = "0";/** * UI工具 */export default class UI {    /**     * 初始化界面     * @param root      */    init(root: HTMLElement | null, getProcess: Function): HTMLDivElement {        if (!root) {            throw new Error('必须要指定根元素');        }        //设置类,控制样式        rootPanel.className = 'panel';        resultPanel.className = 'result';        resultPanel.innerText = result;        rootPanel.appendChild(resultPanel);        buttonPanel.className = "buttons";        btns.forEach(item => {            let linePanel: HTMLDivElement = document.createElement('div');            linePanel.className = 'line';            item.forEach(text => {                let buttonPanel: HTMLDivElement = document.createElement('div');                buttonPanel.className = 'btnPanel';                let button: HTMLButtonElement = document.createElement('button');                button.innerText = text + "";                if (text === '=') {                    button.className = 'eq';                }                //附加按钮的标识,记录具体是什么内容                button.setAttribute('content', text);                let process = getProcess(text);                if (process) {                    button.onclick = () => {                        result = process.process(result);                        updateReslt();                    };                }                buttonPanel.appendChild(button);                linePanel.appendChild(buttonPanel);            })            buttonPanel.appendChild(linePanel);        })        rootPanel.appendChild(buttonPanel);        //生成具体的元素        root.appendChild(rootPanel);        return rootPanel;    }}/** * 更新计算结果 */function updateReslt() {    resultPanel.innerText = result;}

9.src/process/BaseProcess.ts

/** * 处理器 */export default interface BaseProcess {    /**     * 要处理的字符串     */    char: string;    /**     * 按钮点击后计算结构     * @param value  按钮的值     * @param result 计算原始的结果     */    process(result: string): string;}
src/process/BackProcess.ts
import BaseProcess from './BaseProcess';/** * 删除按钮的处理 */export default class BackProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     *删除的处理     * @param result      * @returns      */    process(result: string): string {        if (result.length > 0) {            let result_ = result?.substring(0, result.length - 1);            return result_ ? result_ : '0';        }        return '0';    }}

10.src/process/EqProcess.ts

import BaseProcess from './BaseProcess';/** * 等于号的处理 */export default class EqProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     *清空的处理     * @param result      * @returns      */    process(result?: string): string {        return '0';    }}

11.src/process/EqProcess.ts

import BaseProcess from './BaseProcess';/** * 等于号的处理 */export default class EqProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 等于号的处理     * @param value 空值     * @param result      * @returns      */    process(result: string): string {        /**         * 计算结果:1+2-3/4*5         */        while (result.indexOf('+') != -1 || result.indexOf('-') != -1 || result.indexOf('/') != -1 || result.indexOf('*') != -1) {            //先计算乘除            let chenIndex = result.indexOf('*');            let chuIndex = result.indexOf('/');            while (chenIndex >= 0 || chuIndex >= 0) {                if (chenIndex >= 0 && chuIndex >= 0) {//有乘的计算、也有除的计算                    if (chenIndex < chuIndex) {//乘在前                        result = this.jisuan('*', result, chenIndex);                    } else {                        result = this.jisuan('/', result, chuIndex);                    }                } else {                    if (chenIndex >= 0) {                        result = this.jisuan('*', result, chenIndex);                    } else if (chuIndex >= 0) {                        result = this.jisuan('/', result, chuIndex);                    }                }                chenIndex = result.indexOf('*');                chuIndex = result.indexOf('/');            }            let jiaIndex = result.indexOf('+');            let jianIndex = result.indexOf('-');            if (jiaIndex >= 0 && jianIndex >= 0) {//计算加减                if (jiaIndex < jianIndex) {                    result = this.jisuan('+', result, jiaIndex);                } else {                    result = this.jisuan('-', result, jianIndex);                }            } else {                if (jiaIndex >= 0) {                    result = this.jisuan('+', result, jiaIndex);                } else if (jianIndex >= 0) {                    result = this.jisuan('-', result, jianIndex);                }            }        }        return result;    }    jisuan(op: string, result: string, index: number): string {        let preStr = '';        let startIndex = 0;        for (let i = index - 1; i >= 0 && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i--) {            preStr += result[i];            startIndex = i;        }        //反转        preStr = preStr.split('').reverse().join('');        let nexStr = '';        let endIndex = 0;        for (let i = index + 1; i < result.length && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i++) {            nexStr += result[i];            endIndex = i;        }        let preNum = parseFloat(preStr);        let nextNum = parseFloat(nexStr);        let result_ = '';        for (let i = 0; i < result.length; i++) {            if (i >= startIndex && i <= endIndex) {                if (i == startIndex) {                    if (op == '*') {                        result_ += (preNum * nextNum) + '';                    } else if (op == '/') {                        result_ += (preNum / nextNum) + '';                    } else if (op == '+') {                        result_ += (preNum + nextNum) + '';                    } else {                        result_ += (preNum - nextNum) + '';                    }                }                continue;            }            result_ += result.charAt(i);        }        return result_;    }}

12.src/process/FenProcess.ts

import BaseProcess from './BaseProcess';/** * 几分之几的处理 */export default class FenProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 几分之几的处理     * @param value 空值     * @param result      * @returns      */    process(result: string): string {        /**         * 计算结果:1+2-3/4*5         */        while (result.indexOf('+') != -1 || result.indexOf('-') != -1 || result.indexOf('/') != -1 || result.indexOf('*') != -1) {            //先计算乘除            let chenIndex = result.indexOf('*');            let chuIndex = result.indexOf('/');            while (chenIndex >= 0 || chuIndex >= 0) {                if (chenIndex >= 0 && chuIndex >= 0) {//有乘的计算、也有除的计算                    if (chenIndex < chuIndex) {//乘在前                        result = this.jisuan('*', result, chenIndex);                    } else {                        result = this.jisuan('/', result, chuIndex);                    }                } else {                    if (chenIndex >= 0) {                        result = this.jisuan('*', result, chenIndex);                    } else if (chuIndex >= 0) {                        result = this.jisuan('/', result, chuIndex);                    }                }                chenIndex = result.indexOf('*');                chuIndex = result.indexOf('/');            }            let jiaIndex = result.indexOf('+');            let jianIndex = result.indexOf('-');            if (jiaIndex >= 0 && jianIndex >= 0) {//计算加减                if (jiaIndex < jianIndex) {                    result = this.jisuan('+', result, jiaIndex);                } else {                    result = this.jisuan('-', result, jianIndex);                }            } else {                if (jiaIndex >= 0) {                    result = this.jisuan('+', result, jiaIndex);                } else if (jianIndex >= 0) {                    result = this.jisuan('-', result, jianIndex);                }            }        }        return (1 / parseFloat(result)) + '';    }    jisuan(op: string, result: string, index: number): string {        let preStr = '';        let startIndex = 0;        for (let i = index - 1; i >= 0 && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i--) {            preStr += result[i];            startIndex = i;        }        //反转        preStr = preStr.split('').reverse().join('');        let nexStr = '';        let endIndex = 0;        for (let i = index + 1; i < result.length && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i++) {            nexStr += result[i];            endIndex = i;        }        let preNum = parseFloat(preStr);        let nextNum = parseFloat(nexStr);        let result_ = '';        for (let i = 0; i < result.length; i++) {            if (i >= startIndex && i <= endIndex) {                if (i == startIndex) {                    if (op == '*') {                        result_ += (preNum * nextNum) + '';                    } else if (op == '/') {                        result_ += (preNum / nextNum) + '';                    } else if (op == '+') {                        result_ += (preNum + nextNum) + '';                    } else {                        result_ += (preNum - nextNum) + '';                    }                }                continue;            }            result_ += result.charAt(i);        }        return result_;    }}

13.src/process/NumerProcess.ts

import BaseProcess from './BaseProcess';/** * 计算数字型的按钮 */export default class NumberProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 计算结果,传入的是数字按钮     * @param value 数字     * @param result 现有的结果     * @returns 合并后的值     */    process(result: string): string {        if (this.char == '0') {            if (parseFloat(result) == 0) {                return '0';            }        }        if (parseFloat(result) == 0 && result.indexOf('.') == -1) {            return this.char;        } else {            return result + '' + this.char;        }    }}

14.src/process/OpratorProcess.ts

import BaseProcess from './BaseProcess';/** * 实现操作符的处理 */export default class OpratorProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 操作符的处理,+,-,*,/     * @param result      * @returns 合并后的结果     */    process(result: string): string {        if (result.charAt(result.length - 1) == '+' || result.charAt(result.length - 1) == '-' || result.charAt(result.length - 1) == '*' || result.charAt(result.length - 1) == '/') {            return result;        }        return '' + result + this.char;    }}

15.src/process/PercentProcess.ts

import BaseProcess from './BaseProcess';/** * 百分号的处理 */export default class PercentProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 百分号的处理     * @param value 空值     * @param result      * @returns      */    process(result: string): string {        /**         * 计算结果:1+2-3/4*5         */        while (result.indexOf('+') != -1 || result.indexOf('-') != -1 || result.indexOf('/') != -1 || result.indexOf('*') != -1) {            //先计算乘除            let chenIndex = result.indexOf('*');            let chuIndex = result.indexOf('/');            while (chenIndex >= 0 || chuIndex >= 0) {                if (chenIndex >= 0 && chuIndex >= 0) {//有乘的计算、也有除的计算                    if (chenIndex < chuIndex) {//乘在前                        result = this.jisuan('*', result, chenIndex);                    } else {                        result = this.jisuan('/', result, chuIndex);                    }                } else {                    if (chenIndex >= 0) {                        result = this.jisuan('*', result, chenIndex);                    } else if (chuIndex >= 0) {                        result = this.jisuan('/', result, chuIndex);                    }                }                chenIndex = result.indexOf('*');                chuIndex = result.indexOf('/');            }            let jiaIndex = result.indexOf('+');            let jianIndex = result.indexOf('-');            if (jiaIndex >= 0 && jianIndex >= 0) {//计算加减                if (jiaIndex < jianIndex) {                    result = this.jisuan('+', result, jiaIndex);                } else {                    result = this.jisuan('-', result, jianIndex);                }            } else {                if (jiaIndex >= 0) {                    result = this.jisuan('+', result, jiaIndex);                } else if (jianIndex >= 0) {                    result = this.jisuan('-', result, jianIndex);                }            }        }        return (parseFloat(result) / 100) + '';    }    jisuan(op: string, result: string, index: number): string {        let preStr = '';        let startIndex = 0;        for (let i = index - 1; i >= 0 && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i--) {            preStr += result[i];            startIndex = i;        }        //反转        preStr = preStr.split('').reverse().join('');        let nexStr = '';        let endIndex = 0;        for (let i = index + 1; i < result.length && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i++) {            nexStr += result[i];            endIndex = i;        }        let preNum = parseFloat(preStr);        let nextNum = parseFloat(nexStr);        let result_ = '';        for (let i = 0; i < result.length; i++) {            if (i >= startIndex && i <= endIndex) {                if (i == startIndex) {                    if (op == '*') {                        result_ += (preNum * nextNum) + '';                    } else if (op == '/') {                        result_ += (preNum / nextNum) + '';                    } else if (op == '+') {                        result_ += (preNum + nextNum) + '';                    } else {                        result_ += (preNum - nextNum) + '';                    }                }                continue;            }            result_ += result.charAt(i);        }        return result_;    }}

16.src/process/PinFangProcess.ts

import BaseProcess from './BaseProcess';/** * 几分之几的处理 */export default class PinFangProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 几分之几的处理     * @param value 空值     * @param result      * @returns      */    process(result: string): string {        /**         * 计算结果:1+2-3/4*5         */        while (result.indexOf('+') != -1 || result.indexOf('-') != -1 || result.indexOf('/') != -1 || result.indexOf('*') != -1) {            //先计算乘除            let chenIndex = result.indexOf('*');            let chuIndex = result.indexOf('/');            while (chenIndex >= 0 || chuIndex >= 0) {                if (chenIndex >= 0 && chuIndex >= 0) {//有乘的计算、也有除的计算                    if (chenIndex < chuIndex) {//乘在前                        result = this.jisuan('*', result, chenIndex);                    } else {                        result = this.jisuan('/', result, chuIndex);                    }                } else {                    if (chenIndex >= 0) {                        result = this.jisuan('*', result, chenIndex);                    } else if (chuIndex >= 0) {                        result = this.jisuan('/', result, chuIndex);                    }                }                chenIndex = result.indexOf('*');                chuIndex = result.indexOf('/');            }            let jiaIndex = result.indexOf('+');            let jianIndex = result.indexOf('-');            if (jiaIndex >= 0 && jianIndex >= 0) {//计算加减                if (jiaIndex < jianIndex) {                    result = this.jisuan('+', result, jiaIndex);                } else {                    result = this.jisuan('-', result, jianIndex);                }            } else {                if (jiaIndex >= 0) {                    result = this.jisuan('+', result, jiaIndex);                } else if (jianIndex >= 0) {                    result = this.jisuan('-', result, jianIndex);                }            }        }        return (parseFloat(result) * parseFloat(result)) + '';    }    jisuan(op: string, result: string, index: number): string {        let preStr = '';        let startIndex = 0;        for (let i = index - 1; i >= 0 && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i--) {            preStr += result[i];            startIndex = i;        }        //反转        preStr = preStr.split('').reverse().join('');        let nexStr = '';        let endIndex = 0;        for (let i = index + 1; i < result.length && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i++) {            nexStr += result[i];            endIndex = i;        }        let preNum = parseFloat(preStr);        let nextNum = parseFloat(nexStr);        let result_ = '';        for (let i = 0; i < result.length; i++) {            if (i >= startIndex && i <= endIndex) {                if (i == startIndex) {                    if (op == '*') {                        result_ += (preNum * nextNum) + '';                    } else if (op == '/') {                        result_ += (preNum / nextNum) + '';                    } else if (op == '+') {                        result_ += (preNum + nextNum) + '';                    } else {                        result_ += (preNum - nextNum) + '';                    }                }                continue;            }            result_ += result.charAt(i);        }        return result_;    }}

17.src/process/PointProcess.ts

import BaseProcess from './BaseProcess';/** * 实现操作符的处理 */export default class OpratorProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * .的处理     * @param result      * @returns 合并后的结果     */    process(result: string): string {        if (result.charAt(result.length - 1) == '.') {            return result;        }        if (result.charAt(result.length - 1) == '+' || result.charAt(result.length - 1) == '-' || result.charAt(result.length - 1) == '*' || result.charAt(result.length - 1) == '/') {            return result + '0.';        }        return result + '' + this.char;    }}

18.src/process/SqtProcess.ts

import BaseProcess from './BaseProcess';/** * 几分之几的处理 */export default class SqtProcess implements BaseProcess {    char: string;    constructor(char_: string) {        this.char = char_;    }    /**     * 几分之几的处理     * @param value 空值     * @param result      * @returns      */    process(result: string): string {        /**         * 计算结果:1+2-3/4*5         */        while (result.indexOf('+') != -1 || result.indexOf('-') != -1 || result.indexOf('/') != -1 || result.indexOf('*') != -1) {            //先计算乘除            let chenIndex = result.indexOf('*');            let chuIndex = result.indexOf('/');            while (chenIndex >= 0 || chuIndex >= 0) {                if (chenIndex >= 0 && chuIndex >= 0) {//有乘的计算、也有除的计算                    if (chenIndex < chuIndex) {//乘在前                        result = this.jisuan('*', result, chenIndex);                    } else {                        result = this.jisuan('/', result, chuIndex);                    }                } else {                    if (chenIndex >= 0) {                        result = this.jisuan('*', result, chenIndex);                    } else if (chuIndex >= 0) {                        result = this.jisuan('/', result, chuIndex);                    }                }                chenIndex = result.indexOf('*');                chuIndex = result.indexOf('/');            }            let jiaIndex = result.indexOf('+');            let jianIndex = result.indexOf('-');            if (jiaIndex >= 0 && jianIndex >= 0) {//计算加减                if (jiaIndex < jianIndex) {                    result = this.jisuan('+', result, jiaIndex);                } else {                    result = this.jisuan('-', result, jianIndex);                }            } else {                if (jiaIndex >= 0) {                    result = this.jisuan('+', result, jiaIndex);                } else if (jianIndex >= 0) {                    result = this.jisuan('-', result, jianIndex);                }            }        }        return Math.sqrt(parseFloat(result)) + '';    }    jisuan(op: string, result: string, index: number): string {        let preStr = '';        let startIndex = 0;        for (let i = index - 1; i >= 0 && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i--) {            preStr += result[i];            startIndex = i;        }        //反转        preStr = preStr.split('').reverse().join('');        let nexStr = '';        let endIndex = 0;        for (let i = index + 1; i < result.length && (result.charAt(i) !== '*' && result.charAt(i) !== '/' && result.charAt(i) !== '+' && result.charAt(i) !== '-'); i++) {            nexStr += result[i];            endIndex = i;        }        let preNum = parseFloat(preStr);        let nextNum = parseFloat(nexStr);        let result_ = '';        for (let i = 0; i < result.length; i++) {            if (i >= startIndex && i <= endIndex) {                if (i == startIndex) {                    if (op == '*') {                        result_ += (preNum * nextNum) + '';                    } else if (op == '/') {                        result_ += (preNum / nextNum) + '';                    } else if (op == '+') {                        result_ += (preNum + nextNum) + '';                    } else {                        result_ += (preNum - nextNum) + '';                    }                }                continue;            }            result_ += result.charAt(i);        }        return result_;    }}
六.遇到的问题

问题一:HTMLDivElement无法继承的问题。因为ts中HTMLDivElement是一个接口,没有声明类,因为是一个底层类型,不适合进行扩展。可以新建类实现一个此接口,但就需要实现所有的属性和接口的方法,不太显示;可以新建一个类,定义一个HTMLDivElement类型的数据,将需要封装的内容封装到新建的类中实现想要的效果;也可使用声明合并对HTMLDivElement进行扩展声明,实现相应的功能。

问题二:直接给元素添加点击事件回调时,接口类型的问题。

标签: #panelhtml #net实现一个计算器