@maofuxing/astro-site-plugin
v1.0.4
Published
贸福星建站专用。Complete commerce module for Astro sites including cart, checkout, payment, auth, and orders.
Readme
@maofuxing/astro-site-plugin
贸福星建站专用 · 官方平台:https://maofuxing.cn
MFX 独立站电商交易模块(购物车、结算支付、会员认证、订单管理),专为 Astro 静态输出(SSG)架构打造。
🌟 核心架构与特性
- 纯静态输出(SSG 优先):100% 契合 Astro
output: 'static',无 Node SSR 运行时依赖,适配任意 CDN/静态托管。 - 零框架外部依赖:剔除 React/Vue/Nanostores,基于原生 TypeScript + 原生 DOM API +
CustomEvent事件总线。 - 宿主 Header/Footer 100% 无缝复用(Page Shadowing + View Components):提供可插拔的纯 View 视图组件,宿主只需用自己的
<Layout>包裹组件即可拼装出拥有站点统一头部导航的物理页面。 - 灵活的多语言支持:既兼容 Astro 原生
i18n,又完美支持外贸站常见的物理多语言目录(如src/pages/zh/、src/pages/de/),组件自动根据 URL 首段识别语言环境并切词。 - 未登录强拦截:未登录用户加购或结算强制拦截并安全重定向至
/login?redirect=...,确保购物车数据与服务端账户强绑定。 - 租户隔离广播:内置
BroadcastChannel('mfx-commerce:' + tenantId)跨标签页实时同步,杜绝同域名或多个使用本包站点间干扰。 - 私有页面防抓取:所有交易与会员动态页面强制注入
<meta name="robots" content="noindex, nofollow" />,保护搜索引擎抓取配额。 - 双模式架构(Turnkey 兜底 / Composable 自由拼装):
- 开箱即用模式:零页面代码,Integration 自动注入所有路由。
- 组件拼装模式(推荐):使用宿主
<Layout>包裹 7 个核心<*View />组件,完全掌控页面排版与头部复用。 - Headless 纯 SDK 模式:调用
@maofuxing/astro-site-plugin/clientSDK 接口,用原生 JS 实现完全自由的 UI。
🚀 宿主安装与配置
1. 安装 npm 依赖
在宿主 Astro 项目中安装正式发布的 npm 包:
npm install @maofuxing/astro-site-plugin
# 或使用 pnpm / yarn
pnpm add @maofuxing/astro-site-plugin2. 配置 Integration
// astro.config.mjs
import { defineConfig } from 'astro/config';
import mfxCommerce, { mfxAuth } from '@maofuxing/astro-site-plugin';
const isDev = process.env.NODE_ENV !== 'production';
export default defineConfig({
output: 'static',
integrations: [
mfxCommerce({
// 💡 接口环境域名规范(由宿主项目控制):
// - 开发阶段 (dev): 调用 https://app.maofuxing.cn
// - 生产环境 (prod): 传入当前域名(空字符串 '',请求同源相对路径)
apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '',
tenantId: 'your-tenant-id',
paypalClientId: 'your-paypal-client-id',
cdnHost: 'https://cdn3.btitib.com', // 静态资源 CDN 根域名(短路径图片自动走此 CDN,缺省自动兜底 'https://cdn3.btitib.com')
defaultLocale: 'en',
locales: ['en', 'zh', 'de', 'ja'], // 支持的多语言列表
// 💡 功能模块按需开启(默认全开):
// - auth: 会员基础底座(登录、注册、验证码、账号中心),默认 true 且强制开启
// - cart: 购物车功能(若设为 false,不注入 /cart 路由),默认 true
// - checkout: 结算与支付功能(强依赖 cart,设为 false 则不注入 /checkout 及 /payment/result),默认 true
// - orders: 历史订单系统(强依赖 auth,设为 false 则不注入 /orders),默认 true
features: {
auth: true,
cart: true,
checkout: true,
orders: true
},
// 💡 页面路由注入控制:
// - true (默认): 自动注入所有启用的预置页面(开箱即用模式)
// - false: 不注入任何预置页面(完全由宿主自建物理页面拼装,推荐!消除路由冲突告警并 100% 复用宿主 Header)
// - 对象形式: 按需精细控制,例如 { cart: false } 仅禁用购物车页面注入
injectRoutes: false,
// 可选自定义基础路由路径
routes: {
cart: '/cart',
checkout: '/checkout',
orders: '/orders',
login: '/login',
register: '/register',
account: '/account',
paymentResult: '/payment/result'
},
// 可选自定义词条覆盖(支持 en, zh, ja, de 等所有语言词条的深度合并)
translations: {
en: {
cart: { title: 'Shopping Bag' }
},
zh: {
cart: { title: '我的购物车' }
}
}
})
]
});💡 仅需会员系统?使用
mfxAuth快捷轻量导出: 如果您的站点仅需要会员体系(登录、注册、邮箱验证码、账号中心),完全不需要购物车、结算与 PayPal:import { mfxAuth } from '@maofuxing/astro-site-plugin'; export default defineConfig({ integrations: [ mfxAuth({ apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '', tenantId: 'your-tenant-id' }) ] });
🤖 大模型 / AI Coding Assistant 对接与页面拼装指南
写给接手本项目的大模型(Claude / Cursor / Antigravity / Copilot)及开发者: 当你受命为一个现有的 Astro 独立站项目接入本电商插件时,请严格阅读并执行本指南中的标准化对接流程(SOP)。
1. 核心架构铁律:UI 不满足时坚决使用 Client SDK,严禁抄源码重写接口!
[!CAUTION] 开发与 AI 编码铁律:严禁绕过 SDK 自行手写接口请求 当宿主站点的 UI/UX 设计、视觉风格或交互逻辑与插件预置的
<*View />组件不符时:
- ❌ 严禁行为:去插件内部查看源码(如
http.ts,cart.ts,auth.ts等),然后自己在宿主项目中写原生fetch、直接拼装后端 API、自己在本地维护 Token 或购物车数据!这种做法会彻底破坏整站数据一致性与安全防护,后续升级时必然导致宿主项目功能崩塌。- ✅ 正确规范:坚决使用插件导出的 Headless Client SDK(
@maofuxing/astro-site-plugin/client)!
- 插件已将完整的电商交易能力抽象为无头(Headless)原生 TypeScript SDK。宿主完全可以随意设计自己的 HTML 结构、CSS 样式或 Vue/React 组件,并在事件响应时直接调用 SDK 标准方法(如
addToCart,syncCartFromServer,fetchOrders,createPaymentOrder,loginWithEmail等)。- 所有的底层重活——跨环境域名切换(
apiBaseUrl)、客户端租户鉴权(client-id/ Bearer Token)、多语言请求头、规格型号前置校验、跨标签页实时广播(BroadcastChannel)、服务端单一真实源同步、错误信息多语言转译、PayPal 订单状态轮询——全部由 SDK 严密保障,无需且严禁宿主自行发明轮子!
2. 核心架构痛点解答:交易页面的 Header / Footer 如何复用宿主项目?
- 问题:预置页面(
/cart,/checkout,/login等)使用的是什么 Header?插件自身作为通用 npm 包,不知道宿主使用的是哪个 Layout 文件、顶部是哪个导航组件,难道无法复用宿主的 Header 吗? - 答案:完全可以,且这是本插件推崇的最佳实践!
- 原理:
- Astro 原生路由优先级规定:宿主项目物理目录
src/pages/下的文件,优先级绝对高于 Integration 注入的路由。 - 插件将 7 个核心业务页面的主体逻辑全部封装为了独立的 Astro View 组件(如
<CartView />、<LoginView />等)。 - 大模型或开发者只需在宿主
src/pages/下创建对应的物理页面(如src/pages/cart.astro),引入宿主原本的<BaseLayout>或<Layout>,将<CartView />放在其中——仅需 5 行代码,宿主站点的 Header、Logo、导航菜单、Footer 及全局 CSS 样式即刻被 100% 完整复用!
- Astro 原生路由优先级规定:宿主项目物理目录
3. 大模型对接标准 SOP(五步执行法)
步骤 1:工程感知与探测(Host Reconnaissance)
接手任务后,大模型首先执行文件搜索,探明宿主项目的关键结构:
- 探测宿主主布局(Layout):搜索
src/layouts/*.astro,通常为Layout.astro、BaseLayout.astro或MainLayout.astro。 - 探测宿主头部组件(Header):搜索
src/components/*Header*.astro或Navbar.astro。 - 探测宿主多语言机制:检查宿主是采用物理目录(如存在
src/pages/zh/、src/pages/de/),还是 Astro 内置i18n,还是单语言英文站。
步骤 2:配置 astro.config.mjs
在宿主配置中注册 mfxCommerce。对于准备自建页面的宿主,强烈建议配置 injectRoutes: false,避免路由重复注入告警:
// astro.config.mjs
const isDev = process.env.NODE_ENV !== 'production';
mfxCommerce({
apiBaseUrl: isDev ? 'https://app.maofuxing.cn' : '',
tenantId: 'your-tenant-id',
paypalClientId: 'your-paypal-client-id',
cdnHost: 'https://cdn3.btitib.com',
defaultLocale: 'en',
locales: ['en', 'zh', 'de', 'ja'],
injectRoutes: false // 禁用自动路由注入,交由宿主物理页面完全接管
})步骤 3:宿主 Header 导航挂载
打开宿主的顶部导航组件(如 src/components/SiteHeader.astro),引入插件的导航辅助组件:
---
// 在宿主 Header 组件顶部引入
import CartBadge from '@maofuxing/astro-site-plugin/components/CartBadge.astro';
import UserNav from '@maofuxing/astro-site-plugin/components/UserNav.astro';
---
<!-- 在 Header 的操作按钮区域(通常在语言切换器或搜索框旁边)挂载 -->
<div class="header-actions">
<!-- 购物车实时红点角标:点击自动跳转到对应语言的 /cart -->
<CartBadge />
<!-- 用户状态入口:未登录显示 Log In,登录后显示邮箱与下拉菜单(My Orders / Logout) -->
<UserNav />
</div>步骤 4:拼装 7 个核心业务物理页面(复用宿主 Layout)
在宿主 src/pages/ 目录下创建 7 个核心物理页面,直接引用宿主的 <Layout> 与插件的 <*View />:
① 购物车页:src/pages/cart.astro
---
import Layout from '../layouts/Layout.astro';
import CartView from '@maofuxing/astro-site-plugin/components/CartView.astro';
---
<Layout title="Shopping Cart">
<CartView />
</Layout>② 结算收银页:src/pages/checkout.astro
---
import Layout from '../layouts/Layout.astro';
import CheckoutView from '@maofuxing/astro-site-plugin/components/CheckoutView.astro';
---
<Layout title="Checkout">
<CheckoutView />
</Layout>③ 订单历史页:src/pages/orders.astro
---
import Layout from '../layouts/Layout.astro';
import OrdersView from '@maofuxing/astro-site-plugin/components/OrdersView.astro';
---
<Layout title="My Orders">
<OrdersView />
</Layout>④ 登录页:src/pages/login.astro
---
import Layout from '../layouts/Layout.astro';
import LoginView from '@maofuxing/astro-site-plugin/components/LoginView.astro';
---
<Layout title="Sign In">
<LoginView />
</Layout>⑤ 注册页:src/pages/register.astro
---
import Layout from '../layouts/Layout.astro';
import RegisterView from '@maofuxing/astro-site-plugin/components/RegisterView.astro';
---
<Layout title="Create Account">
<RegisterView />
</Layout>⑥ 账号中心页:src/pages/account.astro
---
import Layout from '../layouts/Layout.astro';
import AccountView from '@maofuxing/astro-site-plugin/components/AccountView.astro';
---
<Layout title="My Account">
<AccountView />
</Layout>⑦ 支付结果页:src/pages/payment/result.astro
---
import Layout from '../../layouts/Layout.astro';
import PaymentResultView from '@maofuxing/astro-site-plugin/components/PaymentResultView.astro';
---
<Layout title="Payment Result">
<PaymentResultView />
</Layout>步骤 5:多语言物理站点的对齐拼装(如 /pages/zh/, /pages/de/)
如果宿主像工业品外贸站常见架构一样,采用物理目录承载多语言(如 src/pages/zh/):
- 大模型只需在对应子目录下创建同名页面。
- 传递
locale="zh"给宿主<Layout>(如果宿主 Layout 需要); - 插件的
<*View />组件自动会从 URL 路径(Astro.url.pathname)中提取语言前缀,无需手动传参,自动加载对应的中/英文案!
示例:中文购物车页 src/pages/zh/cart.astro:
---
import Layout from '../../layouts/Layout.astro';
import CartView from '@maofuxing/astro-site-plugin/components/CartView.astro';
---
<Layout title="购物车" locale="zh">
<!-- CartView 自动感知 /zh/cart 路径,纯中文呈现 -->
<CartView />
</Layout>示例:德文订单页 src/pages/de/orders.astro:
---
import Layout from '../../layouts/Layout.astro';
import OrdersView from '@maofuxing/astro-site-plugin/components/OrdersView.astro';
---
<Layout title="Meine Bestellungen" locale="de">
<OrdersView />
</Layout>步骤 6:产品详情页与加购挂载
在宿主的产品展示页(如 src/pages/products/[slug].astro 或卡片列表组件)中,嵌入加购按钮:
---
import AddToCartButton from '@maofuxing/astro-site-plugin/components/AddToCartButton.astro';
---
<AddToCartButton
productId="2088077609578303488"
productModelId="2089162892886052864" <!-- 💡 多型号产品必传此字段 -->
modelName="M09A02-07-010-1-L" <!-- 可选:型号名称 -->
productCode="M09-02P"
productName="M9 Male Straight Molded Cable Assembly"
image="/images/products/m9.jpg"
url="/products/m9-cable"
unitPriceUsd={10.27}
quantity={1}
class="my-custom-btn-class"
/>产品型号与异常提示规范:
- 多型号产品必传
productModelId:如果商品存在多规格/型号(如工业品),后端接口强制要求传入productModelId。若未传,后端将拒绝加购。- 多语言错误显式提示:
AddToCartButton会自动将后端的失败原因(或多语言兜底文案)通过 Toast 显式弹出提示用户,彻底告别静默失败。- 未登录拦截:未登录用户点击按钮会自动引导重定向至登录页,登录成功后自动回跳。
🧩 完整组件与视图字典(API Reference)
页面级主体视图组件(用于拼装页面,复用 Header)
| 组件名 | 导入路径 | 说明 |
| :--- | :--- | :--- |
| CartView | @maofuxing/astro-site-plugin/components/CartView.astro | 购物车主体:商品明细列表、数量增减、移除、清空、总价汇总、去结算 |
| CheckoutView | @maofuxing/astro-site-plugin/components/CheckoutView.astro | 结算主体:收货地址与国际区号电话、商品勾选确认、PayPal 支付 SDK 容器 |
| OrdersView | @maofuxing/astro-site-plugin/components/OrdersView.astro | 订单历史:全部/已支付/未支付/已关闭标签筛选、分页、未支付订单就地重新支付 |
| LoginView | @maofuxing/astro-site-plugin/components/LoginView.astro | 会员登录:邮箱 + 密码输入、记住登录状态、登录后自动 redirect 回跳 |
| RegisterView | @maofuxing/astro-site-plugin/components/RegisterView.astro | 会员注册:邮箱录入、密码验证、6 位图形/邮件动态验证码弹窗校验 |
| AccountView | @maofuxing/astro-site-plugin/components/AccountView.astro | 会员中心:展示当前账号脱敏信息、注册时间、历史概览、一键安全登出 |
| PaymentResultView | @maofuxing/astro-site-plugin/components/PaymentResultView.astro | 支付结果:URL 订单号解析、向服务端轮询支付状态、成功/失败展示与回跳 |
所有 View 组件均支持以下通用 Props(可选):
locale?: string:强制指定语言代码(默认自动从 URL 截取,如/zh/...->zh)。class?: string:宿主自适应的最外层容器自定义 CSS 类名。
全局导航与挂件组件
| 组件名 | 导入路径 | 放置位置 | 说明 |
| :--- | :--- | :--- | :--- |
| CartBadge | @maofuxing/astro-site-plugin/components/CartBadge.astro | 宿主 Header 操作区 | 购物车红点角标,实时监听加购事件与数量变更,带徽章数字 |
| UserNav | @maofuxing/astro-site-plugin/components/UserNav.astro | 宿主 Header 操作区 | 用户状态入口:未登录显示登录链接,已登录显示邮箱头像及下拉菜单 |
| CartFloat | @maofuxing/astro-site-plugin/components/CartFloat.astro | 宿主 Layout 底部 | 右下角悬浮抽屉式购物车,点击滑出侧边栏迷你购物车 |
| AddToCartButton | @maofuxing/astro-site-plugin/components/AddToCartButton.astro | 产品详情/列表卡片 | 加购按钮,内置未登录强拦截及加购反馈动画 |
| CommerceImage | @maofuxing/astro-site-plugin/components/CommerceImage.astro | 任意 Astro 模板 | 统一图片组件:遵循三段式图片解析规范,支持加载占位符、懒加载与自定义尺寸/样式 |
🖼️ 统一图片组件与三段式解析规范
插件内部所有涉及商品、购物车与订单图片的处理均遵循严密的三段式解析逻辑:
- 完整路径(以
http://、https://、//、data:开头):原样保留,不做任何重复拼接; - 接口类相对路径(以
/api/或api/开头):一律走当前访问域名(客户端取window.location.origin,部署在二级域名如sub.example.com时严格保留二级域名,绝不退回主域名;SSR 静态生成期输出标准相对路径/api/...由浏览器请求同源地址); - 其余普通相对路径 / 短路径:一律走集成配置传入的
cdnHost(未配置或缺省时以"https://cdn3.btitib.com"兜底)。
在 Astro 页面模板中使用 <CommerceImage />:
---
import CommerceImage from '@maofuxing/astro-site-plugin/components/CommerceImage.astro';
---
<CommerceImage
src="/upload/product.jpg"
alt="Product Name"
width={80}
height={80}
loading="lazy"
class="my-product-thumb"
>
<span slot="placeholder">No Image</span>
</CommerceImage>💻 Headless 纯 SDK 客户端编程指南
[!IMPORTANT] 开发指南:当预置 UI 组件不满足需求时,为什么必须使用 SDK 而非自写 fetch?
- 域名与鉴权封装:SDK 统一读取宿主在
astro.config.mjs中配置的apiBaseUrl与tenantId,并自动注入Client-id、Authorization: Bearer <token>、Lang及Accept-Language。自行手写fetch极易漏传关键请求头或将开发域名硬编码到代码中。- 规格型号与异常阻断:SDK 和按钮内部封装了对多规格型号(
productModelId)的完整支持,并内置未登录强拦截机制。自己写接口如果漏传型号参数会直接导致加购报错。- 跨标签页广播与全局联动:SDK 内置了基于
BroadcastChannel的事件总线。调用 SDK 方法修改购物车或登录状态时,页面头部角标(CartBadge)、悬浮抽屉(CartFloat)以及所有已打开的同源浏览器标签页毫秒级自动联动刷新。如果绕过 SDK 自行发请求,页面各部分状态将彻底割裂失步。- 异常提示多语言友好:SDK 具备智能多语言转译能力,非中文语境下能拦截并转译后端透传的中文业务错误,避免外文站出现中文提示。
- 平滑演进与向下兼容:底层 API 协议(如支付收银、加密规则)升级时,使用 SDK 的宿主站仅需升级 npm 包即可平滑过渡,零重构成本。
如果宿主需要更深度的定制,例如希望在自己的自定义 HTML 按钮、Vue/React 组件中直接控制业务,可以直接调用原生 Client SDK:
import {
// 1. 认证接口(严格对应实际 TypeScript 签名)
isLoggedIn, // () => boolean - 判断是否已登录
getCurrentMember, // () => MemberProfile | null - 获取当前登录会员资料
requireLogin, // (redirectUrl?: string) => void - 未登录自动重定向至登录页(登录后自动回跳)
loginWithEmail, // (email, password) => Promise<{ accessToken: string; member: MemberProfile }>
sendRegisterEmailCode, // (email: string) => Promise<{ success: boolean; message?: string }>
verifyEmailCode, // (email: string, code: string) => Promise<string> - 验证并返回注册凭证 ticket
registerWithTicket, // (ticket: string, password: string, confirmPassword?: string) => Promise<{ accessToken: string; member: MemberProfile }>
logout, // () => void - 同步清除 Token、会员与购物车缓存,并跨标签页广播
// 2. 购物车与型号规格接口(服务端作为单一真实源)
getCart, // () => CartItem[] - 获取当前购物车明细列表
getLocalCart, // 别名,同 getCart
syncCartFromServer, // () => Promise<CartItem[]> - 强制向后端拉取最新购物车并同步本地
addToCart, // (item: Omit<CartItem, 'cartItemId'>, options?: { button?: HTMLElement; silent?: boolean }) => Promise<void>
getProductModels, // (productId: string, params?: { pageNo?: number; pageSize?: number }) => Promise<ProductModelListResponse>
updateCartItemQuantity,// (idOrCartItemId: string, quantity: number) => Promise<void>
removeCartItem, // (idOrCartItemId: string) => Promise<void>
clearCart, // () => Promise<void> - 清空购物车
getCartTotalCount, // () => number - 获取购物车商品总件数统计
// 3. 订单与支付接口
fetchOrders, // (query?: OrderListQuery) => Promise<OrderListResult> - 分页查询历史订单
fetchOrderDetail, // (orderId: string) => Promise<OrderDetail> - 查询单笔订单详情
createPaymentOrder, // (payload: CreateOrderPayload) => Promise<CreatedOrderResult> - 创建系统订单与 PayPal 订单
capturePayPalPayment, // (orderId: string, paypalOrderId: string) => Promise<{ paymentStatus: string | number; [key: string]: any }> - 两个位置参数完成 PayPal 捕获
pollOrderStatus, // (orderId: string, maxAttempts?: number, intervalMs?: number) => Promise<'PAID' | 'FAILED' | 'PENDING'>
getOrderRepayUrl, // (orderId: string, locale?: string) => string - 获取待支付订单就地重新付款 URL
// 4. 图片解析与渲染接口(三段式规范)
resolveImageUrl, // (src: string | null | undefined, customCdnHost?: string) => string - 解析为绝对或规范图片 URL
renderImageTag, // (options: RenderImageTagOptions) => string - 客户端动态渲染安全 <img> 标签或占位元素
// 5. 事件总线与生命周期 Hooks
COMMERCE_EVENTS, // { CART_UPDATED: 'mfx:cart-updated', CART_ADDED: 'mfx:cart-added', AUTH_CHANGED: 'mfx:auth-changed' }
hooks // 包含 4 个核心生命周期钩子(见下文详解)
} from '@maofuxing/astro-site-plugin/client';🪝 完整 4 个生命周期 Hooks 详解
插件内置了基于 Tapable 机制的 4 个异步拦截/通知钩子,允许宿主在关键业务节点进行前置阻断或后续埋点:
| Hook 属性名 | 类型 | 触发时机与上下文参数 | 返回值 / 说明 |
| :--- | :--- | :--- | :--- |
| hooks.beforeAddToCart | AsyncSeriesHook | 加购前执行{ productId, quantity, ...item } | 返回 false 可阻止加购;返回 true 允许放行 |
| hooks.afterAddToCart | AsyncParallelHook | 加购成功后执行{ productId, quantity, ...item } | 异步并行触发,用于加购成功后的埋点或通知 |
| hooks.beforeCheckout | AsyncSeriesHook | 去结算创建订单前执行{ cartItemIds, receiverName, receiverPhone, receiverAddress } | 返回 false 可阻止结算(如表单二次合规校验) |
| hooks.onPaymentSuccess | AsyncParallelHook | 支付成功捕获后执行{ orderId, totalAmountUsd?, ...order } | 异步并行触发,用于 GA4 / Facebook Pixel 等 Purchase 事件上报 |
🛠️ 20+ 个实用的 SDK 扩展工具函数
除了核心业务接口外,@maofuxing/astro-site-plugin/client 还完整导出了以下实用工具,供开发者与大模型直接复用,杜绝重复手写:
1. 交互弹窗与轻提示
showToast(message: string, type?: 'error' | 'success' | 'info', duration?: number): void:全局轻量级浮层提示(自动适配移动端与暗黑主题)。showConfirmModal(options: ConfirmModalOptions): Promise<boolean>:Promise 化通用确认弹窗(如删除确认、清空确认),用户点击确认 resolvetrue,取消 resolvefalse。
2. 订单状态映射与辅助
ORDER_STATUS_MAP:订单状态字典常量{ PENDING: 0, PAID: 1, FAILED: 2, CLOSED: 3, REFUNDED: 4 }。getPaymentStatusMeta(status: string | number, locale?: string):根据状态码返回多语言标签文案、徽章样式类及状态标志({ label, badgeClass, isPending, isPaid })。getOrderDetailUrl(orderId: string, locale?: string): string:快速生成当前多语言环境下的订单详情页 URL。
3. 国际化电话与国家区号
COUNTRY_DIAL_CODES:内置 240+ 全球国家/地区 ISO 二字码、英文名与国际电话区号的只读常量数组。getLocalizedCountryList(locale?: string): CountryDialCode[]:获取根据当前语言智能翻译/排序的国家区号列表。normalizePhone(rawValue: string, country?: { dialCode?: string }):将用户输入的电话号码清洗并标准化为带国际区号的标准字符串({ digits, international })。
4. 价格、规格与数据转换
formatMoneyUsd(value: number | string | null | undefined): string:标准格式化美元金额输出(如$12.50)。parseMoq(value?: any): number:最小起订量(MOQ)安全转换为整型数值(兜底为 1)。mapServerCartItem(item: any): CartItem:将后端返回的购物车 JSON 规整转换为前端标准CartItem(内置自动规范化图片 URL)。
5. 图片解析与动态模板渲染
resolveImageUrl(src: string | null | undefined, customCdnHost?: string): string:遵循三段式解析规则(完整 URL 保持原样、/api/保持当前域名含二级域名、普通路径拼 cdnHost 或兜底 CDN),返回标准化图片 URL。renderImageTag(options: RenderImageTagOptions): string:在客户端 JS / 模板字符串中快速生成安全标准<img>标签或图片缺失占位元素 HTML(支持 loading, width, height, className, style, fallbackText)。
6. 底层配置、鉴权与跨标签页通信
getConfig(): CommerceConfig:获取运行时注入的插件全局配置项。getToken(): string/setToken(token: string): void/clearToken(): void:底层 Token 存取封装。getClientLocale(): string:获取浏览器当前上下文解析出的语言代号。getLocalizedRoute(route: string, targetLocale?: string): string:根据当前或指定语言,为基础路径自动注入前缀。requestApi<T = any>(path: string, options?: RequestInit): Promise<T>:底层封装的fetch请求器(自动注入Client-id、Bearer Token、多语言标头及异常转译)。getBroadcastChannel(): BroadcastChannel | null:获取用于同源多标签页数据同步的BroadcastChannel实例。emitCartUpdated(detail?)/emitCartAdded(detail?)/emitAuthChanged(isLoggedIn, detail?):底层跨标签页广播发射器。
实战用例 1:自定义加购并带登录拦截与型号支持
<!-- 宿主纯 HTML 按钮 -->
<button id="custom-buy-btn" class="my-button">Quick Buy Now</button>
<script>
import { isLoggedIn, requireLogin, addToCart, showToast } from '@maofuxing/astro-site-plugin/client';
document.getElementById('custom-buy-btn')?.addEventListener('click', async () => {
// 1. 未登录强拦截:未登录则重定向至登录页并携带当前 URL 回跳
if (!isLoggedIn()) {
requireLogin(window.location.href);
return;
}
try {
// 2. 已登录,执行加购(必须提供唯一 id 与 服务端 productId,多型号传 productModelId)
await addToCart({
id: 'M09A02-07-010-1-L',
productId: '2088077609578303488',
productModelId: '2089162892886052864', // 💡 多规格型号必传
modelName: 'M09A02-07-010-1-L',
productName: 'M9 Male Straight Molded Cable',
image: '/images/products/m9.jpg',
url: window.location.pathname,
unitPriceUsd: 10.27,
quantity: 1
});
showToast('Successfully added to cart!', 'success');
} catch (err) {
// 错误信息已由 SDK 自动本地化转译
showToast(err?.message || 'Failed to add item', 'error');
}
});
</script>实战用例 2:监听购物车变动更新自定义 UI
import { COMMERCE_EVENTS, getCartTotalCount } from '@maofuxing/astro-site-plugin/client';
// 监听跨标签页与本页的所有购物车变动
window.addEventListener(COMMERCE_EVENTS.CART_UPDATED, (event) => {
const count = getCartTotalCount();
console.log('Cart updated! New total item count:', count);
const myCustomBadge = document.getElementById('my-badge');
if (myCustomBadge) {
myCustomBadge.textContent = String(count);
}
});实战用例 3:完整 4 个生命周期 Hooks 拦截与埋点
import { hooks, showToast } from '@maofuxing/astro-site-plugin/client';
// 1. 加购前置拦截校验(返回 false 阻止加购)
hooks.beforeAddToCart.tap(async (item) => {
if (item.unitPriceUsd && item.unitPriceUsd <= 0) {
showToast('Invalid product price', 'error');
return false;
}
return true;
});
// 2. 加购成功后异步通知
hooks.afterAddToCart.tap(async (item) => {
console.log('Item added to cart:', item.productName);
});
// 3. 结算去付款前置校验
hooks.beforeCheckout.tap(async ({ cartItemIds, receiverPhone }) => {
if (!cartItemIds || cartItemIds.length === 0) {
showToast('Please select at least one item', 'error');
return false;
}
return true;
});
// 4. 支付成功回调(向 Google Analytics / Meta Pixel 上报转化事件)
hooks.onPaymentSuccess.tap(async ({ orderId, totalAmountUsd }) => {
if (window.gtag) {
window.gtag('event', 'purchase', {
transaction_id: orderId,
value: totalAmountUsd,
currency: 'USD'
});
}
});实战用例 4:使用确认弹窗(Confirm Modal)
import { showConfirmModal, clearCart, showToast } from '@maofuxing/astro-site-plugin/client';
async function handleClearCart() {
const confirmed = await showConfirmModal({
title: 'Clear Cart',
message: 'Are you sure you want to remove all items from your cart?',
confirmText: 'Clear',
cancelText: 'Cancel',
confirmType: 'danger'
});
if (confirmed) {
await clearCart();
showToast('Cart cleared', 'info');
}
}🎨 样式定制与主题覆盖
模块使用基于 CSS 变量的设计令牌,在宿主全局样式中即可覆盖主题色:
:root {
/* 品牌主色与悬停交互 */
--mfx-commerce-primary: #182922;
--mfx-commerce-primary-hover: #264338;
/* 辅色与强调色 */
--mfx-commerce-secondary: #8c6d3f;
--mfx-commerce-accent: #d4a373;
/* 背景与卡片底色 */
--mfx-commerce-bg: #f9fafb;
--mfx-commerce-card-bg: #ffffff;
/* 圆角与边框 */
--mfx-commerce-radius: 8px;
}若宿主完全不需要预设 CSS,可在 astro.config.mjs 中指定 customStylePath 传入宿主自定义样式文件:
mfxCommerce({
// ...
customStylePath: './src/styles/my-custom-commerce.css'
})❓ 常见问题(FAQ)
Q1:如果我不传 injectRoutes: false 会怎么样?
- 答:插件默认会通过
injectRoute注入所有路由。如果你同时在宿主创建了物理文件(如src/pages/cart.astro),Astro 的优先级规则依然会让你的物理文件生效,但在构建(astro build)时 Astro 会打印一条路由碰撞的警告日志。因此推荐在自建物理页面时明确声明injectRoutes: false。
Q2:宿主没有在 astro.config.mjs 中配置 Astro 官方的 i18n,能用多语言吗?
- 答:完全可以! 很多外贸站采用物理目录(如
/pages/zh/、/pages/de/)进行多语言划分。插件的 View 组件与 SDK 内部会自动从当前浏览器的window.location.pathname与 Astro 的Astro.url.pathname中提取前缀(例如/zh/cart提取出zh),并自动加载对应语言的词典,无缝配合物理多语言站。
Q3:用户退出登录后,本地购物车会清空吗?
- 答:调用
logout()后,插件会自动清除本地 token 与用户关联的购物车缓存,并通过BroadcastChannel通知所有同源标签页同步重置,保护用户隐私与数据一致性。
Q4:如果预置的 UI 组件(比如购物车列表、结账表单、加购按钮)不符合我站点的设计稿,我该怎么办?能直接看插件源码自己写 fetch 吗?
- 答:绝对不要看插件源码去自己写 fetch,请坚决走 Headless SDK 模式!
你可以在宿主项目中自由使用任意 HTML 标签、Tailwind CSS、React 或 Vue 构建你的视觉界面,底层业务逻辑(加购、更新数量、清空、查询型号、创建订单、PayPal 支付捕获、登录认证等)只需要调用
@maofuxing/astro-site-plugin/client导出的 SDK 方法。 这样既能拥有 100% 自由度的 UI 设计还原,又能免费获得服务端单一真实源同步、跨标签页实时广播、多型号自动校验、多语言错误转译、开发/生产域名环境自适应等全部底层保障,彻底杜绝自写代码带来的各种隐患。
🔗 相关链接
- 贸福星官网:https://maofuxing.cn
- 如需商业合作、技术支持或更多建站套件,请访问贸福星数字化出海服务平台。
