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

news2024/11/16 11:34:27

  使用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.coloradmin.cn/o/1435957.html

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

相关文章

Unity3D判断屏幕中某个坐标点的位置是否在指定UI区域内

系列文章目录 unity工具 文章目录 系列文章目录前言一、使用rect.Contains()判断1-1、转换坐标1-2、代码如下&#xff1a;1-3、注意事项1-3、测试效果如下 二、使用坐标计算在不在区域内2-1、方法如下&#xff1a;2-2、注意事项 三、使用RectTransformUtility.ScreenPointToLo…

[每日一题] 02.06 - ABC

ABC lis list(map(int,input().split())) ABC list(input()) lis.sort() dic {A:lis[0],B:lis[1],C:lis[2]} res print(dic) for i in ABC:print(dic[i],end )我感觉没问题&#xff0c;但提交就是出问题了&#xff0c;应该不是最后多了个空格&#xff08;试过去除还是错…

股票投资指南!石家庄开通股票账户佣金最低是多少?怎么开低佣金账户?

股票投资指南可以帮助您更好地了解股票投资的基本知识和技巧&#xff0c;以便您可以做出明智的投资决策。以下是一些股票投资的基本指南&#xff1a; 了解股票市场&#xff1a;学习股票市场的基本概念和运作方式&#xff0c;包括股票交易所、股票指数和股票价格等。 定义投资目…

技术是你的安身立命之本

技术是你的安身立命之本 技术是你的安身立命之本,这句话是我父亲说的,我也一直把这句话奉为圭臬。这句话让我受用至今。 我父亲是一个两面派人士,一面是农民,一直在耕种着五亩薄田,没有像别的人家一样把田租赁出去,另一面是银行职员,勤勤恳恳在小县城的网点干了一辈子…

【AI】告别繁琐阅读,阿里通义智文阅读助手带您轻松畅游知识海洋!

哈喽&#xff0c;大家好&#xff0c;我是木头左&#xff0c;致力于程序服务生活&#xff01; 一、阿里通义智文阅读助手简介 阿里通义智文阅读助手是一款基于人工智能技术的阅读辅助工具&#xff0c;可以帮助用户更高效地阅读和理解各种类型的文档&#xff0c;如PPT、图片和PD…

【多模态MLLMs+图像编辑】MGIE:苹果开源基于指令和大语言模型的图片编辑神器(24.02.03开源)

项目主页&#xff1a;https://mllm-ie.github.io/ 论文 :基于指令和多模态大语言模型图片编辑 2309.Guiding Instruction-based Image Editing via Multimodal Large Language Models &#xff08;加州大学圣巴拉分校苹果&#xff09; 代码&#xff1a;https://github.com/appl…

LeetCode-第2769题-找出最大的可达成数字

1.题目描述 给你两个整数 num 和 t 。 如果整数 x 可以在执行下述操作不超过 t 次的情况下变为与 num 相等&#xff0c;则称其为 可达成数字 &#xff1a; 每次操作将 x 的值增加或减少 1 &#xff0c;同时可以选择将 num 的值增加或减少 1 。 2.样例描述 3.思路描述 当 x…

第五讲 二维费用的背包问题

【题目来源】AcWing 8. 二维费用的背包问题 【题意分析】 本题在前面背包问题的基础上&#xff0c;增加了一个维度——质量&#xff0c;背包拥有了容积、承重两个限制&#xff0c;物品也有了体积、质量两种属性。 【参考资料】第一讲 0/1背包问题 与0/1背包类似&#xff0c;加…

PDF文件格式(一):交叉引用流

在PDF-1.5版本之前&#xff0c;对象的交叉引用信息是存储在交叉引用表(cross-reference table)中的。在PDF-1.5版本之后&#xff0c;引进了交叉引用流(cross-reference stream)对象&#xff0c;可以用它来存储对象的交叉引用信息&#xff0c;就像交叉引用表的功能一样。 采用交…

