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的元素,导致操作总是错误作用到第一个按钮上。
修复步骤
修改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>修改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
相关产品推荐
相关产品推荐

