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

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

  1. 讲解视频

    TS实战项目四:计算器项目创建


    TS实战项目五:Browserify安装配置

  2. B站视频

    TS实战项目四:计算器项目创建


    TS实战项目五:Browserify安装配置

  3. 西瓜视频
    https://www.ixigua.com/7329331349171470899

一.知识点

1. tsify编译
2. tsconfig.json配置项
3. 模块定义及导入导出
4. 类定义
5. 参数属性
6. 存取器
7. 接口定义
8. 命名空间
9. 函数重载
10. 事件处理

二.效果预览

在这里插入图片描述

三.实现思路

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

四.创建项目

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

7. 在package.json中添加编译指令:

"build-cli": "browserify -p tsify ./src/index.ts > ./dist/index.js",
"build-script": "node ./build.js > ./dist/index.js",

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

五.编码实现

1. tsconfig.json

{"compilerOptions": {/* Visit https://aka.ms/tsconfig 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;
}

10. 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';}
}

11. 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';}
}

12. 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_;}
}

13. 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_;}
}

14. 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;}}
}

15. 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;}
}

16. 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_;}
}

17. 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_;}
}

18. 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;}
}

19. 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进行扩展声明,实现相应的功能。
问题二: 直接给元素添加点击事件回调时,接口类型的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/669793.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

当AGI遇到人形机器人

为什么人类对人形机器人抱有执念 人形机器人是一种模仿人类外形和行为的机器人&#xff0c;它的研究和开发有着多方面的目的和意义。 人形机器人可以更好地适应人类的环境和工具。人类的生活和工作空间都是根据人的尺寸和动作来设计的&#xff0c;例如门、楼梯、桌椅、开关等…

【数据分享】1929-2023年全球站点的逐月平均能见度(Shp\Excel\免费获取)

气象数据是在各项研究中都经常使用的数据&#xff0c;气象指标包括气温、风速、降水、能见度等指标&#xff0c;说到气象数据&#xff0c;最详细的气象数据是具体到气象监测站点的数据&#xff01; 之前我们分享过1929-2023年全球气象站点的逐月平均气温数据、逐月最高气温数据…

【征稿已开启】第五大数据、人工智能与软件工程国际研讨会(ICBASE 2024)

第五大数据、人工智能与软件工程国际研讨会&#xff08;ICBASE 2024&#xff09; 2024 5th International Conference on Big Data & Artificial Intelligence & Software Engineering 2024年09月20-22日 | 中国温州 第五届大数据、人工智能与软件工程国际研讨会&…

年假作业4

AACBB DACBDD DACBC DBDCA ADBAD #include <stdio.h> #include <string.h> int main(int argc, const char *argv[]) { int i,j; int temp; int arr[10]; for( i0;i<10;i) { printf("请输入第%d个数",i1); …

【lvgl】esp32移植lvgl

文章目录 一、环境二、抓取代码三、切换分支四、配置芯片信息五、编译异常问题1: 未定义宽高问题2: 修改接口问题3: lv_mem_size问题4&#xff1a;头文件命名打开配置问题5&#xff1a;缺少font12 六、配置引脚问题6&#xff1a;显示花屏&#xff0c;字符不清 七、测试demo八、…

vscode连接ssh报错

关于vscode更新版本至1.86后&#xff0c;导致无法连接服务器问题的记录 原因&#xff1a;vscode1.86更新了对glibc的要求&#xff0c;需要最低2.28版本&#xff0c;导致各种旧版本的linux发行版&#xff08;比如最常见的centos 7&#xff09;都无法用remote-ssh来连接了&#…

Windows11安装运行Linux(Ubuntu)

一、安装windows支持 输入windows打开界面 选择虚拟机监控程序平台、适用于linux的子系统、虚拟机平台 在 Windows 系统中&#xff0c;"虚拟机平台"和"虚拟机监控程序平台"是两个与虚拟化相关的功能&#xff0c;但它们各自有着不同的作用和用途。 虚拟机…

【ArcGIS微课1000例】0101:删除冗余节点或折点

文章目录 一、实验描述二、实验数据三、实验过程1. 手动删除2. 简化线工具四、注意事项一、实验描述 矢量数据获取通常来源于手动或者ArcScan自动采集,其基本存储方式就是记录每个要素的点坐标,如点要素就是一个坐标、线要素由多个点要素连接形成。当某段线要素被过多的节点…

thinkphp数据批量提交(群发消息)

<form id="edit-form" class="form-horizontal" role="form" data-toggle<

LeetCode、1137. 第 N 个泰波那契数【简单,动态规划】

文章目录 前言LeetCode、1137. 第 N 个泰波那契数【简单&#xff0c;动态规划】题目与分类思路一维动态规划 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客之星、阿里云平台优质作者、专注于Java后端技术…

2024/2/5总结

微信小程序 监听对象中所有属性的变化 如果某个对象中需要被监听的属性太多&#xff0c;为了方便&#xff0c;可以使用 通配符 ** 来监听 对象中所有属性的变化 什么是纯数字字段 概念&#xff1a;纯数字字段指的是那些不用于界面渲染的 data 字段。 好处&#xff1a;提升界面…

敏捷开发中的用户故事

用户故事 drawio是一款强大的图表绘制软件&#xff0c;支持在线云端版本以及windows, macOS, linux安装版。 如果想在线直接使用&#xff0c;则直接输入网址drawon.cn或者使用drawon(桌案), drawon.cn内部完整的集成了drawio的所有功能&#xff0c;并实现了云端存储&#xff0c…

transformers重要组件(模型与分词器)

1、模型&#xff1a; from transformers import AutoModelcheckpoint "distilbert-base-uncased-finetuned-sst-2-english" model AutoModel.from_pretrained(checkpoint) 除了像之前使用 AutoModel 根据 checkpoint 自动加载模型以外&#xff0c;我们也可以直接…

如何利用边缘计算网关进行机床数据采集,以提高数据采集的效率和准确性-天拓四方

边缘计算网关集成了数据采集、处理和传输功能的嵌入式设备。它位于传感器和执行器组成的设备层与云计算平台之间&#xff0c;能够实时处理和响应本地设备的数据请求&#xff0c;减轻云平台的压力&#xff0c;提高数据处理的速度和效率。同时&#xff0c;边缘计算网关还可以将处…

跟着cherno手搓游戏引擎【21】shaderLibrary(shader管理类)

前置&#xff1a; ytpch.h&#xff1a; #pragma once #include<iostream> #include<memory> #include<utility> #include<algorithm> #include<functional> #include<string> #include<vector> #include<unordered_map> #in…

ROS笔记一:工作空间和功能包

目录 工作空间 如何创建工作空间&#xff1a; 编译工作空间 设置环境变量 功能包 创建功能包 CMakeLists.txt package.xml 工作空间 ROS的工作空间是用来存放工程文件代码的文件夹 ROS的开发依赖于工作空间&#xff0c;包括编写代码、编译等都是在工作空间下进行的 工作空…

如何在Termux中使用Hexo结合内网穿透工具实现远程访问本地博客站点

文章目录 前言 1.安装 Hexo2.安装cpolar3.远程访问4.固定公网地址 前言 Hexo 是一个用 Nodejs 编写的快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章&#xff0c;在几秒内&#xff0c;即可利用靓丽的主题生成静态网页。 下面介绍在Termux中安装个人hexo博客并结合…

GO语言集成开发 JetBrains GoLand 2023 中文

JetBrains GoLand 2023是一款专为Go语言开发者打造的集成开发环境&#xff08;IDE&#xff09;。它基于IntelliJ IDEA平台&#xff0c;提供了丰富的功能和工具&#xff0c;旨在提高开发效率和质量。GoLand 2023具备强大的Go语言支持&#xff0c;包括语法高亮、自动补全、代码提…

RPA财务机器人之UiPath实战 - 自动化操作Excel进行财务数据汇总与分析之流程建立与数据读取、处理、汇总、分析

一、案例介绍&#xff1a; A公司共有13个开在不同银行的帐户&#xff0c;分别用于不同的业务分部或地区分部收付款。公司总部为了核算每月的收支情况&#xff0c;查看银行在哪个月交易量频繁&#xff0c;需要每月汇总各个银行的帐户借方和贷方金额&#xff0c;并将其净收支&am…

unity 增加系统时间显示、FPS帧率、ms延迟

代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;using UnityEngine;public class Frame : MonoBehaviour {// 记录帧数private int _frame;// 上一次计算帧率的时间private float _lastTime;// 平…