当前位置: 首页 > news >正文

React单位转换系统:设计灵活的单位系统与单位系统转换方案

一个完整的React单位系统方案。这个方案将支持单位定义、转换、系统分组等功能。支持多种单位(如长度、压强、温度)和多个单位系统(如系统1和系统2)。该系统允许用户在不同单位之间进行转换,并能够按系统过滤单位。

常用的单位

物理量类别物理量名称国际单位制 (SI)工程常用单位 (MMKS)备注/换算关系
📏 几何尺寸长度米 (m)毫米 (mm)1 m = 1000 mm
⚖️ 质量与力质量千克 (kg)吨 (t) 或 克 (g)1 t = 1000 kg, 1 kg = 1000 g
牛顿 (N)千牛 (kN)1 kN = 1000 N
压力/应力帕斯卡 (Pa)兆帕 (MPa)1 MPa = 10⁶ Pa = 1 N/mm²
⏱️ 时间时间秒 (s)秒 (s)压射过程常用毫秒 (ms), 1 s = 1000 ms
🌡️ 温度温度开尔文 (K)摄氏度 (°C)数值关系: °C = K - 273.15
🔥 能量与功率」能量焦耳 (J)千焦 (kJ)1 kJ = 1000 J
功率瓦特 (W)千瓦 (kW)1 kW = 1000 W
🧪 材料属性」密度kg/m³g/cm³ 或 t/mm³1 g/cm³ = 1000 kg/m³ (注意量纲转换)
动力粘度Pa·smPa·s1 Pa·s = 1000 mPa·s
热导率W/(m·K)W/(m·K) 常用
比热容J/(kg·K)kJ/(kg·K)1 kJ/(kg·K) = 1000 J/(kg·K)
热膨胀系数1/K1/°C数值相同,注意温度基准

单位系统设计

我们设计一个单位系统,需要考虑以下几个方面:

  1. 单位定义:每个单位需要有一个唯一的编码(id),名称,类型(长度、压强等),以及转换系数(相对于基准单位)。

  2. 单位系统:可以定义多个单位系统,每个系统包含一组单位(例如单位系统1包含mm和Pa,单位系统2包含m和MPa)。

  3. 单位转换:能够将同一个物理量的值从一个单位转换到另一个单位。

设计思路

  • 定义单位类型(维度),如长度、压强等。

  • 每个单位类型有一个基准单位(如长度的基准单位是米m,压强的基准单位是帕斯卡Pa),其他单位相对于基准单位有转换系数。

  • 单位系统是单位的集合,每个单位系统包含多个单位(每个维度一个单位?或者可以多个?但通常一个单位系统内每个维度使用一个单位,比如国际单位制中长度用米m,压强用帕斯卡Pa;而工程单位制可能长度用毫米mm,压强用兆帕Pa)。但这里需求是单位系统1包含mm和Pa,单位系统2包含m和MPa,所以一个单位系统包含多个维度的单位。

实现步骤:

  1. 定义单位维度(类型)枚举。

  2. 定义单位类,包含:id, 名称,维度,转换系数(转换为基准单位所需的乘数)。

  3. 定义单位系统类,包含:id, 名称,单位集合(每个维度一个单位,但也可以多个?这里我们设计为每个维度一个单位,因为同一个维度在一个单位系统中通常只用一个单位)。

  4. 提供单位转换函数,它可以根据给定的值、原单位、目标单位进行转换。也可以根据单位系统进行批量转换。

但是,注意:单位转换可能涉及不同维度之间的转换吗?不,我们只转换同一维度的单位。

另外,我们还需要一个单位管理器来管理所有的单位和单位系统。

考虑到单位转换可能涉及复杂的公式(比如温度转换不仅乘系数还要加常数),我们可以设计一个转换函数,对于线性转换(乘系数)可以简单处理,对于非线性转换需要特殊处理。但这里我们假设都是线性转换。

设计:

单位维度(Dimension)

  • 长度(Length)

  • 压强(Pressure)

单位(Unit):

  • id: string

  • name: string

  • dimension: Dimension

  • toBase: (value: number) => number // 将当前单位的值转换为基准单位的值

  • fromBase: (value: number) => number // 将基准单位的值转换为当前单位的值

但是,对于线性单位,我们可以用一个转换系数(factor)来表示。假设基准单位是u0,当前单位u1,则有:

baseValue = value * factor
value = baseValue / factor

因此,我们可以这样定义单位:

toBase: (value) => value * factor
fromBase: (value) => value / factor

但是,对于非线性单位(如温度),我们需要自定义函数。为了通用,我们使用两个函数。

然而,为了简单,我们先考虑线性单位。我们可以创建一个线性单位类,而非线性单位则特殊处理。

我们设计一个接口Unit:

interface Unit {
id: string;
name: string;
dimension: string; // 维度id
toBase: (value: number) => number;
fromBase: (value: number) => number;
}

然后,我们可以创建一个创建线性单位的工厂函数。

单位系统(UnitSystem)

interface UnitSystem {
id: string;
name: string;
units: Map<string, Unit>; // key为维度id,value为该维度下在此单位系统中使用的单位
}

单位管理器(UnitManager):

  • 管理所有单位

  • 管理所有单位系统

  • 提供单位转换方法

也可以根据单位id进行转换。

另外,我们还需要在单位系统中提供转换方法,比如在单位系统1中,我们使用mm和Pa,如果我们要将单位系统1中的长度转换为单位系统2中的长度(即从mm到m),我们可以通过单位管理器找到对应的单位进行转换。

但是,我们也可以设计一个在单位系统之间转换的函数,例如,给定一个值、原单位系统、目标单位系统,以及值的维度,进行转换。

步骤:

  1. 根据维度,在原单位系统中找到对应的单位。

  2. 在目标单位系统中找到对应维度的单位。

  3. 使用convert函数进行转换。

我们来实现这个系统。

注意:我们假设每个单位系统对每个维度都有一个单位。如果某个维度在单位系统中没有定义,则转换时可能会出错。

代码结构:

  • 定义维度(Dimensions)枚举或常量。

  • 定义Unit接口和线性单位创建函数。

  • 定义UnitSystem接口和类。

  • 定义UnitManager类,用于注册单位、单位系统,以及进行转换。

代码实现

1. 核心类型定义

// types/unit.ts
export interface Unit {code: string;        // 单位编码,如 'mm', 'MPa'name: string;        // 单位名称,如 '毫米', '兆帕'dimension: string;   // 物理量维度,如 'length', 'pressure'system: string;      // 所属系统编码,如 'system1', 'system2'factor: number;      // 相对于基准单位的转换系数offset?: number;     // 偏移量(用于温度等非线性转换)
}export interface UnitSystem {code: string;        // 系统编码name: string;        // 系统名称description?: string; // 系统描述
}export interface QuantityValue {value: number;unit: string;        // 单位编码
}export interface ConversionResult extends QuantityValue {originalValue: number;originalUnit: string;
}

2. 单位管理器

