如何在表单中使用canvas实现用户绘图保存并关联存储至数据库
问题排查与修复方案
现有实现的核心问题
- 表单嵌套违规:你在主表单
formWithElectroSignature内部嵌套了隐藏表单signatureform,HTML规范禁止表单嵌套,会导致提交时数据丢失、提交目标错误 - 提交逻辑错误:JS点击保存时提交的是内层无业务字段的隐藏表单,而非包含人员、日期等字段的主表单,业务数据和签名完全没有一起传递到后端
- 无用代码干扰:
window.location.assign=img、img.download = 'image.png'属于无效代码,前者会尝试跳转页面打断提交,后者对base64字符串设置属性毫无作用 - 画布清空逻辑错误:重置按钮调用
clearRect时用了窗口宽高作为参数,无法完全清空自定义尺寸的画布 - 前端资源引入错误:jQuery的script标签没有闭合,会导致后续JS加载执行失败
修复步骤
1. 修正Twig表单结构
删掉嵌套的隐藏表单,将签名隐藏字段移到主表单内,闭合script标签:
{% extends '@!EasyAdmin/layout.html.twig' %} {% block content %} {% for flashError in app.flashes('verify_email_error') %} <div class="alert alert-danger" role="alert">{{ flashError }}</div> {% endfor %} {{ form_start(formWithElectroSignature) }} <!-- 签名隐藏字段移到主表单内 --> <input type="hidden" id="signature" name="signature"> <div class="form-control js-user-autocomplete" autocomplete="on"> {{ form_label(formWithElectroSignature.personnel) }}<br> {{ form_widget(formWithElectroSignature.personnel) }} </div> <div class="form-control"> <i class="fa fa-calendar"></i> {{ form_label(formWithElectroSignature.dateDebut) }}<br> {{ form_widget(formWithElectroSignature.dateDebut) }} </div> <div class="form-control"> {{ form_label(formWithElectroSignature.cle) }}<br> {{ form_widget(formWithElectroSignature.cle) }} </div> <div class="form-control"> {{ form_label(formWithElectroSignature.document) }}<br> {{ form_widget(formWithElectroSignature.document) }} </div> <div class="form-control"> <div class="col-md-8 col-md-offset-2"> <br> <h2>Signature Electronique !</h2> <hr> <div id="canvasDiv"></div> <br> <button type="button" class="btn btn-danger" id="reset-btn">Clear</button> <button type="button" class="btn btn-success" id="btn-save">Save</button> </div> </div> {{ form_end(formWithElectroSignature) }} {% endblock %} {% block body_javascript %} <!-- 闭合script标签 --> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.min.js"></script> <script src="/signatures/Signature.js"></script> {% endblock %}
2. 修正JS逻辑
修改保存和清空逻辑,移除无效代码:
// 修改reset-btn点击事件 $("#reset-btn").click(function() { // 用canvas自身宽高清空 context.clearRect(0, 0, canvas.width, canvas.height); clickX = []; clickY = []; clickDrag = []; }); // 修改btn-save点击事件 $(document).on('click', '#btn-save', function() { var mycanvas = document.getElementById('canvas'); // 指定png格式保证兼容性 var imgBase64 = mycanvas.toDataURL("image/png"); // 把base64赋值给主表单的隐藏字段 $("#signature").val(imgBase64); // 直接提交主表单 $("form[name=formWithElectroSignature]").submit(); });
3. 后端处理逻辑(Symfony框架示例)
后端接收base64字符串,转成png文件存储到服务器,再将文件名关联存入数据库:
// 控制器中接收提交数据 public function submitSignature(Request $request) { $signatureBase64 = $request->request->get('signature'); // 去掉base64头 $base64Body = preg_replace('#^data:image/\w+;base64,#i', '', $signatureBase64); $fileContent = base64_decode($base64Body); // 生成唯一文件名 $fileName = uniqid().'_signature.png'; // 存储到指定目录 file_put_contents($this->getParameter('signature_directory').'/'.$fileName, $fileContent); // 后续业务逻辑:将文件名和其他表单字段一起存入数据库 $entity = new SignatureEntity(); $entity->setPersonnel($request->request->get('personnel')); $entity->setSignaturePath($fileName); // 其他字段赋值... $em = $this->getDoctrine()->getManager(); $em->persist($entity); $em->flush(); return $this->redirectToRoute('success_page'); }
实现方向说明
你原本的实现思路是正确的,通过canvas收集手写内容、转base64提交是业内通用的手写签名实现方案,仅需修正上述细节问题即可正常运行。
内容的提问来源于stack exchange,提问作者Cephalopodius
相关产品推荐
相关产品推荐

