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

Laravel+jQuery Ajax点赞功能异常:类名错误绑定问题解决

问题描述

在Laravel框架中使用jQuery Ajax实现点赞/取消点赞按钮时出现异常:点击property-id为6的点赞按钮,'liked'类被错误添加到property-id为5的按钮上;点击property-id为6的取消点赞按钮,无法正确移除该按钮的'liked'类。

原代码

Blade模板代码

<div class="property-listing">
    <div class="row g-2">
        @foreach ($properties as $property)
        <div class="col-lg-6 col-12 mb-3">
            <div class="card property-item shadow-sm p-2 pb-0 h-100">
                <div class="position-absolute top-0 start-0 z-index-1 m-4">
                    <div class="badge text-bg-light">
                        From ${{ $property->monthly_price }}/month
                    </div>
                </div>
                <div class="position-absolute top-0 end-0 z-index-1 m-4">
                    <button class="btn favorite-btn rounded-circle {{ $property->isLiked() ? 'liked' : '' }}" aria-label="like" type="button" data-property-id="{{ $property->id }}" id="like-btn">
                    <i class="fa-solid fa-heart fs-3"></i>
                    </button>
                </div>
                <div class="rounded-2 overflow-hidden">
                    <div class="property-galleries mb-0">
                        @foreach ($property->getMedia('property images') as $media)
                        <div><img data-src="{{ $media->getFullUrl() }}" class="lazy" alt="{{ $property->title }}"></div>
                        @endforeach
                    </div>
                </div>
                <div class="position-relative">
                    <div class="card-body px-1 pb-0">
                        <h2 class="card-title fw-bold">
                            <a href="{{ route('front.property-detail', $property->slug) }}">
                            <span class="fw-bold">
                            {{ $property->title }}
                            </span>
                            </a>
                        </h2>
                        <div class="meta">
                            <ul>
                                <li>
                                    {{ $property->district->name }}
                                </li>
                                <li>
                                    {{ $property->specification }}
                                </li>
                                <li>
                                    {{ $property->size }} Sq Ft
                                </li>
                            </ul>
                        </div>
                    </div>
                    <div class="card-footer border-0 bg-transparent px-1 pt-2 d-flex mx-auto">
                        <div class="d-flex flex-column">
                            <span class="text-muted small">
                            Starting at
                            </span>
                            <span class="fw-normal small">
                            ${{ $property->nightly_price }}/night
                            </span>
                        </div>
                        <a href="{{ route('front.property-detail',$property->slug) }}" class="btn btn-sm check-btn mb-0 mt-3 ms-auto stretched-link">Check Availability</a>
                    </div>
                </div>
            </div>
        </div>
        @endforeach
    </div>
</div>

Ajax代码

$(document).on('click', '#like-btn', function(e) {
    e.preventDefault();
    var id = $(this).data('property-id');
    var url = "{{ route('like', ':id') }}";
    url = url.replace(':id', id);
    $.ajax({
        url: url,
        method: 'POST',
        data: {
            _token: '{{ csrf_token() }}'
        },
        success: function(response) {
            if (response.message == 'liked') {
                //add class liked to #like-btn button with data-id = id
                $('#like-btn').addClass('liked');
            }

            if (response.message == 'unliked') {
                //remove class liked
                $('#like-btn').removeClass('liked');
            }
        }
    });
});

Controller代码

public function like(Property $property)
{
    try {
        if ($property->isLiked()) {
            $property->removeLike();
            return response()->json(['message' => 'unliked'], 200);
        }

        $property->likes()->create([
            'user_id' => auth()->id(),
            'ip' => request()->ip(),
            'user_agent' => request()->userAgent(),
        ]);
        
        return response()->json(['message' => 'liked'], 200);

    } catch (\Exception $e) {
        return response()->json(['message' => $e->getMessage()], 500);
    }
}
解决方案

核心问题分析

HTML规范中ID属性必须唯一,但Blade循环里所有点赞按钮都使用了id="like-btn"。jQuery选择器$('#like-btn')只会匹配页面中第一个拥有该ID的元素,导致操作总是错误作用到第一个按钮上。

修复步骤

  1. 修改Blade模板:将重复ID改为类
    将按钮的id="like-btn"替换为class="like-btn",保留data-property-id用于标识房源ID:

    <button class="btn favorite-btn rounded-circle like-btn {{ $property->isLiked() ? 'liked' : '' }}" aria-label="like" type="button" data-property-id="{{ $property->id }}">
        <i class="fa-solid fa-heart fs-3"></i>
    </button>
    
  2. 修改Ajax代码:绑定类选择器,操作当前点击的按钮

    • 事件监听改为.like-btn类
    • 保存当前点击的按钮对象,在success回调中直接操作该对象,避免全局选择错误:
    $(document).on('click', '.like-btn', function(e) {
        e.preventDefault();
        var $currentBtn = $(this); // 保存当前点击的按钮
        var propertyId = $currentBtn.data('property-id');
        var url = "{{ route('like', ':id') }}".replace(':id', propertyId);
        
        $.ajax({
            url: url,
            method: 'POST',
            data: {
                _token: '{{ csrf_token() }}'
            },
            success: function(response) {
                if (response.message === 'liked') {
                    $currentBtn.addClass('liked');
                } else if (response.message === 'unliked') {
                    $currentBtn.removeClass('liked');
                }
            }
        });
    });
    

可选优化:防止重复点击

在Ajax请求过程中禁用按钮,避免用户重复点击导致多次请求:

$.ajax({
    url: url,
    method: 'POST',
    data: {
        _token: '{{ csrf_token() }}'
    },
    beforeSend: function() {
        $currentBtn.prop('disabled', true); // 请求前禁用按钮
    },
    complete: function() {
        $currentBtn.prop('disabled', false); // 请求完成后恢复可用
    },
    success: function(response) {
        // 原逻辑
    }
});

内容的提问来源于stack exchange,提问作者anon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 04:02:06