Livewire Wizard多步骤表单中JS签名板切换步骤后失效求助
LiveWire Wizard切换步骤后签名板无法绘制的解决办法
问题背景
用vildanbina/livewire-wizard搭建多步骤KYC录入系统,其他功能正常,但最后一步的签名板有问题:切换到签名步骤后无法绘制签名,必须刷新页面才能正常使用。试过livewire:navigated事件,但组件用的是wire:click而非wire:navigate,所以没用。
问题原因
LiveWire切换步骤时会动态更新DOM,而原签名板的JS代码只在页面首次加载时执行一次。当签名步骤的DOM被LiveWire动态渲染出来时,原初始化逻辑已经执行过,没有重新绑定事件和创建SignaturePad实例,导致无法绘制。
解决步骤
1. 封装签名板初始化逻辑
把原JS代码改成可复用的函数,方便重复调用,同时清理旧实例避免内存泄漏。
2. 利用LiveWire事件触发初始化
借助livewire-wizard的onStepIn步骤钩子,或者在主Wizard组件的setStep方法中判断步骤,触发自定义事件来执行初始化。
修改后的代码示例
1. 签名步骤组件添加钩子(可选)
如果签名是独立的步骤组件,添加onStepIn方法触发初始化事件:
public function onStepIn() { $this->dispatch('initSignaturePad'); }
2. 主Wizard组件的setStep方法(可选)
如果不想在步骤组件加钩子,可在主Wizard的setStep中判断当前步骤并触发事件:
public function setStep($step): void { $this->callHook('beforeSetStep', $this->activeStep, $step); if ($this->hasPrevStep($step)) { $this->stepsValidation($this->prevStep($step)); } $this->getCurrentStep()->callHook('onStepOut'); $this->activeStep = $step; $this->getCurrentStep()->callHook('onStepIn'); // 假设签名步骤的order是3,根据实际情况修改 if ($step === 3) { $this->dispatch('initSignaturePad'); } $this->callHook('afterSetStep', $this->activeStep, $step); }
3. 签名板视图代码(无需大改)
<div class="col-sm-6"> <h3>Click to sign</h3> <input id="img-data" type="text" wire:model="state.signature" wire:change="updateSignature"> <div id="signature-pad" class="m-signature-pad"> <div class="m-signature-pad--body"> <canvas style="border: 2px dashed #ccc"></canvas> </div> <div class="m-signature-pad--footer"> <button type="button" data-action="clear" id="clear-btn" class="text-white bg-gray-800 hover:bg-gray-900 focus:outline-none focus:ring-4 focus:ring-gray-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-gray-800 dark:hover:bg-gray-700 dark:focus:ring-gray-700 dark:border-gray-700">مسح</button> <button type="button" data-action="save" id="save-btn" class="focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800">حفظ التوقيع</button> </div> </div> </div>
4. 修改后的JavaScript代码
// 封装签名板初始化函数 function initSignaturePad() { // 清理旧实例,避免重复绑定 if (window.signaturePad) { window.signaturePad.off(); window.signaturePad = null; } var wrapper = document.getElementById("signature-pad"); if (!wrapper) return; // DOM不存在时直接返回 var clearButton = wrapper.querySelector("[data-action=clear]"), saveButton = wrapper.querySelector("[data-action=save]"), canvas = wrapper.querySelector("canvas"); // 适配设备像素比,让签名更清晰 function resizeCanvas() { var ratio = window.devicePixelRatio || 1; canvas.width = canvas.offsetWidth * ratio; canvas.height = canvas.offsetHeight * ratio; canvas.getContext("2d").scale(ratio, ratio); } resizeCanvas(); // 创建新的SignaturePad实例 window.signaturePad = new SignaturePad(canvas); // 绑定清除按钮事件 clearButton.addEventListener("click", function() { window.signaturePad.clear(); $("#save-btn").prop("disabled", false); $("#save-btn").attr("class", "focus:outline-none text-white bg-green-700 hover:bg-green-800 focus:ring-4 focus:ring-green-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800"); $("#img-data").val(''); }); // 绑定保存按钮事件 saveButton.addEventListener("click", function(event) { event.preventDefault(); if (window.signaturePad.isEmpty()) { alert("Please provide a signature first."); return; } var dataUrl = window.signaturePad.toDataURL(); var image_data = dataUrl.replace(/^data:image\/(png|jpg);base64,/, ""); $("#img-data").val(image_data); if ($("#img-data").val()) { $("#save-btn").prop("disabled", true); $("#save-btn").attr("class", "py-2.5 px-5 me-2 mb-2 text-sm font-medium text-gray-900 focus:outline-none bg-white rounded-lg border border-gray-200 hover:bg-gray-100 hover:text-blue-700 focus:z-10 focus:ring-4 focus:ring-gray-100 dark:focus:ring-gray-700 dark:bg-gray-800 dark:text-gray-400 dark:border-gray-600 dark:hover:text-white dark:hover:bg-gray-700"); } else { $("#save-btn").prop("disabled", false); } $.ajax({ url: '/save-signature', type: 'POST', data: { image_data: image_data }, }); }); } // 监听LiveWire自定义事件,触发初始化 document.addEventListener('livewire:initialized', () => { Livewire.on('initSignaturePad', initSignaturePad); }); // 页面加载时初始化一次 window.addEventListener('load', initSignaturePad);
内容的提问来源于stack exchange,提问作者CertifiedCoder
相关产品推荐
相关产品推荐