C语言第十九弹---指针(三)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 指针 1、数组名的理解 2、使用指针访问数组 3、⼀维数组传参的本质 4、冒泡排序 5、二级指针 6、指针数组 7、指针数组模拟二维数组 总结 1、数组名的理解…

C++学习Day04之常函数和常对象

目录 一、程序及输出1.1 常函数1.1.1 不能修改对象的成员变量1.1.2 常函数可以被常对象和非常对象调用 1.2 常对象1.2.1 对象的成员变量不能被修改1.2.2 只能调用常函数&#xff0c;不能调用非常函数1.2.3 const_cast 调用非常函数 1.3 常函数中或常对象修改成员变量 二、分析与…

070:vue+cesium: 利用canvas设置线性渐变色材质

第070个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置线性渐变色的材质,这里使用canvas的辅助方法。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共104行)专栏目标示例效果 配置方式 1)查看基础…

WPF控件-ItemsControl

介绍 ItemsControl是用于展示一组项的控件。我们常见的列表&#xff08;ListBox&#xff09;、数据表格&#xff08;DataGrid&#xff09;等都是继承自ItemsControl。可用于自定义样式展示各种批量的数据集合。 常见使用示例&#xff1a; <ItemsControl ItemsSource"…

浅谈交换原理(2)——交换单元

目录 一、交换网络的构成 二、交换单元 2.1 基本模型 2.2 分类 2.2.1 按照信息传送方向分类 2.2.2 按入出线的数量分类 2.2.3 按入出线之间是否共享单一通路分类 2.2.3.1 空分交换单元 2.2.3.2 时分交换单元 2.3 连接方式 2.4 性能 三、总结 一、交换网络的构成 交…

Figma怎么设置中文,Figma有中文版吗?

不是很多人不想用 Figma&#xff0c;真是因为纯英文界面而头疼。这就是为什么有人会到处搜索 Figma 如何设置中文这样的问题。 然后我们直接快刀斩乱麻&#xff0c;Figma 没有中文版&#xff0c;但是我们还有其他的方法&#xff1a;例如&#xff0c; Figma 添加一个插件来解决…

155基于matlab 的形态学权重自适应图像去噪

基于matlab 的形态学权重自适应图像去噪&#xff1b;通过串并联的滤波降噪对比图&#xff0c;说明并联降噪的优越性。输出降噪前后图像和不同方法的降噪情况的信噪比。程序已调通&#xff0c;可直接运行。 155matlab 自适应图像降噪 串并联降噪 (xiaohongshu.com)

linux下 Make 和 Makefile构建你的项目

Make 和 Makefile构建你的项目 介绍 在软件开发中&#xff0c;构建项目是一个必不可少的步骤。make 是一个强大的自动化构建工具&#xff0c;而 Makefile 是 make 工具使用的配置文件&#xff0c;用于描述项目的构建规则和依赖关系。本篇博客将介绍 make 和 Makefile 的基本概…

【机器学习】基于集成学习的 Amazon 用户评论质量预测

实验六: 基于集成学习的 Amazon 用户评论质量预测 1 案例简介 ​ 随着电商平台的兴起&#xff0c;以及疫情的持续影响&#xff0c;线上购物在我们的日常生活中扮演着越来越重要的角色。在进行线上商品挑选时&#xff0c;评论往往是我们十分关注的一个方面。然而目前电商网站的…

《MySQL》超详细笔记

目录 基本知识 主流数据库 数据库基本概念 MySQL启动 数据库基本命令 数据库 启动数据库 显示数据库 创建数据库 删除数据库 使用数据库 查询当前数据库信息 显示数据库中的表 导入数据库脚本 表 查看表的结构 查看创建某个表的SQL语句 数据库的查询命令 查询…

阿里地址标准化相关能力

阿里云地址标准化服务入口 1地址标准化概念 阿地址标准化&#xff08;Address Purification&#xff09;是一站式闭环地址数据处理和服务平台产品&#xff0c;依托阿里云海量的地址语料库&#xff0c;针对各行业业务系统所登记的地址数据&#xff0c;进行纠错、补全、归一、结…