点击Add to cart加购时避免页面刷新的实现方法
问题根源
原生表单设置了action="/cart/add"和method="post",点击提交按钮时会触发浏览器默认的同步表单提交行为,必然导致页面刷新跳转。之前jQuery方案失效基本都是这几个原因:没有正确拦截默认提交事件、事件绑定时机不对(比如DOM还没加载就绑定元素)、表单参数缺失(最常见的是漏传商品变体ID字段)、请求接口地址错误。
实现无刷新加购的完整方案
不需要额外依赖,优先用原生JS实现,兼容性覆盖所有主流浏览器,直接把代码放到页面底部或者主题的JS文件里即可。
第一步:补全表单必填字段
你当前的表单缺少加购接口必须的商品变体ID字段,先在form标签内加一个隐藏input,把value替换成对应商品的实际变体ID:
<input type="hidden" name="id" value="替换为你的商品变体ID">
补全后的完整表单结构参考:
<div class="Product_Card_Button"> <form method="post" action="/cart/add" class="add-to-cart-form"> <!-- 补加的隐藏商品ID字段 --> <input type="hidden" name="id" value="替换为你的商品变体ID"> <quantity-input class="quantity" style="width: 120px; min-height: 25.4px; display: inline-flex;"> <button class="quantity__button no-js-hidden" name="minus" type="button"> - </button> <input class="quantity__input" type="number" name="quantity" id="quantity" min="1" value="1" style="text-align: center;"> <button class="quantity__button no-js-hidden" name="plus" type="button">+</button> </quantity-input> <br> <input type="submit" value="Add to cart" class="Add_To_Cart_Button" /> </form> <!-- 可选:加购成功/失败提示节点 --> <div class="cart-tip" style="font-size: 12px; margin-top: -30px; margin-bottom: 30px; display: none;"></div> </div>
原有CSS不需要改动。
第二步:添加AJAX提交逻辑
核心逻辑是拦截表单的submit事件,阻止默认跳转后用异步请求提交数据:
// 等DOM加载完成再绑定事件 document.addEventListener('DOMContentLoaded', function() { // 给所有加购表单绑定提交事件,支持动态渲染的商品卡片 document.addEventListener('submit', function(e) { const form = e.target.closest('.add-to-cart-form'); if (!form) return; // 核心:阻止默认表单提交跳转行为 e.preventDefault(); const tipNode = form.closest('.Product_Card_Button').querySelector('.cart-tip'); const submitBtn = form.querySelector('.Add_To_Cart_Button'); // 提交时禁用按钮防止重复提交 submitBtn.disabled = true; submitBtn.value = '加购中...'; // 直接收集表单数据 const formData = new FormData(form); // 发送AJAX加购请求 fetch('/cart/add.js', { // Shopify类电商系统AJAX加购接口固定为/cart/add.js,不要用/cart/add method: 'POST', body: formData }) .then(res => { if (!res.ok) throw new Error('加购失败,请重试'); return res.json(); }) .then(data => { // 加购成功逻辑 tipNode.textContent = `已成功加入购物车,当前购物车共${data.item_count}件商品`; tipNode.style.color = 'green'; tipNode.style.display = 'block'; // 可在此处扩展购物车角标更新、打开购物车抽屉等自定义逻辑 setTimeout(() => { tipNode.style.display = 'none'; }, 2000); }) .catch(err => { // 加购失败逻辑 tipNode.textContent = err.message; tipNode.style.color = 'red'; tipNode.style.display = 'block'; }) .finally(() => { // 恢复按钮状态 submitBtn.disabled = false; submitBtn.value = 'Add to cart'; }); }); // 附带数量加减逻辑,之前未实现可直接复用 document.addEventListener('click', function(e) { const minusBtn = e.target.closest('.quantity__button[name="minus"]'); const plusBtn = e.target.closest('.quantity__button[name="plus"]'); const quantityInput = e.target.closest('.quantity')?.querySelector('.quantity__input'); if (!quantityInput) return; let currentVal = parseInt(quantityInput.value); if (minusBtn && currentVal > 1) { quantityInput.value = currentVal - 1; } if (plusBtn) { quantityInput.value = currentVal + 1; } }); });
常见踩坑说明
- 不要把
e.preventDefault()写在异步请求回调里,必须在事件触发的第一时间调用,否则还是会触发默认跳转 - 不要用
/cart/add作为AJAX请求地址,这个地址是同步跳转的页面接口,返回HTML而非JSON,会导致请求解析失败 - 事件绑定尽量用事件委托(上述代码采用的就是document级事件委托),避免商品卡片动态渲染(分页、筛选后加载)导致事件失效
- 表单必须传商品变体ID的
id参数,否则加购接口会直接返回400错误
如果坚持要用jQuery实现,参考以下核心代码,注意规避上述提到的绑定时机、接口地址、默认事件拦截问题:
$(function() { $(document).on('submit', '.add-to-cart-form', function(e) { e.preventDefault(); // 必须在事件回调第一行调用 const $form = $(this); const $btn = $form.find('.Add_To_Cart_Button'); $btn.prop('disabled', true).val('加购中...'); $.ajax({ url: '/cart/add.js', method: 'POST', data: $form.serialize(), dataType: 'json', success: function(res) { alert('加购成功'); // 自定义成功逻辑 }, error: function() { alert('加购失败,请重试'); }, complete: function() { $btn.prop('disabled', false).val('Add to cart'); } }) }) })
内容的提问来源于stack exchange,提问作者fiddle
相关产品推荐
相关产品推荐

