feat: base64编码解码工具
parent
b56daf6145
commit
220d0f4ca9
@ -0,0 +1,364 @@
|
|||||||
|
<template>
|
||||||
|
<div class="base64-tool">
|
||||||
|
<div class="container">
|
||||||
|
<el-card
|
||||||
|
class="tool-card"
|
||||||
|
:body-style="{ padding: '0' }"
|
||||||
|
>
|
||||||
|
<div class="card-header">
|
||||||
|
<h1 class="title">Base64编码/解码工具</h1>
|
||||||
|
<p class="subtitle">使用btoa和atob进行Base64编码和解码</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<el-form
|
||||||
|
:model="form"
|
||||||
|
label-width="auto"
|
||||||
|
>
|
||||||
|
<el-form-item label="输入内容">
|
||||||
|
<el-input
|
||||||
|
v-model="form.input"
|
||||||
|
type="textarea"
|
||||||
|
:rows="5"
|
||||||
|
placeholder="请输入需要编码或解码的内容"
|
||||||
|
resize="none"
|
||||||
|
class="input-textarea"
|
||||||
|
></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<div class="action-buttons">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="encode"
|
||||||
|
:icon="DocumentAdd"
|
||||||
|
class="action-btn"
|
||||||
|
>
|
||||||
|
编码
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
@click="decode"
|
||||||
|
:icon="Document"
|
||||||
|
class="action-btn"
|
||||||
|
>
|
||||||
|
解码
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
@click="clearAll"
|
||||||
|
:icon="Delete"
|
||||||
|
class="action-btn"
|
||||||
|
>
|
||||||
|
清空
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<div class="result-area">
|
||||||
|
<div class="result-header">
|
||||||
|
<h3 class="result-title">结果</h3>
|
||||||
|
<el-button
|
||||||
|
class="copy-btn"
|
||||||
|
type="info"
|
||||||
|
:icon="CopyDocument"
|
||||||
|
@click="copyResult"
|
||||||
|
:disabled="!form.result"
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
复制结果
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<div class="result-box">
|
||||||
|
<pre v-if="form.result">{{ form.result }}</pre>
|
||||||
|
<p
|
||||||
|
v-else
|
||||||
|
class="placeholder"
|
||||||
|
>
|
||||||
|
编码/解码结果将显示在这里...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive } from 'vue';
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||||
|
import { DocumentAdd, Document, Delete, CopyDocument } from '@element-plus/icons-vue';
|
||||||
|
|
||||||
|
// 响应式数据
|
||||||
|
const form = reactive({
|
||||||
|
input: '',
|
||||||
|
result: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 编码函数
|
||||||
|
const encode = () => {
|
||||||
|
if (!form.input.trim()) {
|
||||||
|
ElMessage.warning('请输入需要编码的内容');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用btoa(encodeURIComponent())进行编码
|
||||||
|
form.result = btoa(encodeURIComponent(form.input));
|
||||||
|
ElMessage.success('编码成功');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('编码失败: ' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 解码函数
|
||||||
|
const decode = () => {
|
||||||
|
if (!form.input.trim()) {
|
||||||
|
ElMessage.warning('请输入需要解码的内容');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 使用decodeURIComponent(atob())进行解码
|
||||||
|
form.result = decodeURIComponent(atob(form.input));
|
||||||
|
ElMessage.success('解码成功');
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('解码失败: ' + error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 清空函数
|
||||||
|
const clearAll = async () => {
|
||||||
|
if (form.input || form.result) {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要清空所有内容吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
});
|
||||||
|
form.input = '';
|
||||||
|
form.result = '';
|
||||||
|
ElMessage.info('已清空所有内容');
|
||||||
|
} catch {
|
||||||
|
// 用户取消清空
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ElMessage.info('内容已经是空的');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 复制结果函数
|
||||||
|
const copyResult = async () => {
|
||||||
|
if (!form.result) {
|
||||||
|
ElMessage.warning('没有可复制的内容');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(form.result);
|
||||||
|
ElMessage.success('已复制到剪贴板');
|
||||||
|
} catch (err) {
|
||||||
|
// 降级方案
|
||||||
|
const textArea = document.createElement('textarea');
|
||||||
|
textArea.value = form.result;
|
||||||
|
document.body.appendChild(textArea);
|
||||||
|
textArea.select();
|
||||||
|
try {
|
||||||
|
document.execCommand('copy');
|
||||||
|
ElMessage.success('已复制到剪贴板');
|
||||||
|
} catch {
|
||||||
|
ElMessage.error('复制失败,请手动复制');
|
||||||
|
}
|
||||||
|
document.body.removeChild(textArea);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.base64-tool {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 800px;
|
||||||
|
|
||||||
|
.tool-card {
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
background: linear-gradient(135deg, #3494e6 0%, #ec6ead 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 24px 30px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
margin: 0 0 8px 0;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
margin: 0;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 30px;
|
||||||
|
|
||||||
|
.input-textarea {
|
||||||
|
:deep(.el-textarea__inner) {
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-top: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-area {
|
||||||
|
margin-top: 30px;
|
||||||
|
border-top: 1px solid #eaeaea;
|
||||||
|
padding-top: 20px;
|
||||||
|
|
||||||
|
.result-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
.result-title {
|
||||||
|
margin: 0;
|
||||||
|
color: #2c3e50;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-box {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px;
|
||||||
|
min-height: 120px;
|
||||||
|
border: 1px solid #eaeaea;
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||||
|
line-height: 1.5;
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
margin: 0;
|
||||||
|
color: #7f8c8d;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
margin: 0;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 24px;
|
||||||
|
color: #7f8c8d;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移动端适配
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.base64-tool {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.tool-card {
|
||||||
|
.card-header {
|
||||||
|
padding: 20px 24px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-body {
|
||||||
|
padding: 24px;
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-area {
|
||||||
|
.result-header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
.copy-btn {
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 超小屏幕适配
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.base64-tool {
|
||||||
|
.container {
|
||||||
|
.tool-card {
|
||||||
|
.card-body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue