You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:54:58