一、实现效果

二、实现思路
把表单里的部分数据加密后嵌入到 URL 中,形成分享链接。当其他人点击这个链接时,页面会解析 URL 里的加密数据,将其解密后填充到表单内。
1. 数据存储与状态管理
form:用来存储表单数据,包含 name、phone、email 和 address。
isSharedForm:标记当前页面是否是通过分享链接打开的,初始值为 false。
2. 加密与解密函数
定义了两个简单的加密和解密函数:
encrypt:先对输入的数据进行 encodeURIComponent 编码,再使用 btoa 进行 Base64 编码。
decrypt:先使用 atob 对 Base64 编码的数据进行解码,再用 decodeURIComponent 解码。
3. 生成分享链接
当用户点击 “分享” 按钮时,会触发 generateShareLink 函数,该函数的执行步骤如下:
数据校验:检查 name 和 phone 是否为空,若为空则使用 ElMessage 提示用户输入。
数据加密:对 name 和 phone 调用 encrypt 函数进行加密。
构造链接:以当前页面的域名(window.location.origin)为基础,加上路径 /form,并在后面添加查询参数。其中,data 参数是加密后的 name 和 phone,用 - 分隔;email 和 address 直接作为查询参数。
提示用户:使用 ElMessage 提示用户分享链接已生成,并尝试将链接复制到剪贴板。若复制成功则给出相应提示,失败则在控制台输出错误信息。
4. 页面加载时处理分享链接
在 onMounted 钩子函数里,页面加载时会执行以下操作:
解析 URL 参数:使用 URLSearchParams 解析当前 URL 的查询参数。
检查加密数据:查看 data 参数是否存在,若存在则对其进行分割,分别解密 name 和 phone,并将解密后的数据填充到表单中。同时,将 isSharedForm 标记为 true。
填充其他信息:若 email 和 address 参数存在,将其填充到表单中。
三、代码
<template>
<div class="form-container">
<!-- 按钮区域 -->
<div class="button-group">
<!-- 只有在非分享链接打开的页面中显示分享按钮 -->
<el-button v-if="!isSharedForm" type="primary" @click="generateShareLink">分享</el-button>
<!-- 在所有页面中显示保存按钮 -->
<el-button type="success" @click="saveForm">保存</el-button>
</div>
<!-- 表单内容 -->
<el-form ref="formRef" :model="form" label-width="80px">
<el-form-item label="姓名">
<el-input v-model="form.name" placeholder="请输入姓名"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input v-model="form.phone" placeholder="请输入电话"></el-input>
</el-form-item>
<el-form-item label="邮箱">
<el-input v-model="form.email" placeholder="请输入邮箱"></el-input>
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" placeholder="请输入地址"></el-input>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
// 表单数据
const form = ref({
name: '',
phone: '',
email: '',
address: ''
});
// 是否是通过分享链接打开的表单
const isSharedForm = ref(false);
// 使用简单的加密函数(示例中使用 Base64 编码)
const encrypt = (data: string): string => {
return btoa(encodeURIComponent(data));
};
// 使用简单的解密函数(示例中使用 Base64 解码)
const decrypt = (data: string): string => {
return decodeURIComponent(atob(data));
};
// 生成分享链接
const generateShareLink = () => {
const { name, phone, email, address } = form.value;
if (!name || !phone) {
ElMessage.error('请输入姓名和电话号码');
return;
}
// 对姓名和电话号码进行加密
const encryptedName = encrypt(name);
const encryptedPhone = encrypt(phone);
// 构造分享链接,包含加密后的姓名和电话,以及其他信息
const shareLink = `${window.location.origin}/form?data=${encryptedName}-${encryptedPhone}&email=${email}&address=${address}`;
// 提示用户分享链接
ElMessage.success(`分享链接已生成:${shareLink}`);
// 可以将链接复制到剪贴板
navigator.clipboard.writeText(shareLink).then(() => {
ElMessage.success('链接已复制到剪贴板');
}).catch(err => {
console.error('复制失败:', err);
});
};
// 保存表单数据
const saveForm = () => {
// 这里可以添加表单校验逻辑
if (!form.value.name || !form.value.phone) {
ElMessage.error('姓名和电话不能为空');
return;
}
// 调用后端接口保存表单数据
console.log('表单数据已保存:', form.value);
// 以下为发送请求的代码示例,暂时注释掉
// axios.post('/api/form/save', form.value).then(() => {
// ElMessage.success('表单保存成功');
// }).catch(err => {
// console.error('保存失败:', err);
// ElMessage.error('表单保存失败');
// });
};
// 页面加载时,检查是否有加密后的数据参数以及其他信息参数
onMounted(() => {
const urlParams = new URLSearchParams(window.location.search);
const dataParam = urlParams.get('data');
const emailParam = urlParams.get('email');
const addressParam = urlParams.get('address');
if (dataParam) {
// 对加密后的数据进行解密
const [encryptedName, encryptedPhone] = dataParam.split('-');
if (encryptedName && encryptedPhone) {
const decodedName = decrypt(encryptedName);
const decodedPhone = decrypt(encryptedPhone);
form.value.name = decodedName;
form.value.phone = decodedPhone;
}
// 如果是通过分享链接打开的表单,标记为共享表单
isSharedForm.value = true;
}
// 填充其他信息
if (emailParam) {
form.value.email = emailParam;
}
if (addressParam) {
form.value.address = addressParam;
}
});
</script>
<style scoped>
.form-container {
max-width: 500px;
margin: 0 auto;
padding: 20px;
}
.button-group {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
</style>



965

被折叠的 条评论
为什么被折叠?



