#HarmonyOS NEXT体验官# 实现基于HarmonyOS Next的万能计算器 原创
本文详细介绍了如何实现一个基于HarmonyOS Next的万能计算器,下面是一些效果图。计算器的主要功能博阿凯基础的计算功能,单位转换,进制转换。
主界面
app的主界面使用ArkUI实现,核心的功能使用Web组件以及js实现,也就是上面的工具栏在Index.ets中完成,代码如下:
代码详细中文注释与实现原理
这段代码是基于 ArkTS 实现的应用程序主界面,主要包括了主界面的布局和交互逻辑。以下是对代码的详细中文注释和实现原理的解释。
import { MarginType } from '@kit.ArkUI';
import { ShapePanel } from '../components/ShapePanel'
import { webview } from '@kit.ArkWeb';
import { trimQuotes } from './common'
import { media } from '@kit.MediaKit';
import { BusinessError } from '@ohos.base';
import { window } from '@kit.ArkUI';
import { common } from '@kit.AbilityKit';
import { systemShare } from '@kit.ShareKit';
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
// 扩展 Row 组件,定义一个背景样式函数
@Extend(Row)
function backgroundStyle() {
.width('100%')
.height(40)
.padding({ top: 5, left: 10, bottom: 5, right: 10 })
// 设置背景颜色为状态栏背景色
.backgroundColor($r('app.color.statusbar_background'))
}
// 扩展 Text 组件,定义一个文本样式函数,带有宽度、高度和背景颜色参数
@Extend(Text)
function textStyle(width: number, height: number, backgroundColor: ResourceColor) {
.height(height) // 设置高度
.width(width) // 设置宽度
.backgroundColor(backgroundColor) // 设置背景颜色
.textAlign(TextAlign.End) // 文本对齐方式为右对齐
.align(Alignment.BottomEnd) // 对齐方式为底部右对齐
}
// 扩展 Column 组件,定义一个列样式函数
@Extend(Column)
function columnStyle() {
.width('100%') // 设置宽度为100%
.padding(12) // 设置内边距
.borderRadius(16) // 设置圆角半径
.backgroundColor(Color.White) // 设置背景颜色为白色
.justifyContent(FlexAlign.SpaceAround) // 设置主轴对齐方式为均匀分布
}
// 扩展 Column 组件,定义一个卡片样式函数
@Extend(Column)
function cardStyle() {
.backgroundColor('#ffff00') // 设置背景颜色为黄色
.borderRadius(16) // 设置圆角半径
.width('100%') // 设置宽度为100%
.padding(12) // 设置内边距
}
// 扩展 Text 组件,定义一个侧边栏文本样式函数
@Extend(Text)
function sidebarTextStyle() {
.fontSize(25) // 设置字体大小为25
.fontColor('#ffff0000') // 设置字体颜色为红色
}
// 定义一个测试类,用于控制面板的显示状态
class testClass {
private panelState: boolean = false; // 面板状态,默认为隐藏
constructor() {
}
// 切换面板显示状态
showPanel(): boolean {
return !this.panelState; // 返回面板状态的反值
}
}
// 主界面组件
@Entry
@Component
struct Index {
@State shapePanelVisibility: Visibility = Visibility.Hidden; // 定义形状面板的可见性状态
@State color: string = '#ff00ff' // 定义一个颜色状态变量
@State shapeButtonBackgroundColor: Resource = $r('app.color.button_push_background'); // 定义形状按钮的背景颜色
@State calcButtonBackgroundColor: Resource = $r('app.color.button_push_background'); // 定义计算器按钮的背景颜色
@State dwButtonBackgroundColor: Resource = $r('app.color.statusbar_background'); // 定义单位转换按钮的背景颜色
@State jzButtonBackgroundColor: Resource = $r('app.color.statusbar_background'); // 定义进制转换按钮的背景颜色
@State shapeTitle: string = '更多功能'; // 定义形状面板的标题
@State web1: Visibility = Visibility.Visible; // 定义 Webview 1 的可见性
@State web2: Visibility = Visibility.None; // 定义 Webview 2 的可见性
@State calcVisible1: Visibility = Visibility.Visible; // 定义计算器的可见性
@State calcVisible2: Visibility = Visibility.None; // 定义单位转换的可见性
@State calcVisible3: Visibility = Visibility.None; // 定义进制转换的可见性
private webIndex: number = 1; // 定义一个用于控制 Webview 切换的索引
controller1: webview.WebviewController = new webview.WebviewController(); // 创建第一个 Webview 控制器
controller2: webview.WebviewController = new webview.WebviewController(); // 创建第二个 Webview 控制器
controller3: webview.WebviewController = new webview.WebviewController(); // 创建第三个 Webview 控制器
activeController: webview.WebviewController = this.controller1; // 定义当前活跃的 Webview 控制器
private hscroller: Scroller = new Scroller(); // 创建一个水平滚动条
// 切换形状面板的可见性
toggleShapePanel() {
if (this.shapePanelVisibility == Visibility.Visible) {
this.shapePanelVisibility = Visibility.Hidden;
this.shapeButtonBackgroundColor = $r('app.color.statusbar_background');
} else {
this.shapePanelVisibility = Visibility.Visible;
this.shapeButtonBackgroundColor = $r('app.color.button_push_background');
}
}
// 构建主界面布局
build() {
// 创建一个列布局
Column() {
// 创建一个行布局,用于容纳多个按钮
Row({ space: 15 }) {
// 创建“形状”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.shapes')).width(16).height(16) // 加载形状图标并设置大小
Text($r('app.string.shapes')) // 显示形状文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.visibility(Visibility.None) // 设置按钮初始不可见
.width(36)
.height(36)
.borderRadius(8)
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.backgroundColor(this.shapeButtonBackgroundColor) // 设置按钮背景颜色
.onClick(() => {
this.toggleShapePanel(); // 点击按钮时切换形状面板的可见性
})
// 创建“计算器”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.calc')).width(16).height(16) // 加载计算器图标并设置大小
Text('计算器') // 显示计算器文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(40)
.height(36)
.backgroundColor(this.calcButtonBackgroundColor) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.onClick(() => {
this.calcVisible1 = Visibility.Visible; // 显示计算器
this.calcVisible2 = Visibility.None; // 隐藏单位转换
this.calcVisible3 = Visibility.None; // 隐藏进制转换
this.calcButtonBackgroundColor = $r('app.color.button_push_background'); // 更新按钮背景颜色
this.dwButtonBackgroundColor = $r('app.color.statusbar_background');
this.jzButtonBackgroundColor = $r('app.color.statusbar_background');
this.activeController = this.controller1; // 设置活跃控制器为第一个 Webview 控制器
})
// 创建“单位转换”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.dw')).width(16).height(16) // 加载单位转换图标并设置大小
Text('单位转换') // 显示单位转换文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(40)
.height(36)
.backgroundColor(this.dwButtonBackgroundColor) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.onClick(() => {
this.calcVisible2 = Visibility.Visible; // 显示单位转换
this.calcVisible1 = Visibility.None; // 隐藏计算器
this.calcVisible3 = Visibility.None; // 隐藏进制转换
this.shapePanelVisibility = Visibility.Hidden; // 隐藏形状面板
this.dwButtonBackgroundColor = $r('app.color.button
_push_background'); // 更新按钮背景颜色
this.calcButtonBackgroundColor = $r('app.color.statusbar_background');
this.jzButtonBackgroundColor = $r('app.color.statusbar_background');
this.activeController = this.controller2; // 设置活跃控制器为第二个 Webview 控制器
})
// 创建“进制转换”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.jz')).width(16).height(16) // 加载进制转换图标并设置大小
Text('进制转换') // 显示进制转换文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(40)
.height(36)
.backgroundColor(this.jzButtonBackgroundColor) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.onClick(() => {
this.calcVisible3 = Visibility.Visible; // 显示进制转换
this.calcVisible1 = Visibility.None; // 隐藏计算器
this.calcVisible2 = Visibility.None; // 隐藏单位转换
this.shapePanelVisibility = Visibility.Hidden; // 隐藏形状面板
this.jzButtonBackgroundColor = $r('app.color.button_push_background'); // 更新按钮背景颜色
this.dwButtonBackgroundColor = $r('app.color.statusbar_background');
this.calcButtonBackgroundColor = $r('app.color.statusbar_background');
this.activeController = this.controller3; // 设置活跃控制器为第三个 Webview 控制器
})
// 创建“分享”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.share')).width(16).height(16) // 加载分享图标并设置大小
Text('分享') // 显示分享文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(40)
.height(36)
.backgroundColor($r('app.color.statusbar_background')) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.onClick(() => {
this.activeController.runJavaScript('getSharedText()').then(data => {
let sharedData: systemShare.SharedData = new systemShare.SharedData({
utd: utd.UniformDataType.PLAIN_TEXT,
content: trimQuotes(data)
});
// 构建 ShareController
let controller: systemShare.ShareController = new systemShare.ShareController(sharedData);
// 获取 UIAbility 上下文对象
let context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
// 注册分享面板关闭监听
controller.on('dismiss', () => {
console.log('Share panel closed');
// 分享结束后,可处理其他业务
});
controller.show(context, {
previewMode: systemShare.SharePreviewMode.DETAIL,
selectionMode: systemShare.SelectionMode.SINGLE
});
}).catch();
})
// 创建“多选”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.multi_selection')).width(16).height(16) // 加载多选图标并设置大小
Text($r('app.string.multi_selection')) // 显示多选文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(36)
.height(36)
.backgroundColor($r('app.color.statusbar_background')) // 设置按钮背景颜色
.visibility(Visibility.None) // 设置按钮初始不可见
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
// 创建“设置”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.settings')).width(16).height(16) // 加载设置图标并设置大小
Text($r('app.string.settings')) // 显示设置文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(36)
.height(36)
.visibility(Visibility.None) // 设置按钮初始不可见
.backgroundColor($r('app.color.statusbar_background')) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
}.backgroundStyle() // 使用定义的背景样式
.justifyContent(FlexAlign.Start) // 设置主轴对齐方式为左对齐
.alignItems(VerticalAlign.Center) // 设置交叉轴对齐方式为居中对齐
// 创建堆叠布局,用于容纳多个 Webview 和侧边栏
Stack() {
Column() {
// 创建第一个 Webview
Web({ src: $rawfile('fabric1.html'), controller: this.controller1 })
.size({ width: '100%', height: '100%' }) // 设置 Webview 尺寸
.domStorageAccess(true) // 允许访问 DOM 存储
.javaScriptProxy({
object: this,
name: "obj",
methodList: ["toggleShapePanel"],
controller: this.controller1
}).visibility(this.calcVisible1); // 根据状态设置 Webview 的可见性
// 创建第二个 Webview
Web({ src: $rawfile('dw.html'), controller: this.controller2 })
.size({ width: '100%', height: '100%' })
.domStorageAccess(true)
.javaScriptProxy({
object: this,
name: "obj",
methodList: ["toggleShapePanel"],
controller: this.controller2
}).visibility(this.calcVisible2);
// 创建第三个 Webview
Web({ src: $rawfile('jz.html'), controller: this.controller3 })
.size({ width: '100%', height: '100%' })
.domStorageAccess(true)
.javaScriptProxy({
object: this,
name: "obj",
methodList: ["toggleShapePanel"],
controller: this.controller3
}).visibility(this.calcVisible3);
}
.height('100%')
.width('100%')
.height('100%')
.alignSelf(ItemAlign.Start)
// 创建形状面板列布局
Column() {
Row() {
// 创建“关闭”按钮
Button({ type: ButtonType.Normal }) {
Column() {
Image($r('app.media.close')).width(16).height(16) // 加载关闭图标并设置大小
Text($r('app.string.close')) // 显示关闭文本
.fontSize(10)
.fontColor(0xffffff)
.fontWeight(FontWeight.Bold)
.margin({ top: 4 }) // 设置上边距
}
}
.width(36)
.height(36)
.backgroundColor($r('app.color.shape_panel_background')) // 设置按钮背景颜色
.padding({ top: 3, bottom: 3 }) // 设置上下内边距
.onClick(() => {
this.toggleShapePanel(); // 点击按钮时切换形状面板的可见性
})
}.height(50).width('100%') // 设置行布局高度为50,宽度为100%
.backgroundColor($r('app.color.shape_panel_background')) // 设置背景颜色
.justifyContent(FlexAlign.SpaceAround) // 设置主轴对齐方式为均匀分布
// 显示形状面板标题
Text(this.shapeTitle) {
}
.height(20)
.width('100%')
.textAlign(TextAlign.Center) // 设置文本居中对齐
.backgroundColor($r('app.color.shape_title_background')) // 设置背景颜色
.fontColor('#ffffff') // 设置字体颜色为白色
.fontSize(11) // 设置字体大小为11
// 创建形状面板按钮布局
Column() {
Button("π") // 创建“π”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("π")'); // 点击按钮时向 Webview 发送 JavaScript 命令
});
Button("e") // 创建“e”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("e")');
});
Button("sin") // 创建“sin”按钮
.width("
80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("sin(")');
});
Button("cos") // 创建“cos”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("cos(")');
});
Button("tan") // 创建“tan”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("tan(")');
});
Button("log") // 创建“log”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("log(")');
});
Button("ln") // 创建“ln”按钮
.width("80")
.height("80")
.fontSize(25)
.type(ButtonType.Normal)
.backgroundColor("#444444")
.onClick(() => {
this.controller1.runJavaScript('addText("ln(")');
});
}.width("100%") // 设置列布局宽度为100%
}.width(80) // 设置列布局宽度为80
.height('100%') // 设置列布局高度为100%
.backgroundColor($r('app.color.shape_panel_background')) // 设置背景颜色
.visibility(this.shapePanelVisibility) // 设置列布局的可见性
}
.backgroundColor('#ff00FF00') // 设置堆叠布局的背景颜色
.width('100%') // 设置宽度为100%
.height('100%') // 设置高度为100%
.alignContent(Alignment.TopStart) // 设置内容对齐方式为顶部左对齐
.margin({ top: 3 }) // 设置顶部边距为3
}
.width('100%') // 设置列布局宽度为100%
.height('100%') // 设置列布局高度为100%
.backgroundColor('#444444') // 设置列布局的背景颜色
}
}
代码实现原理
这段代码实现了一个基于 ArkTS 的应用程序主界面,包含以下几个主要部分:
-
主界面布局:
- 主界面主要使用
Column
(列布局)和Row
(行布局)来组织按钮和其他界面元素。不同功能的按钮(如“形状”、“计算器”、“单位转换”、“进制转换”、“分享”等)位于行布局中,用户可以通过点击这些按钮在不同的 Webview 中切换功能。
- 主界面主要使用
-
按钮和面板的交互:
- 用户点击按钮时,会触发
onClick
事件,代码会根据按钮的功能调整相关面板的显示状态以及按钮的背景颜色。例如,点击“形状”按钮时,会切换形状面板的可见性。
- 用户点击按钮时,会触发
-
Webview 的切换:
- 代码中创建了三个 Webview 控制器,通过点击按钮切换不同的 Webview 显示不同的内容(如计算器、单位转换、进制转换)。控制器的切换通过更新
activeController
来实现,保证不同 Webview 之间的独立性。
- 代码中创建了三个 Webview 控制器,通过点击按钮切换不同的 Webview 显示不同的内容(如计算器、单位转换、进制转换)。控制器的切换通过更新
-
形状面板:
- 形状面板包含一些用于在 Webview 中插入特定符号的按钮(如 π、e、sin、cos 等)。这些按钮点击时会调用 Webview 中的 JavaScript 方法,实现与网页内容的交互。
-
共享功能:
- 在“分享”按钮的点击事件中,代码通过调用系统的分享功能,将指定的文本内容分享给其他应用。这一部分的实现依赖于 ArkTS 提供的
systemShare
和common
模块。
- 在“分享”按钮的点击事件中,代码通过调用系统的分享功能,将指定的文本内容分享给其他应用。这一部分的实现依赖于 ArkTS 提供的
通过这些部分的实现,代码构建了一个功能丰富的应用程序主界面,用户可以通过界面进行多种操作,并通过 Webview 与网页内容进行交互。
基础计算功能
基础计算功能由calc.html完成,在Web组件中会装载这个calc.html,代码和实现原理如下:
代码详细中文注释与实现原理
HTML 结构与样式部分
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" name="viewport" content="user-scalable=no">
<!-- 设置网页的字符编码为UTF-8,并禁止用户缩放网页 -->
<title>Web计算器</title>
<!-- 设置网页标题为"Web计算器" -->
<style>
/* 全局样式,应用于 body 和 html 元素 */
body, html {
height: 100%; /* 设置页面高度为100% */
margin: 0; /* 移除默认外边距 */
font-family: Arial, sans-serif; /* 设置字体为Arial */
user-select: none; /* 禁止用户选择文本 */
}
/* 计算器的整体样式 */
.calculator {
display: flex;
flex-direction: column; /* 设置布局方向为垂直 */
height: 100%; /* 计算器高度占满整个页面 */
}
/* 输入框和结果框的样式 */
.input,
.result {
flex: 0.25; /* 输入框区域占整个高度的1/4 */
background-color: #f0f0f0; /* 设置背景颜色为浅灰色 */
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
padding: 20px; /* 设置内边距 */
border-bottom: 1px solid #ccc; /* 设置底部边框 */
}
/* 输入框和结果框中的输入元素样式 */
.input input,
.result input {
width: 100%; /* 设置宽度为100% */
height: 100%; /* 设置高度为100% */
border: none; /* 去除边框 */
background: none; /* 去除背景 */
font-size: 5em; /* 设置字体大小为5em */
text-align: right; /* 文本右对齐 */
padding: 10px; /* 设置内边距 */
}
/* 结果框的特定样式 */
.result {
flex: 0.1; /* 结果框高度占整体的1/10 */
}
/* 按钮区域的样式 */
.buttons {
display: grid; /* 使用网格布局 */
grid-template-columns: repeat(4, 1fr); /* 将按钮分为4列 */
grid-template-rows: 0.5fr repeat(5, 1fr); /* 设置按钮的行比例 */
flex: 0.6; /* 按钮区域占高度的60% */
}
/* 按钮的样式 */
.button {
font-size: 5em; /* 设置按钮文字大小为5em */
border: 1px solid #ccc; /* 设置边框 */
background-color: #e8e8e8; /* 设置背景颜色 */
display: flex;
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
transition: background-color 0.2s; /* 设置背景颜色过渡效果 */
}
.button:active {
background-color: #d4d4d4; /* 设置按钮按下时的背景颜色 */
}
/* 占据两列空间的小按钮样式 */
.small-button {
grid-column: span 2;
}
/* 修复iOS设备上的激活状态保持问题 */
.button:active {
background-color: #ccc;
outline: none; /* 去除焦点轮廓 */
}
.button:focus {
outline: none; /* 去除焦点轮廓 */
}
</style>
</head>
<body>
实现原理概述
这段代码实现了一个基于 HTML 和 JavaScript 的 Web 计算器。计算器的布局使用了 HTML 和 CSS 来组织输入框、结果框以及按钮。核心功能通过 JavaScript 实现,支持基础的算术运算以及一些常见的数学函数。
实现步骤
-
界面布局
- 计算器界面使用
flexbox
布局来垂直排列不同的区域。 - 顶部是一个用于输入公式的文本框和一个显示结果的文本框,按钮区域使用
grid
布局,将按钮排列为4列。
- 计算器界面使用
-
按钮功能
- 每个按钮代表不同的操作符、数字或功能键,点击按钮时会触发对应的操作。
- 特殊按钮如 “C” 清除输入,“⌫” 删除最后一个字符。
-
JavaScript 逻辑
calculateAndUpdate()
函数根据输入框中的公式计算结果并实时显示。- 特殊符号如
π
、e
以及数学函数sin
、cos
、tan
、log
、ln
等会被替换为 JavaScript 对应的数学函数进行计算。 - 使用
eval()
函数来动态计算表达式结果,确保用户输入的公式能够正确解析和计算。
-
交互
- 用户点击按钮后,公式输入框会被更新,
calculateAndUpdate()
会被调用来更新结果。 - 通过
DOMContentLoaded
事件,确保页面内容加载完毕后为按钮绑定点击事件,增强用户体验。
- 用户点击按钮后,公式输入框会被更新,
这个 Web 计算器通过简洁的布局和基本的数学运算功能,为用户提供了一个直观的界面来进行计算操作。
单位转换
单位转换使用dw.html实现,代码和实现原理如下:
代码的详细中文注释与实现原理
这段代码实现了一个基于 HTML 和 JavaScript 的单位转换器,用户可以在不同的长度和重量单位之间进行转换。下面是代码的详细中文注释以及实现原理的解释。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" name="viewport" content="user-scalable=no">
<!-- 定义文档类型,设置语言为中文,禁止用户缩放页面 -->
<title>单位转换器</title>
<!-- 设置页面的标题为"单位转换器" -->
<style>
/* 全局样式,应用于 body 和 html 元素 */
body, html {
margin: 0; /* 移除默认的外边距 */
padding: 0; /* 移除默认的内边距 */
height: 100%; /* 设置页面高度为100% */
display: flex; /* 使用flex布局 */
flex-direction: column; /* 垂直方向布局 */
font-family: Arial, sans-serif; /* 使用Arial字体 */
}
/* 转换器部分的样式 */
.converter-section {
display: flex; /* 使用flex布局 */
flex-direction: column; /* 垂直方向布局 */
flex: 0.2; /* 每部分占用20%的垂直空间 */
align-items: center; /* 水平居中 */
justify-content: center; /* 垂直居中 */
}
/* 标签样式 */
.converter-label {
width: 100%;
text-align: left; /* 文本左对齐 */
font-size: 2em; /* 字体大小为2em */
margin-bottom: 10px; /* 标签与输入框之间的间距 */
}
/* 控制元素(选择框和输入框)的样式 */
.converter-controls {
width: 100%;
display: flex; /* 使用flex布局 */
}
.converter-section select,
.converter-section input {
flex: 1; /* 每个控件占用相等的宽度 */
font-size: 2em; /* 字体大小为2em */
padding: 10px; /* 内边距10px */
border: 1px solid #ccc; /* 边框为浅灰色 */
margin: 0 5px; /* 两侧的外边距为5px */
}
/* 输入框的特定样式,文本右对齐 */
.converter-section input {
text-align: right;
}
/* 计算器部分样式 */
.calculator {
display: flex; /* 使用flex布局 */
flex: 0.6; /* 占用60%的垂直空间 */
}
/* 按钮区域的网格布局 */
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 定义4列布局 */
grid-template-rows: repeat(4, 1fr); /* 定义4行布局 */
width: 100%; /* 宽度100% */
height: 100%; /* 高度100% */
}
/* 按钮的样式 */
.button {
display: flex; /* 使用flex布局 */
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
border: 1px solid #ccc; /* 边框为浅灰色 */
font-size: 5em; /* 按钮字体大小为5em */
background-color: #f8f8f8; /* 按钮背景颜色为浅灰色 */
}
/* 按钮按下时的效果 */
.button:active {
background-color: #d4d4d4; /* 按下按钮时的背景颜色 */
}
/* 占据两列的按钮 */
.small-button {
grid-column: span 2; /* 占据两列的空间 */
}
/* 去除iOS上的焦点轮廓 */
.button:focus {
outline: none;
}
</style>
</head>
<body>
<!-- 转换器部分 -->
<div class="converter-section">
<!-- 从单位选择和输入 -->
<div class="converter-label">从单位</div>
<div class="converter-controls">
<select id="unit1">
<!-- 定义多个长度和重量单位的选项 -->
<option value="mm">毫米(mm)</option>
<option value="cm">厘米(cm)</option>
<option value="dm">分米(dm)</option>
<option value="m">米(m)</option>
<option value="km">千米(km)</option>
<option value="in">英寸(in)</option>
<option value="ft">英尺(ft)</option>
<option value="yd">码(yd)</option>
<option value="mi">英里(mi)</option>
<option value="mg">毫克(mg)</option>
<option value="g">克(g)</option>
<option value="kg">千克(kg)</option>
<option value="t">吨(t)</option>
</select>
<input type="number" id="input1">
<!-- 用户输入需要转换的数值 -->
</div>
</div>
<div class="converter-section">
<!-- 到单位选择和输入 -->
<div class="converter-label">到单位</div>
<div class="converter-controls">
<select id="unit2">
<!-- 定义多个长度和重量单位的选项 -->
<option value="mm">毫米(mm)</option>
<option value="cm">厘米(cm)</option>
<option value="dm">分米(dm)</option>
<option value="m">米(m)</option>
<option value="km">千米(km)</option>
<option value="in">英寸(in)</option>
<option value="ft">英尺(ft)</option>
<option value="yd">码(yd)</option>
<option value="mi">英里(mi)</option>
<option value="mg">毫克(mg)</option>
<option value="g">克(g)</option>
<option value="kg">千克(kg)</option>
<option value="t">吨(t)</option>
</select>
<input type="text" id="input2">
<!-- 转换结果的显示 -->
</div>
</div>
<!-- 计算器部分 -->
<div class="calculator">
<div class="buttons">
<!-- 定义计算器按钮区域 -->
<div class="button">7</div>
<div class="button">8</div>
<div class="button">9</div>
<div class="button" onclick="backspace()">⌫</div>
<div class="button">4</div>
<div class="button">5</div>
<div class="button">6</div>
<div class="button" onclick="swapUnits()">↑↓</div>
<div class="button">1</div>
<div class="button">2</div>
<div class="button">3</div>
<div class="button">.</div>
<div class="button">0</div>
<div class="button">00</div>
<div class="button">000</div>
<div class="button" onclick="clearInput()">C</div>
</div>
</div>
<script>
/* 定义一个函数用于单位转换 */
function convertUnit(value, fromUnit, toUnit) {
// 定义长度单位的转换比例
const lengthUnits = {
"毫米(mm)": 0.001,
"厘米(cm)": 0.01,
"分米(dm)": 0.1,
"米(m)": 1,
"千米(km)": 1000,
"英寸(in)": 0.0254,
"英尺(ft)": 0.3048,
"码(yd)": 0.9144,
"英里(mi)": 1609.34
};
// 定义重量单位的转换比例
const weightUnits = {
"毫克(mg)": 0.000001,
"克(g)": 0.001,
"千克(kg)": 1,
"吨(t)": 1000
};
try {
// 将输入的值转为数字类型
value = parseInt(value);
// 判断单位是否属于同一类别
if(lengthUnits[fromUnit] && lengthUnits[toUnit]) {
// 执行长度单位的转换
return ((value * lengthUnits[fromUnit]) / lengthUnits[toUnit]).toFixed(4);
} else if(weightUnits[fromUnit] && weightUnits[toUnit]) {
// 执行重量单位的转换
return ((value * weightUnits[fromUnit]) / weightUnits[toUnit]).toFixed(4);
} else {
// 单位不匹配或不存在
return "";
}
} catch(e) {
// 如果转换过程中出现错误,返回空字符串
return "";
}
}
/* 定义一个函数用于生成分享文本 */
function getSharedText() {
var selectElement1 = document.getElementById('unit1');
var selectedOption1 = selectElement1.options[selectElement1.selectedIndex];
var selectElement2 = document.getElementById('unit2');
var selectedOption2 = selectElement2.options[selectElement2.selectedIndex];
const input1 = document.getElementById('input1').value;
const input2 = document.getElementById('input2').value;
return input1 + selectedOption1.text + " = " + input2 + selectedOption2.text;
}
/* 定义一个函数用于更新转换结果 */
function updateConversion() {
var selectElement1 = document.getElementById('unit1');
var selectedOption1 = selectElement1.options[selectElement1.selectedIndex];
var selectElement2 = document.getElementById('unit2');
var selectedOption2 = selectElement2.options[selectElement2.selectedIndex];
const input1 = document.getElementById('input1').value;
const convertedValue = convertUnit(input1, selectedOption1.text, selectedOption2.text);
document.getElementById('input2').value = convertedValue || ''; // 显示转换结果
}
// 监听输入框内容变化事件,更新转换结果
document.getElementById('input1').addEventListener('input', updateConversion);
document.getElementById('unit1').addEventListener('change', updateConversion);
document.getElementById('unit2').addEventListener('change', updateConversion);
// 设置当前活跃的输入框为 input1
let activeInput = document.getElementById('input1');
document.getElementById('input1').onfocus = function() {
activeInput = this;
};
document.getElementById('input2').onfocus = function() {
activeInput = this;
};
// 为所有按钮添加点击事件
document.querySelectorAll('.button').forEach(button => {
button.addEventListener('click', function() {
if(!this.hasAttribute('onclick')) {
activeInput.value += this.textContent;
updateConversion();
}
});
});
// 定义回退(删除)功能
function backspace() {
activeInput.value = activeInput.value.slice(0, -1);
updateConversion();
}
// 清空输入框的内容
function clearInput() {
document.getElementById('input1').value = '';
document.getElementById('input2').value = '';
}
// 交换两个单位选择框的值,并更新转换结果
function swapUnits() {
let unit1 = document.getElementById('unit1');
let unit2 = document.getElementById('unit2');
let tempValue = unit1.value;
unit1.value = unit2.value;
unit2.value = tempValue;
updateConversion();
}
</script>
</body>
</html>
实现原理概述
-
布局和样式:
- 代码使用了
flexbox
和grid
布局来组织页面的元素,使得界面布局整齐且响应式良好。 - 页面主要分为两个部分:单位选择与输入部分、计算器部分。用户可以在单位选择部分选择转换的单位,并输入需要转换的值;计算器部分则提供数字输入和基本操作功能。
- 代码使用了
-
单位转换逻辑:
- 通过
convertUnit()
函数,根据用户选择的单位类型和输入的数值,进行单位转换。代码定义了两个字典lengthUnits
和weightUnits
来存储单位之间的转换比例。 - 当用户更改输入值或切换单位时,页面会自动更新转换结果,确保用户始终看到最新的转换值。
- 通过
-
交互功能:
- 计算器的按钮通过
addEventListener
方法为每个按钮绑定点击事件,用户点击后将对应的数字或符号添加到输入框中,并即时更新转换结果。 - 提供了
C
(清空)、⌫
(回退)等基本功能按钮,方便用户操作。 swapUnits()
函数实现单位交换功能,用户可以一键交换“从单位”和“到单位”。
- 计算器的按钮通过
-
数据更新:
- 页面中的输入框、单位选择框以及计算器按钮都被事件监听器监控,实时响应用户输入并更新结果。
updateConversion()
函数确保每次输入变化或单位选择变化时,自动计算并更新转换结果,保持界面数据的同步和实时性。
通过上述布局、逻辑和交互设计,该代码实现了一个简洁实用的单位转换器,适合用户在浏览器中快速进行单位转换操作。
进制转换
进制转换使用jz.html实现,代码和实现原理解释如下:
代码详细中文注释与实现原理
这段代码实现了一个基于 HTML 和 JavaScript 的进制转换器,用户可以在二进制、八进制、十进制和十六进制之间进行转换。以下是代码的详细中文注释以及实现原理的解释。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" name="viewport" content="user-scalable=no">
<!-- 设置文档类型、语言为中文,并禁止用户缩放页面 -->
<title>进制转换器</title>
<!-- 设置页面标题为"进制转换器" -->
<style>
/* 全局样式设置,应用于 body 和 html 元素 */
body, html {
margin: 0; /* 移除默认外边距 */
padding: 0; /* 移除默认内边距 */
height: 100%; /* 设置页面高度为100% */
display: flex; /* 使用flex布局 */
flex-direction: column; /* 垂直方向布局 */
font-family: Arial, sans-serif; /* 使用Arial字体 */
}
/* 转换器部分样式 */
.converter-section {
display: flex; /* 使用flex布局 */
flex-direction: column; /* 垂直方向布局 */
flex: 0.15; /* 每部分占用15%的垂直空间 */
align-items: center; /* 水平居中对齐 */
justify-content: center; /* 垂直居中对齐 */
}
/* 标签样式 */
.converter-label {
width: 100%;
text-align: left; /* 文本左对齐 */
font-size: 2em; /* 设置字体大小为2em */
margin-bottom: 10px; /* 标签与输入框之间的间距 */
}
/* 控制元素(选择框和输入框)的样式 */
.converter-controls {
width: 100%;
display: flex; /* 使用flex布局 */
}
.converter-section select,
.converter-section input {
flex: 1; /* 每个控件占用相等的宽度 */
font-size: 2em; /* 设置字体大小为2em */
padding: 10px; /* 设置内边距为10px */
border: 1px solid #ccc; /* 设置边框为浅灰色 */
margin: 0 5px; /* 设置左右外边距为5px */
}
/* 输入框的特定样式,文本右对齐 */
.converter-section input {
text-align: right;
}
/* 计算器部分样式 */
.calculator {
display: flex; /* 使用flex布局 */
flex: 0.7; /* 占用70%的垂直空间 */
}
/* 按钮区域的网格布局 */
.buttons {
display: grid;
grid-template-columns: repeat(4, 1fr); /* 定义4列布局 */
grid-template-rows: repeat(5, 1fr); /* 定义5行布局 */
width: 100%; /* 宽度100% */
height: 100%; /* 高度100% */
}
/* 按钮的样式 */
.button {
display: flex; /* 使用flex布局 */
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
border: 1px solid #ccc; /* 设置边框为浅灰色 */
font-size: 5em; /* 设置按钮字体大小为5em */
background-color: #f8f8f8; /* 设置按钮背景颜色为浅灰色 */
}
/* 按钮按下时的效果 */
.button:active {
background-color: #d4d4d4; /* 按下按钮时的背景颜色 */
}
/* 占据两列的按钮 */
.small-button {
grid-column: span 2; /* 占据两列的空间 */
}
/* 去除iOS上的焦点轮廓 */
.button:focus {
outline: none;
}
</style>
</head>
<body>
<!-- 转换器部分 -->
<div class="converter-section">
<!-- 从进制选择和输入 -->
<div class="converter-label">从进制</div>
<div class="converter-controls">
<select id="unit1">
<!-- 定义多个进制选项 -->
<option value="decimal">十进制</option>
<option value="binary">二进制</option>
<option value="octal">八进制</option>
<option value="hexadecimal">十六进制</option>
</select>
<input type="text" id="input1">
<!-- 用户输入需要转换的数值 -->
</div>
</div>
<div class="converter-section">
<!-- 到进制选择和输入 -->
<div class="converter-label">到进制</div>
<div class="converter-controls">
<select id="unit2">
<!-- 定义多个进制选项 -->
<option value="decimal">十进制</option>
<option value="binary">二进制</option>
<option value="octal">八进制</option>
<option value="hexadecimal">十六进制</option>
</select>
<input type="text" id="input2">
<!-- 显示转换结果 -->
</div>
</div>
<!-- 计算器部分 -->
<div class="calculator">
<div class="buttons">
<!-- 定义计算器按钮区域 -->
<div class="button" style="color:red" onclick="clearInput()">C</div>
<div class="button">00</div>
<div class="button">.</div>
<div class="button" onclick="backspace()">⌫</div>
<div class="button">7</div>
<div class="button">8</div>
<div class="button">9</div>
<div class="button">F</div>
<div class="button">4</div>
<div class="button">5</div>
<div class="button">6</div>
<div class="button">E</div>
<div class="button">1</div>
<div class="button">2</div>
<div class="button">3</div>
<div class="button">D</div>
<div class="button">0</div>
<div class="button">A</div>
<div class="button">B</div>
<div class="button">C</div>
</div>
</div>
<script>
/**
* 转换数字的基数(进制)。
* @param {string} value 要转换的值,以字符串形式表示。
* @param {string} fromBaseStr 原始进制基数的中文描述(如 "二进制"、"十进制")。
* @param {string} toBaseStr 目标进制基数的中文描述。
* @returns {string} 转换后的值,如果转换失败,则返回空字符串。
*/
function convertBase(value, fromBaseStr, toBaseStr) {
// 将中文基数描述转换为数字
const baseMap = {
"二进制": 2,
"八进制": 8,
"十进制": 10,
"十六进制": 16
};
const fromBase = baseMap[fromBaseStr];
const toBase = baseMap[toBaseStr];
try {
// 检查是否成功获取了基数
if (fromBase === undefined || toBase === undefined) {
return '';
}
// 将输入值从原始进制转换为十进制
const decimal = parseInt(value, fromBase);
if (isNaN(decimal)) {
return ''; // 如果解析失败(不是有效的数字),返回空字符串
}
// 将十进制数字转换为目标进制
return decimal.toString(toBase).toUpperCase();
} catch (error) {
// 如果转换过程中出现错误,返回空字符串
return '';
}
}
/* 定义一个函数用于生成分享文本 */
function getSharedText() {
var selectElement1 = document.getElementById('unit1');
var selectedOption1 = selectElement1.options[selectElement1.selectedIndex];
var selectElement2 = document.getElementById('unit2');
var selectedOption2 = selectElement2.options[selectElement2.selectedIndex];
const input1 = document.getElementById('input1').value;
const input2 = document.getElementById('input2').value;
return input1 + "(" + selectedOption1.text + ") = " + input2 + "(" + selectedOption2.text + ")"
}
/* 定义一个函数用于更新转换结果 */
function updateConversion() {
var selectElement1 = document.getElementById('unit1');
var selectedOption1 = selectElement1.options[selectElement1.selectedIndex];
var selectElement2 = document.getElementById('unit2');
var selectedOption2 = selectElement2.options[select
Element2.selectedIndex];
const input1 = document.getElementById('input1').value;
const convertedValue = convertBase(input1, selectedOption1.text, selectedOption2.text);
document.getElementById('input2').value = convertedValue || ''; // 如果返回空字符串,设置为空
}
// 监听输入框内容变化事件,更新转换结果
document.getElementById('input1').addEventListener('input', updateConversion);
document.getElementById('unit1').addEventListener('change', updateConversion);
document.getElementById('unit2').addEventListener('change', updateConversion);
// 设置当前活跃的输入框为 input1
let activeInput = document.getElementById('input1');
document.getElementById('input1').onfocus = function () {
activeInput = document.getElementById('input1');
};
document.getElementById('input2').onfocus = function () {
activeInput = document.getElementById('input1');
};
// 为所有按钮添加点击事件
document.querySelectorAll('.button').forEach(button => {
button.addEventListener('click', function() {
if (!this.hasAttribute('onclick')) {
activeInput.value += this.textContent.toUpperCase();
updateConversion();
}
});
});
// 定义回退(删除)功能
function backspace() {
activeInput.value = activeInput.value.slice(0, -1);
updateConversion();
}
// 清空输入框的内容
function clearInput() {
document.getElementById('input1').value = '';
document.getElementById('input2').value = '';
}
// 交换两个单位选择框的值,并更新转换结果
function swapUnits() {
let unit1 = document.getElementById('unit1');
let unit2 = document.getElementById('unit2');
let tempValue = unit1.value;
unit1.value = unit2.value;
unit2.value = tempValue;
updateConversion();
}
</script>
</body>
</html>
实现原理概述
-
布局和样式:
- 代码使用了
flexbox
和grid
布局来组织页面的元素,使得界面布局整齐且响应性良好。 - 页面主要分为两个部分:进制选择与输入部分、计算器部分。用户可以在进制选择部分选择转换的进制类型,并输入需要转换的值;计算器部分则提供数字输入和基本操作功能。
- 代码使用了
-
进制转换逻辑:
convertBase()
函数根据用户选择的原始进制和目标进制,将输入值转换为对应的进制格式。代码使用parseInt()
函数将原始进制的字符串转换为十进制数值,再使用toString()
函数将十进制数值转换为目标进制。- 当用户更改输入值或切换进制类型时,页面会自动更新转换结果,确保用户始终看到最新的转换值。
-
交互功能:
- 计算器的按钮通过
addEventListener
方法为每个按钮绑定点击事件,用户点击后将对应的数字或符号添加到输入框中,并即时更新转换结果。 - 提供了
C
(清空)、⌫
(回退)等基本功能按钮,方便用户操作。 swapUnits()
函数实现进制选择交换功能,用户可以一键交换“从进制”和“到进制”。
- 计算器的按钮通过
-
数据更新:
- 页面中的输入框、进制选择框以及计算器按钮都被事件监听器监控,实时响应用户输入并更新结果。
updateConversion()
函数确保每次输入变化或进制选择变化时,自动计算并更新转换结果,保持界面数据的同步和实时性。
通过上述布局、逻辑和交互设计,该代码实现了一个简洁实用的进制转换器,适合用户在浏览器中快速进行进制转换操作。
求源码