开发教程
不用买 App,自己给 Shopify 购物车加满减进度条
很多 Shopify 独立站为了加一个「满减进度条」,每个月多花 $10–30 订阅 App。
其实完全不用。Shopify 原生提供 Cart API,只需要三步——10 行 HTML、一段 CSS、20 行 JS——就能自己实现一个带实时更新、三种颜色状态的满减提示 Banner,App 费用归零,维护成本也几乎为零。
行业数据显示,这类满减提示平均能将 AOV(客单价)提升 15–18%。逻辑很简单:用户看到「再加 $7 就免运费」,会主动多加一件商品凑单。
效果预览:三种状态
这个组件根据购物车金额与免运费门槛的距离,自动显示三种视觉状态:
STATE 1 · 金额偏低(< 40% 进度) 🔴 红色背景 + 红色进度条 "$30 to go — You're just getting started!"
STATE 2 · 快到门槛(40–99% 进度) 🟡 橙色背景 + 橙色进度条 "$7 away — Almost there!"
STATE 3 · 已解锁(100% 进度) 🟢 绿色背景 + 绿色进度条 "🎉 You've unlocked FREE Shipping!"
状态切换完全自动,用户每次加购后无需刷新页面,进度条和文案实时更新。
实现原理:Shopify Cart API
核心依赖是 Shopify 内置的 /cart.js 接口——这是一个不需要任何认证的原生端点,返回当前购物车的完整数据:
GET /cart.js
{
"total_price": 4300, // 单位是"分"→ $43.00
"item_count": 1, // 商品件数
"currency": "USD", // 店铺货币
"items": […] // 商品详情数组
}
整个逻辑只需要三步:
页面加载 → fetch /cart.js → 拿到 total_price
↓
计算进度百分比 + 差值 → 更新文案 + 进度条宽度 + 切换状态 class
↓
监听 cart:updated 事件 → 用户加购后自动重算,无需刷页面
Shopify Dawn 及主流 2.0 主题在 AJAX 加购后都会原生派发 cart:updated 事件,直接监听即可,不需要任何额外配置。
Step 1 · HTML(5 分钟)
在 sections/cart-template.liquid 顶部插入 Banner 的 HTML 骨架:
{%- comment -%} Free Shipping Bar {%- endcomment -%}
<div id="fs-bar-wrap">
<div class="fs-bar">
<span class="fs-icon">🚚</span>
<span id="fs-msg"></span>
</div>
<div class="fs-track">
<div id="fs-fill"></div>
</div>
</div>
三个关键节点,各有分工:
#fs-bar-wrap 是整个 Banner 的容器,JS 通过切换它的 class(state-low / state-mid / state-done)来驱动颜色变化,用 ID 直接获取,无需遍历 DOM。
#fs-msg 是文案占位符,内容由 JS 动态写入——金额不够时显示「Add $7.00 more for FREE Shipping!」,已解锁时显示庆祝文案。
#fs-fill 是进度条的填充块,JS 动态设置 style.width = progress%,CSS 的 transition 会让它平滑地动起来,不需要任何动画库。
Step 2 · CSS(5 分钟)
用 CSS 变量定义三种状态的颜色,JS 只需要切换一个 class,颜色、背景、过渡动画全部跟着变:
#fs-bar-wrap {
background: var(--banner-bg, #FEF3C7);
border-radius: 10px;
padding: 10px 14px;
margin-bottom: 12px;
}
.fs-bar {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
#fs-fill {
height: 6px;
border-radius: 3px;
background: var(--bar-color, #F59E0B);
transition: width 0.5s ease, background 0.4s ease;
}
.fs-track {
height: 6px;
background: rgba(0, 0, 0, 0.08);
border-radius: 3px;
overflow: hidden;
}
/* JS 切换这三个 class,颜色全部跟着变 */
.state-low { --banner-bg: #FEE2E2; --bar-color: #EF4444; }
.state-mid { --banner-bg: #FEF3C7; --bar-color: #F59E0B; }
.state-done { --banner-bg: #DCFCE7; --bar-color: #22C55E; }
CSS 变量 + class 切换的优势:JS 代码里不需要写任何颜色值,只需要 wrap.className = 'state-done',所有视觉变化(背景色、进度条颜色、transition 过渡动画)全部自动生效,后期改颜色也只需要改 CSS 这一处。
Step 3 · JavaScript(10 分钟)
完整逻辑 20 行,从 fetch 到监听事件全部搞定:
const THRESHOLD = 50; // 免运费门槛,单位美元,按需修改
async function updateBar() {
const cart = await fetch('/cart.js').then(r => r.json());
const total = cart.total_price / 100; // ① 分 → 元
const remaining = Math.max(THRESHOLD - total, 0);
const pct = Math.min(total / THRESHOLD * 100, 100); // ② clamp 到 100
const wrap = document.getElementById('fs-bar-wrap');
document.getElementById('fs-fill').style.width = pct + '%';
if (remaining === 0) {
wrap.className = 'state-done';
document.getElementById('fs-msg').textContent =
"🎉 You've unlocked FREE Shipping!";
} else {
wrap.className = pct < 40 ? 'state-low' : 'state-mid';
document.getElementById('fs-msg').textContent =
`Add $${remaining.toFixed(2)} more for FREE Shipping!`;
}
}
updateBar(); // 页面加载时立即执行一次
document.addEventListener('cart:updated', updateBar); // ③ 加购后自动更新
三个需要特别注意的细节:
① total_price 单位是「分」:Shopify Cart API 里所有金额都以分为单位,$43.00 在接口里是 4300。拿到数据后第一步必须除以 100,否则进度条永远是满格。
② 用 Math.min 把百分比夹到 100:当购物车总价超过免运费门槛时,total / THRESHOLD * 100 会大于 100。不做限制的话进度条会溢出容器,出现视觉 bug。Math.min(..., 100) 一行搞定。
③ cart:updated 事件是 Shopify 原生的:Dawn 和主流 2.0 主题在 AJAX 加购(不刷页面的加购)后,会在 document 上自动派发这个事件。监听它,每次用户加购时 updateBar 就自动重跑一次,进度条和文案实时更新,无需手动触发,也不需要轮询。
将 JS 文件引入主题
把上面的 JS 保存为 assets/free-shipping-bar.js,然后在 cart-template.liquid 底部引入:
<script src="{{ 'free-shipping-bar.js' | asset_url }}" defer></script>
defer 属性确保脚本在 DOM 渲染完毕后再执行,避免找不到 #fs-bar-wrap 等元素的问题。
扩展:多个门槛、多货币
如果想支持多货币,用 Liquid 把店铺货币注入到 HTML 里,JS 读取后动态显示货币符号:
<div id="fs-bar-wrap" data-currency="{{ cart.currency }}">
...
</div>
const currency = document.getElementById('fs-bar-wrap').dataset.currency;
// 然后用 Intl.NumberFormat 格式化金额
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency', currency: currency
}).format(remaining);
如果想设置多个阶梯门槛(比如满 $50 免运费、满 $100 送礼品),把 THRESHOLD 改成数组,在 updateBar 里找到当前处于哪个阶梯区间,切换对应文案即可。
总结
| 步骤 | 内容 | 时间 |
|---|---|---|
| Step 1 · HTML | 在 cart-template.liquid 加入 Banner 容器、文案占位、进度条 DOM | 5 分钟 |
| Step 2 · CSS | CSS 变量控制三种状态颜色,transition 平滑动画 | 5 分钟 |
| Step 3 · JS | fetch /cart.js 算差值,监听 cart:updated 实时更新 | 10 分钟 |
| 合计 | 三文件,20 分钟,$0 App 费用 | 20 分钟 |
整个方案不依赖任何第三方 App 和外部 CDN,代码完全在你的主题里,可以随时修改,没有额外的月费,也没有 App 加载带来的性能损耗。
💡 上线后用 Shopify Analytics 对比安装前后一周的「平均订单金额」(AOV)变化,就能看到这个小组件的实际效果。根据你的免运费门槛与店铺客单价的差距,效果差异会比较明显——门槛设在客单价的 120%–150% 区间时,凑单效果通常最好。