起因
最近接到一个需求,后端需要实现一个信用卡支付的功能,一开始让我在已有的系统上完成一个静态的表单,后端通过iframe在页面中嵌入表单,本地调试非常顺利,最后一步上线测试时发现iframe嵌套存在跨域问题,查阅资料发现并没有一个相对安全解决办法。再次与后端沟通后,发现他想要的功能就是一个类似支付的的SDK,可以同工具函数一样,在需要的地方引入,生成一个动态的form表单,调用提交按钮发起支付请求,最后再将支付结果返回给后端即可。
实现思路
理解真正的需求之后,发现实现起来也很简单。
1.创建一个支付方法的类
2.实现动态生成表单函数createPaymentForm
3.实现收集表单数据函数collectFormData
4.实现支付回调函数handleFormSubmit
代码实现
class PaymentSDK {
constructor(config) {
this.config = config;
// this.createPaymentForm() 可以构造函数中初始化表单 也可以手动调用 更加灵活
// 初始化其他必要的设置或服务
}
// 创建一个支付表单的HTML
createPaymentForm() {
const formHTML = `
<form id="payment-form">
<div class="form-item">
<label for="card-number">Cardholder Name:</label>
<input type="text" id="card-name" name="card-name">
</div>
<! -- 其他参数 -->
</form>
`;
const bodyHtml = document.createElement('div')
bodyHtml.innerHTML = formHTML
if(this.config?.doc) { // 表单可以挂载在指定元素下,可以默认挂载在body
const doc = this.config.doc
doc.appendChild(bodyHtml)
} else {
document.body.appendChild(bodyHtml);
}
}
// 处理表单提交
handleFormSubmit() {
// 由于是示例,我们将仅打印表单数据
console.log('Form submitted with data:', this.collectFormData());
const {name, } = this.collectFormData()
// 真实场景中,你会调用支付API,并处理响应
return new Promise((resolve, reject) => {
// 这里可以直接使用fetch 不用引入jquery 现在的浏览器基本都支持fetch
fetch('payUrl',{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
// 支付需要的参数
})
}).then(res => {
resolve('sucess',res)
}).catch(err => {
reject('err',err)
})
})
}
// 收集表单数据
collectFormData() {
const name = document.getElementById('card-name').value
// ...其他参数
// 这里可以处理或转换formData以适应API的需求
return {
name,
// 其他参数
};
}
}
美化表单
上面的实现是一个简易的form表单,可以添加一些style样式来美化表单。
const styleTextt = `
.form-item {
display: flex;
align-items: center;
margin-bottom: 12px;
}
.form-item label {
display: inline-block;
height: 32px;
line-height: 32px;
margin-right: 12px;
width: 150px;
text-align: right;
color: #606266;
font-size: 14px
}
input {
flex: 1;
height: 32px;
background: none;
border-radius: 4px;
padding: 1px 11px;
border: 1px solid #dcdfe6;
box-shadow: 0 0 0 1px var(#dcdfe6, #dcdfe6) inset;
}
input:hover, input:focus {
border-color: #429a9a;
}
input:focus-visible {
outline: none;
}
`
class PaymentSDK {
constructor(config) {
this.config = config;
// this.createPaymentForm() 可以构造函数中初始化表单 也可以手动调用 更加灵活
// 初始化其他必要的设置或服务
}
// 创建一个支付表单的HTML
createPaymentForm() {
const formHTML = `表单HTML`;
let style = document.createElement('style')
style.type = 'text/css'
style.innerHTML = styleTextt
document.head.appendChild(style);
const bodyHtml = document.createElement('div')
bodyHtml.innerHTML = formHTML
if(this.config?.doc) { // 表单可以挂载在指定元素下,可以默认挂载在body
const doc = this.config.doc
doc.appendChild(bodyHtml)
} else {
document.body.appendChild(bodyHtml);
}
}
// 处理表单提交
handleFormSubmit() {
// 由于是示例,我们将仅打印表单数据
console.log('Form submitted with data:', this.collectFormData());
const {name, } = this.collectFormData()
// 真实场景中,你会调用支付API,并处理响应
}
// 收集表单数据
collectFormData() {
const name = document.getElementById('card-name').value
// ...其他参数
// 这里可以处理或转换formData以适应API的需求
return {
name,
// 其他参数
};
}
}
使用示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Payment SDK Example</title>
<script src="payment-sdk.js.js"></script>
<!-- 假设你的SDK脚本保存为payment-sdk.js -->
<style>
#form {
width: 500px;
}
</style>
</head>
<body>
<div id="form"></div>
<script>
const form = document.getElementById('form')
const sdkConfig = {
// 这里填入你的支付服务配置,如API密钥等
doc:form
};
const paymentSDK = new PaymentSDK(sdkConfig);
paymentSDK.createPaymentForm()
paymentSDK.handleFormSubmit().then(res => {
console.log(123, res)
});
</script>
</body>
</html>
这样一个简易的支付SDK就完成了,可以将js放在项目文件中,也可以传到服务器。