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.rhkb.cn/news/255038.html

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

相关文章

零基础学编程从入门到精通,系统化的编程视频教程上线,中文编程开发语言工具构件之缩放控制面板构件用法

一、前言 零基础学编程从入门到精通&#xff0c;系统化的编程视频教程上线&#xff0c;中文编程开发语言工具构件之缩放控制面板构件用法 编程入门视频教程链接 https://edu.csdn.net/course/detail/39036 编程工具及实例源码文件下载可以点击最下方官网卡片——软件下载—…

Win32 SDK Gui编程系列之--ListView自绘OwnerDraw(续)

通过所有者绘制的列表视图(2) 所有者绘制列表视图的基础已在前一页中说明。本页将展示如何在所有者绘制列表视图中显示数据库表数据。 1、访问日志 正如在另一个页面中所述,本网站的访问日志目前是通过SQLite3数据库管理的。 以下是上述程序执行的结果。为…

网神 SecGate 3600 防火墙 route_ispinfo_import_save 文件上传漏洞复现

0x01 产品简介 网神SecGate 3600防火墙是基于状态检测包过滤和应用级代理的复合型硬件防火墙,是专门面向大中型企业、政府、军队、高校等用户开发的新一代专业防火墙设备,支持外部攻击防范、内网安全、网络访问权限控制、网络流量监控和带宽管理、动态路由、网页内容过滤、邮…

数据库管理-第146期 最强Oracle监控EMCC深入使用-03(20240206)

数据库管理145期 2024-02-06 数据库管理-第146期 最强Oracle监控EMCC深入使用-03&#xff08;20240206&#xff09;1 概览2 性能中心3 性能中心-Exadata总结 数据库管理-第146期 最强Oracle监控EMCC深入使用-03&#xff08;20240206&#xff09; 作者&#xff1a;胖头鱼的鱼缸&…

C++初阶篇----新手进村

目录 一、什么是C二、C关键字三、命名空间3.1命名空间的定义3.2命名空间的使用 四、C输入和输出五、缺省参数5.1缺省参数的概念5.2缺省参数的分类 六、函数重载6.1函数重载的概念6.2函数重载的原理----名字修饰 七、引用7.1引用概念7.2引用特性7.3常引用7.4引用的使用7.5传值、…

波奇学Linux:文件重定向和虚拟文件系统

重定向 文件描述符所对应的分配规则&#xff0c;从0开始&#xff0c;寻找最小没有使用的数组位置。 如图所示&#xff0c;关闭文件描述符的0&#xff0c;新打开的文件描述符为0&#xff0c;而关闭2&#xff0c;文件描述符为2。 重定向&#xff1a;文件输出的对象发生改变 例…

肯尼斯·里科《C和指针》第12章 使用结构和指针(1)链表

只恨当时学的时候没有读到这本书&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c;&#xff0c; 12.1 链表 有些读者可能还不熟悉链表&#xff0c;这里对它作一简单介绍。链表(linked list)就一些包含数据的独立数据结构&#xff08;通常称为节点&#xff09;的集…

代码审计-CVE-2023-6654-PHPEMS-加密-解密分析

路由&#xff1a; 入口方法&#xff1a; 鉴权分析&#xff1a; 由此可以得出 鉴权是由session类负责获取参数后&#xff0c;由各个类的魔术方法负责&#xff1a;&#xff08;在此还有一个方法 全局搜索登录关键词&#xff09; 1、断点分析&#xff1a; 寻找鉴权点分析&#…

(十八)springboot实战——spring securtity注解方式的授权流程源码解析

前言 在上一节内容中&#xff0c;我们介绍了如何在FilterSecurityInterceptor过滤器中处理用户的授权流程&#xff0c;并分析了其源码&#xff0c;spring security还提供了方法级别的授权方式&#xff0c;通过EnableMethodSecurity注解启用权限认证流程&#xff0c;只需要在方…

SpringBoot 事务管理Transactional 数据回滚 数据一致性