// services/UnitManager.ts
class UnitManager {private units: Map<string, Unit> = new Map();private systems: Map<string, UnitSystem> = new Map();private dimensionUnits: Map<string, Unit[]> = new Map();// 注册单位系统registerSystem(system: UnitSystem): void {this.systems.set(system.code, system);}// 注册单位registerUnit(unit: Unit): void {this.units.set(unit.code, unit);// 按维度分组if (!this.dimensionUnits.has(unit.dimension)) {this.dimensionUnits.set(unit.dimension, []);}this.dimensionUnits.get(unit.dimension)!.push(unit);}// 批量注册单位registerUnits(units: Unit[]): void {units.forEach(unit => this.registerUnit(unit));}// 获取单位getUnit(unitCode: string): Unit | undefined {return this.units.get(unitCode);}// 获取同一维度的所有单位getUnitsByDimension(dimension: string): Unit[] {return this.dimensionUnits.get(dimension) || [];}// 获取同一系统的所有单位getUnitsBySystem(systemCode: string): Unit[] {return Array.from(this.units.values()).filter(unit => unit.system === systemCode);}// 单位转换convert(value: number, fromUnitCode: string, toUnitCode: string): number {const fromUnit = this.getUnit(fromUnitCode);const toUnit = this.getUnit(toUnitCode);if (!fromUnit || !toUnit) {throw new Error(`Unit not found: ${fromUnitCode} or ${toUnitCode}`);}if (fromUnit.dimension !== toUnit.dimension) {throw new Error(`Cannot convert between different dimensions: ${fromUnit.dimension} and ${toUnit.dimension}`);}// 线性转换: value * (fromUnit.factor / toUnit.factor) + offsetconst baseValue = (value - (fromUnit.offset || 0)) * fromUnit.factor;return baseValue / toUnit.factor + (toUnit.offset || 0);}// 批量转换convertValue(quantity: QuantityValue, toUnitCode: string): ConversionResult {const result = this.convert(quantity.value, quantity.unit, toUnitCode);return {value: result,unit: toUnitCode,originalValue: quantity.value,originalUnit: quantity.unit};}// 获取可转换的单位列表getConvertibleUnits(unitCode: string): Unit[] {const unit = this.getUnit(unitCode);if (!unit) return [];return this.getUnitsByDimension(unit.dimension).filter(u => u.code !== unitCode);}
}// 创建单例实例
export const unitManager = new UnitManager();

3. 初始化单位数据

// data/units.ts
import { Unit, UnitSystem } from '../types/unit';// 定义单位系统
export const unitSystems: UnitSystem[] = [{ code: 'system1', name: '系统1', description: '使用毫米和帕斯卡的系统' },{ code: 'system2', name: '系统2', description: '使用米和兆帕的系统' }
];// 定义单位
export const units: Unit[] = [// 长度单位{ code: 'mm', name: '毫米', dimension: 'length', system: 'system1', factor: 0.001 },{ code: 'cm', name: '厘米', dimension: 'length', system: 'system1', factor: 0.01 },{ code: 'm', name: '米', dimension: 'length', system: 'system2', factor: 1 },{ code: 'km', name: '千米', dimension: 'length', system: 'system2', factor: 1000 },// 压强单位{ code: 'Pa', name: '帕斯卡', dimension: 'pressure', system: 'system1', factor: 1 },{ code: 'kPa', name: '千帕', dimension: 'pressure', system: 'system1', factor: 1000 },{ code: 'MPa', name: '兆帕', dimension: 'pressure', system: 'system2', factor: 1000000 },{ code: 'bar', name: '巴', dimension: 'pressure', system: 'system2', factor: 100000 },// 温度单位(非线性转换示例){ code: '°C', name: '摄氏度', dimension: 'temperature', system: 'system1', factor: 1, offset: 0 },{ code: '°F', name: '华氏度', dimension: 'temperature', system: 'system2', factor: 5/9, offset: -32 * 5/9 },{ code: 'K', name: '开尔文', dimension: 'temperature', system: 'system2', factor: 1, offset: -273.15 }
];

4. React Hooks

// hooks/useUnitSystem.ts
import { useState, useCallback, useMemo } from 'react';
import { Unit, QuantityValue, ConversionResult } from '../types/unit';
import { unitManager } from '../services/UnitManager';export const useUnitSystem = () => {const [currentSystem, setCurrentSystem] = useState<string>('system1');// 获取当前系统的单位const getCurrentSystemUnits = useCallback((): Unit[] => {return unitManager.getUnitsBySystem(currentSystem);}, [currentSystem]);// 按维度获取当前系统的单位const getUnitsByDimensionInCurrentSystem = useCallback((dimension: string): Unit[] => {const allUnits = unitManager.getUnitsByDimension(dimension);return allUnits.filter(unit => unit.system === currentSystem);}, [currentSystem]);// 转换到当前系统的对应单位const convertToCurrentSystem = useCallback((value: number, fromUnitCode: string): ConversionResult | null => {try {const fromUnit = unitManager.getUnit(fromUnitCode);if (!fromUnit) return null;// 找到当前系统中同维度的单位const targetUnits = getUnitsByDimensionInCurrentSystem(fromUnit.dimension);if (targetUnits.length === 0) return null;// 通常选择第一个单位作为目标单位const targetUnit = targetUnits[0];return unitManager.convertValue({ value, unit: fromUnitCode }, targetUnit.code);} catch (error) {console.error('Conversion error:', error);return null;}}, [getUnitsByDimensionInCurrentSystem]);// 批量转换到当前系统const convertMultipleToCurrentSystem = useCallback((values: QuantityValue[]): (ConversionResult | null)[] => {return values.map(value => convertToCurrentSystem(value.value, value.unit));}, [convertToCurrentSystem]);return {currentSystem,setCurrentSystem,getCurrentSystemUnits,getUnitsByDimensionInCurrentSystem,convertToCurrentSystem,convertMultipleToCurrentSystem,unitManager};
};

