React Native for OpenHarmony 实战:摩斯密码实现

今天我们用 React Native 实现一个摩斯密码转换工具,支持文本和摩斯密码的双向转换,还带有完整的摩斯密码对照表。
摩斯密码映射表
import React, { useState, useRef } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet, ScrollView, Animated } from 'react-native';
const morseMap: { [key: string]: string } = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....',
'I': '..', 'J': '.---', 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---', 'P': '.--.',
'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-', 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-',
'Y': '-.--', 'Z': '--..', '0': '-----', '1': '.----', '2': '..---', '3': '...--', '4': '....-',
'5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', ' ': '/'
};
const reverseMorse = Object.fromEntries(Object.entries(morseMap).map(([k, v]) => [v, k]));
摩斯密码的核心是字符和编码的映射关系。
映射表设计:用对象存储 26 个字母、10 个数字、1 个空格的摩斯编码。键是字符,值是摩斯编码。比如 'A': '.-' 表示字母 A 的摩斯编码是 .-。
点和划:摩斯密码用点(.)和划(-)表示。点是短信号,划是长信号,长度是点的 3 倍。字母之间用空格分隔,单词之间用 / 分隔。
反向映射:reverseMorse 是反向映射表,键是摩斯编码,值是字符。用 Object.fromEntries 和 Object.entries 配合 map 实现键值对调。这样就能从摩斯编码反向查找字符。
为什么用对象而不是数组?因为对象的查找是 O(1) 复杂度,数组的查找是 O(n)。虽然只有 37 个字符,性能差异不大,但对象的语义更清晰。
状态设计
export const MorseCode: React.FC = () => {
const [text, setText] = useState('');
const [morse, setMorse] = useState('');
const buttonAnim1 = useRef(new Animated.Value(1)).current;
const buttonAnim2 = useRef(new Animated.Value(1)).current;
const outputAnim = useRef(new Animated.Value(1)).current;
状态设计非常简洁:
文本状态:
text:普通文本,用户输入或从摩斯密码转换得到morse:摩斯密码,从文本转换得到或用户输入
动画值:
buttonAnim1:第一个按钮(文本转摩斯)的缩放动画buttonAnim2:第二个按钮(摩斯转文本)的缩放动画outputAnim:摩斯密码输入框的缩放动画
为什么两个按钮用独立的动画值?因为用户可能快速点击不同的按钮,独立的动画值让每个按钮的动画互不干扰。
动画函数
const animateButton = (anim: Animated.Value) => {
Animated.sequence([
Animated.timing(anim, { toValue: 0.9, duration: 100, useNativeDriver: true }),
Animated.spring(anim, { toValue: 1, friction: 3, useNativeDriver: true }),
]).start();
Animated.sequence([
Animated.timing(outputAnim, { toValue: 0.95, duration: 100, useNativeDriver: true }),
Animated.spring(outputAnim, { toValue: 1, friction: 4, useNativeDriver: true }),
]).start();
};
这个函数同时触发两个动画:按钮动画和输出框动画。
按钮动画:传入的 anim 参数指定要动画化的按钮。先缩小到 90%(100ms),再弹回到 100%。friction: 3 让弹簧动画有明显的回弹效果。
输出框动画:摩斯密码输入框缩小到 95%,再弹回到 100%。friction: 4 比按钮的摩擦力大,弹性稍弱,动画更稳定。
为什么输出框缩小到 95% 而按钮缩小到 90%?因为输出框比按钮大,相同的缩放比例在大元素上更明显。95% 的缩放刚刚好,既能让用户注意到变化,又不会太夸张。
两个动画同时启动,给用户"点击按钮 → 按钮缩放 → 输出更新"的完整反馈。
文本转摩斯密码
const textToMorse = () => {
animateButton(buttonAnim1);
const result = text.toUpperCase().split('').map(c => morseMap[c] || c).join(' ');
setMorse(result);
};
文本转摩斯密码的算法很简单:
转大写:toUpperCase() 把文本转成大写,因为摩斯密码不区分大小写,映射表只有大写字母。
拆分字符:split('') 把字符串拆成字符数组,每个字符独立处理。
映射转换:map(c => morseMap[c] || c) 遍历每个字符,在映射表中查找对应的摩斯编码。如果找到(比如 'A' 找到 '.-'),返回摩斯编码;如果找不到(比如标点符号),返回原字符。
拼接结果:join(' ') 用空格把摩斯编码拼接起来。每个字符的摩斯编码之间用空格分隔,这是摩斯密码的标准格式。
示例:"HELLO" → ['H', 'E', 'L', 'L', 'O'] → ['....', '.', '.-..', '.-..', '---'] → ".... . .-.. .-.. ---"
摩斯密码转文本
const morseToText = () => {
animateButton(buttonAnim2);
const result = morse.split(' ').map(m => reverseMorse[m] || m).join('');
setText(result);
};
摩斯密码转文本是反向过程:
拆分编码:split(' ') 按空格分割,得到每个字符的摩斯编码数组。
反向映射:map(m => reverseMorse[m] || m) 遍历每个摩斯编码,在反向映射表中查找对应的字符。如果找到(比如 '.-' 找到 'A'),返回字符;如果找不到,返回原编码。
拼接结果:join('') 直接拼接,不加分隔符,因为文本字符之间不需要分隔。
示例:".... . .-.. .-.. ---" → ['....', '.', '.-..', '.-..', '---'] → ['H', 'E', 'L', 'L', 'O'] → "HELLO"
空格处理:如果摩斯密码中有 /(表示单词分隔),会被转换成空格,因为映射表中 ' ': '/',反向映射就是 '/': ' '。
鸿蒙 ArkTS 对比:转换逻辑
morseMap: Record<string, string> = {
'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', 'F': '..-.', 'G': '--.', 'H': '....',
// ... 其他映射
}
reverseMorse: Record<string, string> = {}
aboutToAppear() {
// 构建反向映射
Object.entries(this.morseMap).forEach(([k, v]) => {
this.reverseMorse[v] = k
})
}
textToMorse() {
this.animateButton(0)
const result = this.text.toUpperCase().split('').map(c => this.morseMap[c] || c).join(' ')
this.morse = result
}
morseToText() {
this.animateButton(1)
const result = this.morse.split(' ').map(m => this.reverseMorse[m] || m).join('')
this.text = result
}
ArkTS 中的转换逻辑完全一样,因为字符串方法、数组方法、对象操作都是 JavaScript 标准 API,跨平台通用。反向映射在组件初始化时构建,避免每次转换都重新计算。
界面渲染:头部和文本输入
return (
<ScrollView style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerIcon}>📡</Text>
<Text style={styles.headerTitle}>摩斯密码</Text>
<Text style={styles.headerSubtitle}>文本与摩斯密码互转</Text>
</View>
<View style={styles.inputCard}>
<Text style={styles.label}>📝 文本</Text>
<TextInput
style={styles.input}
value={text}
onChangeText={setText}
placeholder="输入文本..."
placeholderTextColor="#666"
multiline
/>
</View>
头部区域包含图标、标题、副标题。📡 天线图标表示"无线电通信"的概念,和摩斯密码的历史用途相符。
文本输入框:
- 标签"📝 文本"明确告诉用户这里输入普通文本
multiline支持多行输入,用户可以输入长文本placeholder提示用户输入内容- 最小高度 80 像素,确保有足够的空间
转换按钮和摩斯输入
<Animated.View style={{ transform: [{ scale: buttonAnim1 }] }}>
<TouchableOpacity style={styles.btn} onPress={textToMorse} activeOpacity={0.8}>
<Text style={styles.btnText}>转换为摩斯密码 ⬇️</Text>
</TouchableOpacity>
</Animated.View>
<Animated.View style={[styles.inputCard, { transform: [{ scale: outputAnim }] }]}>
<Text style={styles.label}>📡 摩斯密码</Text>
<TextInput
style={[styles.input, styles.morseInput]}
value={morse}
onChangeText={setMorse}
placeholder=".- -... -.-."
placeholderTextColor="#666"
multiline
/>
</Animated.View>
<Animated.View style={{ transform: [{ scale: buttonAnim2 }] }}>
<TouchableOpacity style={styles.btn} onPress={morseToText} activeOpacity={0.8}>
<Text style={styles.btnText}>转换为文本 ⬆️</Text>
</TouchableOpacity>
</Animated.View>
第一个按钮:用 Animated.View 包裹,应用 buttonAnim1 动画。点击时触发 textToMorse 函数,把文本转换成摩斯密码。⬇️ 箭头表示"向下转换"。
摩斯密码输入框:
- 用
Animated.View包裹,应用outputAnim动画 - 标签"📡 摩斯密码"明确告诉用户这里显示摩斯编码
morseInput样式应用等宽字体和字符间距,让摩斯编码更易读- 占位符
".- -... -.-."(ABC 的摩斯编码)提示用户格式
第二个按钮:应用 buttonAnim2 动画。点击时触发 morseToText 函数,把摩斯密码转换成文本。⬆️ 箭头表示"向上转换"。
为什么用两个按钮而不是一个切换按钮?因为两个输入框都可以编辑,用户可能在任意一个输入框输入内容,然后选择转换方向。两个按钮让转换方向更明确。
摩斯密码对照表
<View style={styles.table}>
<Text style={styles.tableTitle}>📋 摩斯密码表</Text>
<View style={styles.tableGrid}>
{Object.entries(morseMap).filter(([k]) => k !== ' ').map(([char, code]) => (
<View key={char} style={styles.tableItem}>
<Text style={styles.tableChar}>{char}</Text>
<Text style={styles.tableCode}>{code}</Text>
</View>
))}
</View>
</View>
</ScrollView>
);
};
对照表显示所有字符和对应的摩斯编码,方便用户查阅。
过滤空格:filter(([k]) => k !== ' ') 过滤掉空格,因为空格的摩斯编码是 /,显示在表格里不太合适。
网格布局:flexWrap: 'wrap' 让表格项自动换行。每个表格项宽度 16.66%(100% / 6),一行显示 6 个字符。
表格项内容:
- 上面是字符,蓝色粗体,醒目
- 下面是摩斯编码,灰色小字,起辅助说明作用
为什么显示对照表?因为摩斯密码不是常用知识,大多数人不记得编码。对照表让用户可以手动查阅,也可以学习摩斯密码。
样式定义:容器和输入框
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#0f0f23', padding: 20 },
header: { alignItems: 'center', marginBottom: 24 },
headerIcon: { fontSize: 50, marginBottom: 8 },
headerTitle: { fontSize: 28, fontWeight: '700', color: '#fff' },
headerSubtitle: { fontSize: 14, color: '#888', marginTop: 4 },
inputCard: {
backgroundColor: '#1a1a3e',
borderRadius: 16,
padding: 16,
marginBottom: 16,
borderWidth: 1,
borderColor: '#3a3a6a',
},
label: { color: '#888', fontSize: 14, marginBottom: 10 },
input: {
backgroundColor: '#252550',
padding: 14,
borderRadius: 10,
minHeight: 80,
color: '#fff',
fontSize: 16,
},
morseInput: { fontFamily: 'monospace', letterSpacing: 2 },
输入卡片用深蓝色背景,圆角 16,边框。输入框用更深的背景色,和卡片形成对比。
摩斯输入框特殊样式:
fontFamily: 'monospace':等宽字体让点和划对齐,更易读letterSpacing: 2:增加字符间距,让点和划分开,避免粘在一起
为什么摩斯编码需要等宽字体?因为摩斯编码由点和划组成,等宽字体让每个字符占据相同宽度,编码看起来更整齐。
样式定义:按钮和对照表
btn: {
backgroundColor: '#4A90D9',
padding: 16,
borderRadius: 12,
alignItems: 'center',
marginBottom: 16,
shadowColor: '#4A90D9',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.3,
shadowRadius: 8,
},
btnText: { color: '#fff', fontWeight: '700', fontSize: 16 },
table: {
backgroundColor: '#1a1a3e',
padding: 16,
borderRadius: 16,
borderWidth: 1,
borderColor: '#3a3a6a',
},
tableTitle: { fontSize: 16, fontWeight: '600', marginBottom: 16, textAlign: 'center', color: '#fff' },
tableGrid: { flexDirection: 'row', flexWrap: 'wrap' },
tableItem: { width: '16.66%', padding: 8, alignItems: 'center' },
tableChar: { fontSize: 16, fontWeight: '600', color: '#4A90D9' },
tableCode: { fontSize: 9, color: '#888', marginTop: 2 },
});
按钮用蓝色背景和蓝色阴影,是页面的视觉焦点。阴影向下偏移 4 像素,模拟"悬浮"效果。
对照表用网格布局,每个表格项宽度 16.66%(1/6),一行显示 6 个字符。字符用蓝色粗体,编码用灰色小字,形成清晰的视觉层次。
编码字号 9 很小,因为对照表要显示 36 个字符(26 个字母 + 10 个数字),如果字号太大,表格会很长,需要滚动很久。小字号让表格更紧凑。
小结
这个摩斯密码工具展示了字符映射和双向转换的实现。用对象存储映射关系,查找效率是 O(1)。反向映射通过键值对调实现,避免重复定义。转换算法用 split、map、join 三步完成,代码简洁清晰。对照表让用户可以查阅和学习摩斯密码。在 OpenHarmony 平台上,字符串和数组方法是 JavaScript 标准 API,跨平台通用。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)