SpringBoot 事务的属性rollbackFor 与 propagetion 介绍 SpringBoot当中的事物他保证了一致性&#xff0c;要么全部一起成功&#xff08;提交&#xff09;&#xff0c;要么一起失败&#xff0c;失败&#xff08;回滚&#xff09;后数据会回到当初的样子&#xff0c;是一组操…

No matching client found for package name ‘com.unity3d.player‘

2024年2月6日更新 使用Unity插件包方式接入&#xff08;Unity方式&#xff09;&#xff0c;且必须使用EDM(ExternalDependencyManager)&#xff0c;若已有ExternalDependencyManager文件夹&#xff08;其他SDK也可能带有&#xff09;则选用最新的即可。 工程Assets- E…

Qt网络编程-写一个简单的网络调试助手

环境 Windows&#xff1a;Qt5.15.2&#xff08;VS2022&#xff09; Linux&#xff1a;Qt5.12.12&#xff08;gcc) 源代码 TCP服务器 头文件&#xff1a; #ifndef TCPSERVERWIDGET_H #define TCPSERVERWIDGET_H #include <QWidget> namespace Ui { class TCPServerW…

Linux文件和目录管理

目录基础 Linux操作系统以目录的方式来组织和管理系统中的所有文件。所谓的目录&#xff0c;就是将所有文件的说明信息采用树状结构组织起来。每个目录节点之下会有文件和子目录。 所有一切都从 ‘根’ 开始&#xff0c;用 ‘/’ 代表, 并且延伸到子目录。 bin&#xff1a;B…

【RT-DETR有效改进】利用SENetV1重构化网络结构 (ILSVRC冠军得主)

👑欢迎大家订阅本专栏,一起学习RT-DETR👑 一、本文介绍 本文给大家带来的改进机制是SENet(Squeeze-and-Excitation Networks)其是一种通过调整卷积网络中的通道关系来提升性能的网络结构。SENet并不是一个独立的网络模型,而是一个可以和现有的任何一个模型相结合…

R语言学习case10:ggplot基础画图Parallel Coordinate Plot 平行坐标图

step1: 导入ggplot2库文件 library(ggplot2)step2&#xff1a;带入自带的iris数据集 iris <- datasets::irisstep3&#xff1a;查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4&#xff1a;利用ggplot工具包绘图 plot5 <- ggparcoord(…

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

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

单片机学习笔记---蜂鸣器工作原理

目录 蜂鸣器介绍 蜂鸣器的驱动方式 ULN2003D芯片工作原理 实战预备知识&#xff1a;基础乐理 音名的分组 全音和半音的关系 音高的表示 五线谱中的符号定义 简谱上的符号定义 C调音符与频率对照表 相关计算 蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件&a…

SaperaCamExpert(相机专家)中文使用指南

参考&#xff1a;SaperaCamExpert中文使用指南.PDF 文章目录 软件介绍安装首次打开资源占用率功能主界面布局菜单栏FileViewPre-Processing&#xff1a;预处理 Tools&#xff1a; 快捷键&#xff1a;新建&#xff1b;打开&#xff1b;保存&#xff1b;帮助Device窗体属性树图像…

Bytebase 签约 Vianova,助力欧洲城市交通智能平台中 Snowflake 和 PG 的变更自动化及版本控制

在数字化发展的浪潮中&#xff0c;自动化数据库变更管理成为提升产品上线效率、降低人为失误风险的关键工具&#xff0c;同时促进流程的一致性与标准化&#xff0c;确保合规性和变更的可追溯性。近日&#xff0c;数据库 DevOps 团队协同管理工具 Bytebase 签约欧洲交通数据管理…

网站被攻击有什么办法呢?

最近&#xff0c;德迅云安全遇到不少网站用户遇到攻击问题&#xff0c;来咨询安全解决方案。目前在所有的网络攻击方式中&#xff0c;DDoS是最常见&#xff0c;也是最高频的攻击方式之一。不少用户网站上线后&#xff0c;经常会遭受到攻击的困扰。有些攻击持续时间比较短影响较…