Laravel中使用AJAX实现无刷新更新Session的问题求助
问题描述
正在开发购物车系统,需要实现点击Add按钮时为指定assignment创建Session并在页面展示,暂未实现增减数量、删除逻辑。目前无法做到不刷新页面就存储Session并更新页面内容,操作后页面会强制刷新,求解决方案。
现有代码
Controller代码
public function storeAssignmentSession($id, Request $request) { $assignmentId = $request->input('assignment_id'); $quantity = 1; // Default quantity is 1 $assignment = Assignment::find($assignmentId); if ($assignment) { $taskSession = session('session_' . $id, []); $existingKey = null; foreach ($taskSession as $key => $sessionData) { if ($sessionData['assignment_id'] === $assignment->id) { $existingKey = $key; break; } } if ($existingKey !== null) { $taskSession[$existingKey]['quantity'] += $quantity; } else { $taskSession[] = [ 'assignment_id' => $assignment->id, 'assignment_name' => $assignment->assignment_name, 'assignment_status' => $assignment->assignment_status, 'quantity' => $quantity, ]; } session(['session_' . $id => $taskSession]); } return redirect()->back(); }
Route代码
Route::post('/task/{id}/store-assignment-session', [Taskmanager::class, 'storeAssignmentSession'])->name('store_assignment_session');
Blade代码
<script> $(document).ready(function() { // Handle the "Add" button click $(".add-assignment").click(function(e) { e.preventDefault(); // Prevent the default form submission var assignmentId = $(this).data("assignment-id"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/store-assignment-session', data: { assignment_id: assignmentId }, success: function(response) { // Load the page to refresh the content location.reload(); // Log the session data in the console console.log(response); }, error: function(error) { alert('Failed to add assignment to session.'); } }); }); // Handle the "Subtract" button click $(".subtract-assignment").click(function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/subtracting-assignment-session/' + key, success: function(response) { // Load the page to refresh the content location.reload(); }, error: function(error) { alert('Failed to subtract assignment from session.'); } }); }); // Handle the "Add" button click $(".add-assignment").click(function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/adding-assignment-session/' + key, success: function(response) { // Load the page to refresh the content location.reload(); }, error: function(error) { alert('Failed to add assignment to session.'); } }); }); // Handle the "Delete" button click $(".delete-assignment").click(function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/delete-assignment-session/' + key, success: function(response) { // Load the page to refresh the content location.reload(); }, error: function(error) { alert('Failed to delete assignment from session.'); } }); }); }); </script>
解决方案
核心思路:后端返回JSON格式的购物车数据,前端通过AJAX接收后直接修改页面DOM,替代页面刷新;同时修复原有代码中的重复事件绑定、CSRF令牌缺失问题。
1. 修改Controller返回JSON数据
将跳转响应改为返回包含购物车数据的JSON,让前端直接拿到最新购物车状态:
public function storeAssignmentSession($id, Request $request) { $assignmentId = $request->input('assignment_id'); $quantity = 1; // Default quantity is 1 $assignment = Assignment::find($assignmentId); if ($assignment) { $taskSession = session('session_' . $id, []); $existingKey = null; foreach ($taskSession as $key => $sessionData) { if ($sessionData['assignment_id'] === $assignment->id) { $existingKey = $key; break; } } if ($existingKey !== null) { $taskSession[$existingKey]['quantity'] += $quantity; } else { $taskSession[] = [ 'assignment_id' => $assignment->id, 'assignment_name' => $assignment->assignment_name, 'assignment_status' => $assignment->assignment_status, 'quantity' => $quantity, ]; } session(['session_' . $id => $taskSession]); } // 返回JSON格式的操作结果和购物车数据 return response()->json([ 'success' => true, 'cart' => session('session_' . $id) ]); }
后续实现增减数量、删除的Controller方法时,也需返回相同格式的JSON数据。
2. 修复Blade中的AJAX逻辑
2.1 确保CSRF令牌验证
Laravel默认拦截无CSRF令牌的POST请求,在页面头部添加CSRF meta标签:
<meta name="csrf-token" content="{{ csrf_token() }}">
2.2 修改JS代码,移除页面刷新,动态更新DOM
修复重复的add-assignment事件绑定,添加DOM更新函数,移除location.reload():
$(document).ready(function() { // 全局配置AJAX携带CSRF令牌 $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); // 处理Add按钮点击(仅保留一个绑定) $(".add-assignment").click(function(e) { e.preventDefault(); var assignmentId = $(this).data("assignment-id"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/store-assignment-session', data: { assignment_id: assignmentId }, success: function(response) { if (response.success) { updateCartDisplay(response.cart); console.log('商品已添加到购物车'); } }, error: function(error) { alert('Failed to add assignment to session.'); } }); }); // 处理数量减少按钮点击 $(".subtract-assignment").click(function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/subtracting-assignment-session/' + key, success: function(response) { if (response.success) { updateCartDisplay(response.cart); } }, error: function(error) { alert('Failed to subtract assignment from session.'); } }); }); // 处理数量增加按钮点击(修改类名避免和添加按钮冲突) $(document).on('click', '.add-quantity-assignment', function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/adding-assignment-session/' + key, success: function(response) { if (response.success) { updateCartDisplay(response.cart); } }, error: function(error) { alert('Failed to add assignment quantity.'); } }); }); // 处理删除按钮点击 $(".delete-assignment").click(function() { var key = $(this).data("key"); var taskId = {{$task->id}}; $.ajax({ type: 'POST', url: '/task/' + taskId + '/delete-assignment-session/' + key, success: function(response) { if (response.success) { updateCartDisplay(response.cart); } }, error: function(error) { alert('Failed to delete assignment from session.'); } }); }); // 动态更新购物车展示的函数 function updateCartDisplay(cartData) { var cartContainer = $('#cart-container'); cartContainer.empty(); if (cartData.length === 0) { cartContainer.html('<p>购物车为空</p>'); return; } // 循环生成购物车项HTML cartData.forEach(function(item, index) { var cartItem = ` <div class="cart-item"> <h4>${item.assignment_name}</h4> <p>状态: ${item.assignment_status}</p> <p>数量: ${item.quantity}</p> <button class="subtract-assignment" data-key="${index}">-</button> <button class="add-quantity-assignment" data-key="${index}">+</button> <button class="delete-assignment" data-key="${index}">删除</button> </div> `; cartContainer.append(cartItem); }); } });
2.3 添加购物车展示容器
在Blade页面中添加用于展示购物车的容器,初始内容从Session读取:
<div id="cart-container"> @if(session('session_' . $task->id)) @foreach(session('session_' . $task->id) as $key => $item) <div class="cart-item"> <h4>{{ $item['assignment_name'] }}</h4> <p>状态: {{ $item['assignment_status'] }}</p> <p>数量: {{ $item['quantity'] }}</p> <button class="subtract-assignment" data-key="{{ $key }}">-</button> <button class="add-quantity-assignment" data-key="{{ $key }}">+</button> <button class="delete-assignment" data-key="{{ $key }}">删除</button> </div> @endforeach @else <p>购物车为空</p> @endif </div>
3. 示例:数量增加的Controller和Route
Controller方法
public function addAssignmentQuantity($id, $key) { $taskSession = session('session_' . $id, []); if (isset($taskSession[$key])) { $taskSession[$key]['quantity'] += 1; session(['session_' . $id => $taskSession]); } return response()->json([ 'success' => true, 'cart' => session('session_' . $id) ]); }
Route配置
Route::post('/task/{id}/adding-assignment-session/{key}', [Taskmanager::class, 'addAssignmentQuantity'])->name('add_assignment_quantity');
内容的提问来源于stack exchange,提问作者Amir Adamov
相关产品推荐
相关产品推荐

