首页 > 解决方案 > 来自 javascript (async) 的 Livewire 加载状态

问题描述

我有一个向 Stripe 发送请求的表单,以便我的用户添加付款方式:

<form id="card-form">
   <label>Card details</label>
   <div id="card-element"></div>

   <button wire:target="addPaymentMethod" wire:loading.class="hidden" class="button round" id="card-button">Add payment card</button>
   <!-- Loading spinner -->
   <svg wire:target="addPaymentMethod" wire:loading class="inline-block animate-spin h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
      <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
      <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
   </svg>
</form>

(精简的)JavaScript 如下所示:

const stripe = Stripe('stripe-public-key');
const elements = stripe.elements();

const form = document.getElementById('card-form')
const cardButton = document.getElementById('card-button');
const cardElement = elements.create('card');
cardElement.mount('#card-element');
                
form.addEventListener('submit', async (e) => {
    e.preventDefault();
    cardButton.disabled = true;

    const {
        setupIntent,
        error
    } = await stripe.confirmCardSetup(
        clientSecret, {
            payment_method: {
                card: cardNumber,
                billing_details: {
                    name: 'Oliver'
                }
            }
        }
    );

    if (error) {
        // Display error.message to the user...
        cardButton.disabled = false
        console.log(error.message)
    } else {
        // The card has been verified successfully...
        @this.addPaymentMethod(setupIntent.payment_method)
    }

});

如果上面的 async 方法响应成功,会触发 Livewire 组件下面的方法:

public function addPaymentMethod($paymentMethod)
{
   //Create the payment method in Stripe...
   auth()->user()->addPaymentMethod($paymentMethod);

   //Other validation etc...

}

所有这些的输出都在下面的 gif 中捕获。正如您在此处看到的,用户输入信用卡详细信息并单击“添加支付卡”并被重定向到另一个页面。

问题是,加载状态会开始一段时间,但在实际请求/重定向完成之前就消失了。

在对 Stripe 的实际请求完成之前,如何显示加载微调器?

在此处输入图像描述

标签: laravellaravel-livewirealpine.js

解决方案


这取决于addPaymentMethod您的加载状态为何提前隐藏的其他情况。为了让您更好地控制该时间,我可能会将您的加载状态的显示/隐藏推迟到 javascript 层。这里有几种方法可以解决它:

1. 使用承诺

Livewire 的一个很好的特性是,当通过 javascript 调用组件方法时,它们会在完成后返回一个 Promise。因此,如果您需要隐藏加载状态,可以在此处执行此操作:

// The card has been verified successfully...
@this.addPaymentMethod(setupIntent.payment_method)
    .then(result => {
        // Hide loading state
    })

2. 发出事件

另一种方法是从您可以在组件前端收听的事件中发出一个事件。addPaymentMethod

public function addPaymentMethod($paymentMethod)
{
    // Your add payment code runs...

    // Emit an event to the frontend (with optional data)
    $this->dispatchBrowserEvent('add-payment-method-complete', ['someData' => $value]);
}

您可以使用AlpineJs在前端非常简单地监听此事件。这是一个使用 Alpine 管理加载状态的简短表单示例:

<form
// Init AlpineJs with the x-data attribute
x-data="{
    isLoading: false
}"
// Listen the forms submit event and change
// our "isLoading" flag to true
x-on:submit="isLoading = true">
    // Listen for the event emitted from Livewire to the window
    // and reset the isLoading flag to false
    <svg x-on:add-payment-method-complete.window="isLoading = false" />
</form>

推荐阅读