x-显示基于父元素 class in Alpine.js 的元素

x-show elements based on parent element class in Alpine.js

在我的 WooCommerce 主题中,我想在 WooCommerce 使用 AJAX 向元素动态添加“正在加载”class 时显示微调器图标。

我尝试使用 Alpine.js 的 $el 属性 来检索当前的 DOM 节点,但这不起作用。它也不是 'watching' 的 classList of .

如何使用 Alpine.js 完成此操作?

<button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="ajax_add_to_cart add_to_cart_button single_add_to_cart_button button alt flex justify-center" data-product_id="<?php echo get_the_ID(); ?>">

    <!-- Spinner Icon -->
    <svg x-show="$el.parentElement.classList.contains('loading')" class="animate-spin py-1 h-7 w-7 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
        ...
    </svg>

    <!-- Toevoegen aan winkelmand -->
    <span x-show="$el.parentElement.classList.contains('!loading')">
        <?php echo esc_html( $product->single_add_to_cart_text() ); ?>
    </span>
    
</button>

深入研究 WooCommerce source code 发现它使用 jQuery 事件系统,因此我们必须在 jQuery 和 Alpine.js 之间创建一个小事件总线。这两个事件分别是 AJAX 调用之前调用的 adding_to_cart 和 AJAX 调用成功后触发的 added_to_cart 事件(即产品已添加到购物车) .

让我们调用事件总线 catchWooEvents:

<script>
document.addEventListener('alpine:init', () => {
    Alpine.data('catchWooEvents', () => ({
        loading: false,

        init() {
            $(document.body).on('adding_to_cart', (event, button, data) => {
                this.loading = true
            })
            $(document.body).on('added_to_cart', (fragments, cart_hash, button) => {
                this.loading = false
            })
        }
    }))
})
</script>

我们有一个新变量 loading 在两个事件之间处于活动状态。您会看到我们在 init() 中使用了 jQuery 的 $.on() 函数来捕获 jQuery 事件,但随后我们操纵了一个 Alpine.js 变量。

修改按钮示例:

<div x-data="catchWooEvents">
    <button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="ajax_add_to_cart add_to_cart_button single_add_to_cart_button button alt flex justify-center" data-product_id="<?php echo get_the_ID(); ?>">

        <!-- Spinner Icon -->
        <svg x-show="loading" class="animate-spin py-1 h-7 w-7 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
            ...
        </svg>

        <!-- Toevoegen aan winkelmand -->
        <span x-show="!loading">
            <?php echo esc_html( $product->single_add_to_cart_text() ); ?>
        </span>
        
    </button>
</div>

我们有一个新的父 div 元素,我们在其中应用了 catchWooEvents 组件,因此多个子按钮可以共享加载状态。在 x-show 属性中,loading 变量现在是反应式的。

注意:catchWooEvents的定义必须放在jQuery脚本行之后。