5. 单位选择器组件

// components/UnitSelector.tsx
import React from 'react';
import { Unit } from '../types/unit';
import { unitManager } from '../services/UnitManager';interface UnitSelectorProps {dimension: string;value: string;onChange: (unitCode: string) => void;excludeUnits?: string[];className?: string;
}export const UnitSelector: React.FC<UnitSelectorProps> = ({dimension,value,onChange,excludeUnits = [],className = ''
}) => {const units = unitManager.getUnitsByDimension(dimension).filter(unit => !excludeUnits.includes(unit.code));return (<select value={value} onChange={(e) => onChange(e.target.value)}className={className}>{units.map(unit => (<option key={unit.code} value={unit.code}>{unit.name} ({unit.code})</option>))}</select>);
};

6. 单位转换器组件

// components/UnitConverter.tsx
import React, { useState, useMemo } from 'react';
import { UnitSelector } from './UnitSelector';
import { unitManager } from '../services/UnitManager';interface UnitConverterProps {dimension: string;initialValue?: number;initialUnit?: string;
}export const UnitConverter: React.FC<UnitConverterProps> = ({dimension,initialValue = 0,initialUnit
}) => {const units = unitManager.getUnitsByDimension(dimension);const defaultUnit = initialUnit || units[0]?.code;const [inputValue, setInputValue] = useState<number>(initialValue);const [inputUnit, setInputUnit] = useState<string>(defaultUnit);const [outputUnit, setOutputUnit] = useState<string>(units.find(u => u.code !== defaultUnit)?.code || defaultUnit);const convertedValue = useMemo(() => {if (!inputUnit || !outputUnit) return null;try {return unitManager.convert(inputValue, inputUnit, outputUnit);} catch (error) {return null;}}, [inputValue, inputUnit, outputUnit]);const convertibleUnits = unitManager.getConvertibleUnits(inputUnit);return (<div className="unit-converter"><div className="input-section"><inputtype="number"value={inputValue}onChange={(e) => setInputValue(parseFloat(e.target.value) || 0)}className="value-input"/><UnitSelectordimension={dimension}value={inputUnit}onChange={setInputUnit}excludeUnits={[outputUnit]}/></div><div className="output-section"><span className="converted-value">{convertedValue !== null ? convertedValue.toFixed(4) : 'N/A'}</span><UnitSelectordimension={dimension}value={outputUnit}onChange={setOutputUnit}excludeUnits={[inputUnit]}/></div>{convertibleUnits.length > 0 && (<div className="quick-conversions"><h4>快速转换:</h4>{convertibleUnits.map(unit => (<buttonkey={unit.code}onClick={() => setOutputUnit(unit.code)}className={`quick-btn ${outputUnit === unit.code ? 'active' : ''}`}>{unit.name}</button>))}</div>)}</div>);
};

7. 系统初始化

