在开发新项目中。我们面临一个具体场景:纯预览展示的协议文档需要动态填充用户数据。这些协议本身是静态HTML模板,但其中包含大量需要根据具体业务数据动态替换的字段,如客户姓名、贷款金额、银行信息等。
技术挑战
- 多环境适配:协议模板需要在开发、测试、生产不同环境中运行
- 数据安全:敏感数据(如银行卡号、身份证号)需要安全获取和展示
- 动态替换:协议中的占位符需要精准、高效地被实际数据替换
- 兼容性:方案需要支持多种浏览器环境和模块系统
解决方案架构
核心设计理念
我们设计了一个SignatureDataService类,作为数据获取和模板填充的核心服务。该方案采用以下关键设计:
- 环境智能判断:自动识别运行环境,配置对应的API端点
- 数据隔离存储:使用本地存储管理业务入口标识(entryCode)
- 模板引擎:轻量级占位符替换机制
- 单例模式:确保全局唯一的数据服务实例
环境配置策略
javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| function getEnvConfig() { const hostname = window.location.hostname; const href = window.location.href;
// 开发环境 if (hostname === 'localhost') { return { apiBaseUrl: 'http://localhost:8080/api', env: 'development' }; }
// 测试环境 if (href.includes('.test.') || hostname.includes('test')) { return { apiBaseUrl: '测试环境地址', env: 'testcloud' }; }
// 生产环境 return { apiBaseUrl: '生产环境地址', env: 'prodcloud' }; }
|
核心服务类
SignatureDataService类封装了完整的数据处理流程:
1. 数据获取
javascript
1 2 3 4 5 6 7 8
| async fetchSignatureData() { const entryCode = this.getEntryCode(); if (!entryCode) return null; const apiUrl = `${this.config.apiBaseUrl}/signature/getSignatureParams`; const response = await fetch(`${apiUrl}?entryCode=${encodeURIComponent(entryCode)}`); // ... 处理响应 }
|
2. 模板填充
javascript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| fillTemplate(data) { if (!data) return; let content = document.body.innerHTML; const fields = { 'bankName': data.bankName || '', 'bankCardNo': data.bankCardNo || '', // ... 其他30+字段 }; // 正则表达式替换所有${fieldName}占位符 Object.keys(fields).forEach(key => { const placeholder = `${${key}}`; const regex = new RegExp( placeholder.replace(/$/g, '\$').replace(/{/g, '\{').replace(/}/g, '\}'), 'g' ); content = content.replace(regex, this.escapeHtml(fields[key])); }); document.body.innerHTML = content; }
|
3. 安全防护
javascript
1 2 3 4 5
| escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; }
|
支持的数据字段
系统支持超过30个业务字段的自动填充,涵盖:
- 客户信息:customerName, cardNum, phoneNum
- 贷款信息:loanAmount, period, totalInterest
- 车辆信息:carModel, chassisNo, carColor
- 公司信息:companyName, companyUsci, companyAddress
- 金额相关:所有金额字段同时提供数字和中文大写形式
使用方式
1. HTML模板准备
协议模板中使用${fieldName}格式的占位符:
html
1 2 3 4 5
| <div class="contract-section"> <p>甲方(借款人):${customerName}</p> <p>身份证号:${cardNum}</p> <p>贷款金额:${loanAmount}元(${loanAmountWord})</p> </div>
|
2. 页面初始化
javascript
1 2 3 4 5 6 7 8 9 10 11 12
| // 方式一:使用默认配置 const service = window.SignatureDataService.getSignatureService(); service.initPage();
// 方式二:自定义配置 const service = new window.SignatureDataService.SignatureDataService({ storageKey: 'customEntryCode' }); service.initPage();
// 方式三:直接获取数据 const data = await window.SignatureDataService.fetchSignatureData();
|
技术优势
1. 无框架依赖
纯JavaScript实现,不依赖React、Vue等框架,适用于各种传统项目
2. 性能优化
- 单例模式减少内存开销
- 批量正则替换提升渲染效率
- 按需加载数据
3. 安全考虑
- HTML转义防止XSS攻击
- 敏感数据本地存储隔离
- HTTPS环境自动适配
4. 扩展性
- 模块化设计,易于添加新字段
- 支持CommonJS和浏览器全局两种导出方式
- 配置可覆盖,便于定制
5. 错误处理
完善的异常捕获机制:
javascript
1 2 3 4 5 6 7 8 9 10 11 12
| try { const data = await this.fetchSignatureData(); if (!data) { console.error('数据加载失败,请稍后重试'); return false; } this.fillTemplate(data); return true; } catch (error) { console.error('初始化失败:', error); return false; }
|