1
0
forked from zguiy/utils
Files
utils/src/components/tools/UnicodeConverter.vue
2025-06-28 22:38:49 +08:00

323 lines
9.3 KiB
Vue

<template>
<div class="space-y-6">
<!-- 转换工具栏 -->
<div class="card p-4">
<div class="flex flex-wrap gap-2">
<button
@click="() => convertTo('unicode')"
class="btn-primary"
>
<FontAwesomeIcon :icon="['fas', 'arrow-right']" class="mr-2" />
转为Unicode编码
</button>
<button
@click="() => convertTo('text')"
class="btn-secondary"
>
<FontAwesomeIcon :icon="['fas', 'arrow-left']" class="mr-2" />
解码为文本
</button>
<button
@click="() => convertTo('hex')"
class="btn-secondary"
>
<FontAwesomeIcon :icon="['fas', 'hashtag']" class="mr-2" />
转为16进制
</button>
<button
@click="clearAll"
class="btn-secondary"
>
<FontAwesomeIcon :icon="['fas', 'trash']" class="mr-2" />
清空
</button>
</div>
</div>
<!-- 输入输出区域 -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<!-- 输入区域 -->
<div class="card p-4">
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-semibold text-primary">输入</h3>
<button
@click="pasteFromClipboard"
class="p-2 rounded text-secondary hover:text-primary transition-colors"
title="粘贴"
>
<FontAwesomeIcon :icon="['fas', 'clipboard']" />
</button>
</div>
<textarea
v-model="inputText"
placeholder="输入要转换的文本或Unicode编码..."
class="textarea-field h-80"
/>
<div class="mt-3 text-sm text-tertiary">
<p>字符数量: {{ inputText.length }}</p>
</div>
</div>
<!-- 输出区域 -->
<div class="card p-4">
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-semibold text-primary">输出</h3>
<button
@click="copyToClipboard"
:disabled="!outputText"
class="p-2 rounded text-secondary hover:text-primary transition-colors disabled:opacity-50"
title="复制"
>
<FontAwesomeIcon
:icon="copied ? ['fas', 'check'] : ['fas', 'copy']"
:class="copied && 'text-success'"
/>
</button>
</div>
<textarea
v-model="outputText"
placeholder="转换结果将显示在这里..."
class="textarea-field h-80"
readonly
/>
</div>
</div>
<!-- 字符信息 -->
<div v-if="charInfo.length > 0" class="card p-4">
<h3 class="text-lg font-semibold text-primary mb-3">字符详细信息</h3>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div
v-for="(char, index) in charInfo"
:key="index"
class="bg-block p-3 rounded"
>
<div class="text-center space-y-2">
<div class="text-2xl font-bold text-primary">{{ char.char }}</div>
<div class="text-sm text-secondary space-y-1">
<div><strong>Unicode:</strong> {{ char.unicode }}</div>
<div><strong>UTF-8:</strong> {{ char.utf8 }}</div>
<div><strong>十进制:</strong> {{ char.decimal }}</div>
<div><strong>十六进制:</strong> {{ char.hex }}</div>
<div v-if="char.description"><strong>描述:</strong> {{ char.description }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- 快速转换示例 -->
<div class="card p-4">
<h3 class="text-lg font-semibold text-primary mb-3">快速转换示例</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<h4 class="font-medium text-secondary mb-2">常用字符</h4>
<div class="space-y-2">
<button
v-for="example in examples"
:key="example.text"
@click="() => useExample(example.text)"
class="block w-full text-left p-2 bg-block hover:bg-hover rounded text-sm"
>
<span class="font-mono">{{ example.text }}</span>
<span class="text-secondary ml-2">{{ example.unicode }}</span>
</button>
</div>
</div>
<div>
<h4 class="font-medium text-secondary mb-2">转换格式说明</h4>
<div class="space-y-2 text-sm">
<div class="bg-block p-3 rounded">
<div><strong>Unicode编码格式:</strong></div>
<div class="font-mono text-xs">
\\u4E2D (JavaScript格式)<br>
U+4E2D (标准格式)<br>
&#20013; (HTML实体)
</div>
</div>
<div class="bg-block p-3 rounded">
<div><strong>支持的输入格式:</strong></div>
<div class="text-xs">
普通文本<br>
Unicode编码序列<br>
十六进制编码
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
// 响应式状态
const inputText = ref('')
const outputText = ref('')
const copied = ref(false)
const charInfo = ref<Array<{
char: string
unicode: string
utf8: string
decimal: number
hex: string
description?: string
}>>([])
// 示例数据
const examples = [
{ text: '中', unicode: '\\u4E2D' },
{ text: '文', unicode: '\\u6587' },
{ text: '😀', unicode: '\\uD83D\\uDE00' },
{ text: '©', unicode: '\\u00A9' },
{ text: '™', unicode: '\\u2122' },
{ text: '€', unicode: '\\u20AC' }
]
// 文本转Unicode
const textToUnicode = (text: string): string => {
return text.split('').map(char => {
const code = char.charCodeAt(0)
if (code > 127) {
return '\\u' + code.toString(16).toUpperCase().padStart(4, '0')
}
return char
}).join('')
}
// Unicode转文本
const unicodeToText = (unicode: string): string => {
try {
// 处理不同格式的Unicode编码
let processedUnicode = unicode
.replace(/\\u([0-9a-fA-F]{4})/g, '\\u$1')
.replace(/U\+([0-9a-fA-F]{4})/g, '\\u$1')
.replace(/&#(\d+);/g, (match, dec) => {
const hex = parseInt(dec).toString(16).toUpperCase().padStart(4, '0')
return '\\u' + hex
})
return JSON.parse('"' + processedUnicode + '"')
} catch (error) {
throw new Error('Unicode格式错误')
}
}
// 文本转十六进制
const textToHex = (text: string): string => {
return text.split('').map(char => {
const code = char.charCodeAt(0)
return '0x' + code.toString(16).toUpperCase().padStart(4, '0')
}).join(' ')
}
// 转换函数
const convertTo = (type: 'unicode' | 'text' | 'hex') => {
if (!inputText.value.trim()) return
try {
switch (type) {
case 'unicode':
outputText.value = textToUnicode(inputText.value)
break
case 'text':
outputText.value = unicodeToText(inputText.value)
break
case 'hex':
outputText.value = textToHex(inputText.value)
break
}
} catch (error) {
outputText.value = '转换失败: ' + (error instanceof Error ? error.message : '未知错误')
}
}
// 分析字符信息
const analyzeCharacters = (text: string) => {
if (!text || text.length > 20) {
charInfo.value = []
return
}
charInfo.value = text.split('').map(char => {
const code = char.charCodeAt(0)
const unicode = '\\u' + code.toString(16).toUpperCase().padStart(4, '0')
// UTF-8 编码
const utf8Bytes = new TextEncoder().encode(char)
const utf8 = Array.from(utf8Bytes).map(b => '0x' + b.toString(16).toUpperCase()).join(' ')
return {
char,
unicode,
utf8,
decimal: code,
hex: '0x' + code.toString(16).toUpperCase(),
description: getCharDescription(char, code)
}
})
}
// 获取字符描述
const getCharDescription = (char: string, code: number): string | undefined => {
if (code >= 0x4E00 && code <= 0x9FFF) return 'CJK统一汉字'
if (code >= 0x3040 && code <= 0x309F) return '平假名'
if (code >= 0x30A0 && code <= 0x30FF) return '片假名'
if (code >= 0x1F600 && code <= 0x1F64F) return 'Emoji表情'
if (code >= 0x0020 && code <= 0x007F) return 'ASCII字符'
if (code >= 0x00A0 && code <= 0x00FF) return 'Latin-1补充'
return undefined
}
// 使用示例
const useExample = (text: string) => {
inputText.value = text
convertTo('unicode')
}
// 清空所有内容
const clearAll = () => {
inputText.value = ''
outputText.value = ''
charInfo.value = []
}
// 粘贴功能
const pasteFromClipboard = async () => {
try {
const text = await navigator.clipboard.readText()
inputText.value = text
} catch (error) {
console.error('粘贴失败:', error)
}
}
// 复制功能
const copyToClipboard = async () => {
if (!outputText.value) return
try {
await navigator.clipboard.writeText(outputText.value)
copied.value = true
setTimeout(() => {
copied.value = false
}, 2000)
} catch (error) {
console.error('复制失败:', error)
}
}
// 监听输入变化,自动分析字符
watch(inputText, (newValue) => {
analyzeCharacters(newValue)
}, { immediate: true })
</script>