// App.tsx
import React from 'react';
import { unitManager } from './services/UnitManager';
import { unitSystems, units } from './data/units';
import { UnitConverter } from './components/UnitConverter';
import { useUnitSystem } from './hooks/useUnitSystem';
import './App.css';// 初始化单位系统
unitSystems.forEach(system => unitManager.registerSystem(system));
unitManager.registerUnits(units);function App() {const { currentSystem, setCurrentSystem, getCurrentSystemUnits } = useUnitSystem();return (<div className="App"><header className="app-header"><h1>单位转换系统</h1><div className="system-selector"><label>当前系统: </label><select value={currentSystem} onChange={(e) => setCurrentSystem(e.target.value)}>{unitSystems.map(system => (<option key={system.code} value={system.code}>{system.name}</option>))}</select></div></header><main className="app-main"><div className="converter-section"><h2>长度转换</h2><UnitConverter dimension="length" initialValue={1000} initialUnit="mm" /></div><div className="converter-section"><h2>压强转换</h2><UnitConverter dimension="pressure" initialValue={1} initialUnit="MPa" /></div><div className="converter-section"><h2>温度转换</h2><UnitConverter dimension="temperature" initialValue={25} initialUnit="°C" /></div><div className="current-system-units"><h3>当前系统单位列表</h3><ul>{getCurrentSystemUnits().map(unit => (<li key={unit.code}>{unit.name} ({unit.code}) - {unit.dimension}</li>))}</ul></div></main></div>);
}export default App;

8. 使用示例

// 在组件中使用
import React from 'react';
import { useUnitSystem } from './hooks/useUnitSystem';const MyComponent: React.FC = () => {const { currentSystem, convertToCurrentSystem,unitManager } = useUnitSystem();// 示例:将不同系统的值转换为当前系统const values = [{ value: 1000, unit: 'mm' },{ value: 1, unit: 'MPa' },{ value: 25, unit: '°C' }];const convertedValues = convertMultipleToCurrentSystem(values);return (<div><h3>当前系统: {currentSystem}</h3>{convertedValues.map((result, index) => (result && (<div key={index}>{values[index].value} {values[index].unit} = {result.value} {result.unit}</div>)))}</div>);
};

http://www.dtcms.com/a/427450.html

相关文章:

  • React 18 前端最佳实践技术栈清单(2025版)
  • jsp网站开发 开题依据设计一个企业网站大概多少钱
  • 计算机网络---应用层
  • 营销网站的例子公司软件定制开发
  • SpringBoot3+WebSocket+Vue3+TypeScript实现简易在线聊天室(附完整源码参考)
  • 农作物空间分布数据集整理
  • C# UDP 服务端与客户端2.0
  • Gartner发布威胁情报的演变趋势:成为统一的网络风险情报,更加主动、协作和以行动为中心,以应对不断演变的全球网络威胁
  • 建站快车打电话安装wordpress的目录改变了
  • Spring Boot 2.5集成Elasticsearch(亲测)
  • Eclipse 快速修复
  • 赣州专业网站推广多少钱专门做任务的网站6
  • 如何快速切换网络配置?高效实现IP、MAC、主机名一体化管理
  • Mosquitto 架构分析:解读 mosquitto.c 的核心作用与执行流程
  • 单克隆抗体的核心概念
  • Java 并发锁实战手册:各类锁的特性、适用场景与选择方法论
  • 从化商城网站建设wordpress主题制作全过程
  • 传统网站架构 和 现代云服务 的区别简要分析
  • numpy -- 字符串函数 add()与multiply()
  • 使用Polars和PyTorch完成药物发现
  • 利津网站定制网络游戏投诉平台
  • 网站建设询价做网站必须网站备案
  • 跛脚就被辞退,道歉有用还要制度干什么?
  • 在windows 的子系统Ubuntu部署qanything-v2
  • AudioNotes:当FunASR遇见Qwen2,音视频转笔记的技术革命
  • 蛋白质结构预测:从AlphaFold到未来的计算生物学革命
  • 地区性中介类网站建设做网站的电脑需要什么配置
  • 4-6〔O҉S҉C҉P҉ ◈ 研记〕❘ WEB应用攻击▸文件上传漏洞-A
  • 《五年级上册语文1-8单元习作详解》+五年级语文作文指导/各单元提纲/写作技巧+完整电子版可下载打印
  • 第二届管理与智能社会发展国际学术会议(MISD 2026)