返回博客列表

开发教程

不用买 App,自己给 Shopify 购物车加满减进度条

2026-06-27

很多 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 · HTMLcart-template.liquid 加入 Banner 容器、文案占位、进度条 DOM5 分钟
Step 2 · CSSCSS 变量控制三种状态颜色,transition 平滑动画5 分钟
Step 3 · JSfetch /cart.js 算差值,监听 cart:updated 实时更新10 分钟
合计三文件,20 分钟,$0 App 费用20 分钟

整个方案不依赖任何第三方 App 和外部 CDN,代码完全在你的主题里,可以随时修改,没有额外的月费,也没有 App 加载带来的性能损耗。

💡 上线后用 Shopify Analytics 对比安装前后一周的「平均订单金额」(AOV)变化,就能看到这个小组件的实际效果。根据你的免运费门槛与店铺客单价的差距,效果差异会比较明显——门槛设在客单价的 120%–150% 区间时,凑单效果通常最好。