07 - 组件体系
组件库总览
项目有 64 个导出组件,分为旧版组件(10个,标记 /* old */)和新版 sp-* 前缀组件(54个)。
组件导出入口
src/components/index.js 统一导出所有组件:
js
// 旧版组件
export { default as GoodsItem } from './goods-item' /* old */
export { default as BackToTop } from './back-to-top' /* old */
export { default as FilterBar } from './filter-bar' /* old */
export { default as GoodsBuyPanel } from './goods-buy-panel' /* old */
export { default as FormIdCollector } from './form-id-collector' /* old */
export { default as Loading } from './loading' /* old */
export { default as TabBar } from './tab-bar' /* old */
export { default as AddressChoose } from './address/choose-address' /* old */
export { default as CouponItem } from './coupon-item' /* old */
export { default as SpCheckbox } from './sp-checkbox' /* old */
// 新版 sp-* 组件
export { default as SpButton } from './sp-button'
export { default as SpGoodsItem } from './sp-goods-item'
export { default as SpGoodsCell } from './sp-goods-cell'
// ... 共 54 个sp-* 组件清单
基础组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpButton | ./sp-button | 按钮,支持主题色、加载态 |
SpInput | ./sp-input | 输入框 |
SpSelect | ./sp-select | 选择器 |
SpCheckbox | ./sp-checkbox | 复选框 |
SpCheckboxNew | ./sp-checkbox | 新版复选框 |
SpInputNumber | ./sp-input-number | 数字输入框 |
SpNumberKeyBoard | ./sp-numberkeyboard | 数字键盘 |
SpPicker | ./sp-picker | 选择器 |
SpTimePicker | ./sp-time-picker | 时间选择器 |
SpModal | ./sp-modal | 模态弹窗 |
SpFloatLayout | ./sp-float-layout | 浮动布局 |
SpSearch | ./sp-search | 搜索组件 |
SpSearchBar | ./search-bar | 搜索栏 |
SpSearchInput | ./sp-search-input | 搜索输入框 |
SpSearchOne | ./sp-search-one | 单选搜索 |
SpToast | ./toast | Toast 提示 |
SpLoading | ./sp-loading | 加载中 |
SpDefault | ./sp-default | 默认空状态 |
商品相关组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpGoodsItem | ./sp-goods-item | 商品卡片 |
SpGoodsCell | ./sp-goods-cell | 商品列表项 |
SpGoodsPrice | ./sp-goods-price | 商品价格 |
SpPrice | ./sp-price | 价格展示 |
SpPoint | ./sp-point | 积分展示 |
SpVipLabel | ./sp-vip-label | VIP 标签 |
SpSkuSelect | ./sp-sku-select | SKU 选择器 |
SpOrderItem | ./sp-order-item | 订单商品项 |
SpTradeItem | ./sp-trade-item | 交易商品项 |
SpRecommend | ./sp-recommend | 推荐商品 |
SpRecommendItem | ./sp-recommend-item | 推荐商品项 |
媒体组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpImg | ./sp-img | 图片 |
SpImage | ./sp-image | 图片(增强版) |
SpHtml | ./sp-html | 富文本(微信使用 mp-html) |
SpUpload | ./sp-upload | 文件上传 |
SpPoster | ./sp-poster | 海报生成 |
表单组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpForm | ./sp-form | 表单容器 |
SpFormItem | ./sp-form-item | 表单项 |
SpAddress | ./sp-address | 地址选择 |
营销组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpCoupon | ./sp-coupon | 优惠券 |
SpNewCoupon | ./sp-new-coupon | 新版优惠券 |
SpCouponPackage | ./sp-coupon-package | 优惠券包 |
SpShopCoupon | ./sp-shop-coupon | 店铺优惠券 |
SpShopFullReduction | ./sp-shop-fullReduction | 满减 |
SpScreenAd | ./sp-screen-ad | 弹屏广告 |
SpFloatMenus | ./sp-float-menus | 浮动菜单 |
SpFloatMenuItem | ./sp-float-menu-item | 浮动菜单项 |
SpFloatAd | ./sp-float-ad | 浮动广告 |
导航与布局
| 组件 | 路径 | 说明 |
|---|---|---|
SpPage | ./sp-page | 页面容器(提供 Context) |
SpNavBar | ./sp-nav-bar | 导航栏 |
SpTabbar | ./sp-tabbar | 底部 TabBar |
SpTabs | ./sp-tabs | 标签页 |
SpCell | ./sp-cell | 列表单元格 |
SpScrollView | ./sp-scrollview | 滚动视图 |
SpPoweredBy | ./sp-powered-by | 版权标识 |
分类组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpCategorySearch | ./sp-category-search | 分类搜索 |
SpClassifyHorizontal | ./sp-classify-horizontal | 横向分类 |
SpClassifyVertical | ./sp-classify-vertical | 纵向分类 |
SpBrandIndexes | ./sp-brand-indexes | 品牌索引 |
业务组件
| 组件 | 路径 | 说明 |
|---|---|---|
SpCashier | ./sp-cashier | 收银台 |
SpDeliver | ./sp-deliver | 配送选择 |
SpShop | ./sp-shop | 店铺信息 |
SpChat | ./sp-chat | 客服聊天 |
SpPurchaseEnterpriseBar | ./sp-purchase-enterprise-bar | 内购企业栏 |
SpLogin | ./sp-login | 登录组件 |
SpPrivacyModal | ./sp-privacy-modal | 隐私协议弹窗 |
SpNote | ./sp-note | 笔记/提示 |
高阶组件(HOCs)
src/hocs/index.js 导出 6 个 HOC:
js
export { withLogin, withPager, withBackToTop, withPointitem, withLoadMore, withPageWrapper }withLogin — 登录 HOC
js
import { withLogin, LIFE_CYCLE_TYPES } from '@/hocs'
@withLogin((next) => { /* 登录后回调 */ }, LIFE_CYCLE_TYPES.DID_SHOW)
class MyPage extends Component { ... }| 参数 | 说明 |
|---|---|
nextFn | 登录成功后回调 |
lifeCycle | 触发时机:WILL_MOUNT(0) / DID_MOUNT(1) / DID_SHOW(2) |
行为:在指定生命周期调用 Spx.autoLogin() 完成自动登录,支持异步轮询等待(最多 8 × 70ms)。
withPager — 分页 HOC
js
@withPager
class MyList extends Component {
state = { list: [] }
async fetch({ page_no, page_size }) {
const data = await api.getList({ page: page_no, pageSize })
this.setState({ list: data.list })
return { total: data.total } // 必须返回 total
}
}注入 this.state.page = { hasNext, isLoading, total, page_no, page_size } 和 this.nextPage() / this.resetPage() 方法。
withLoadMore — 滚动加载 HOC
js
@withLoadMore
class MyList extends Component {
onLoadMore(index, type, '_', dataLength) {
// 当 .lastItem 元素进入视口时触发
}
}使用微信 IntersectionObserver 监听 .lastItem 元素,进入视口时触发回调。
withPageWrapper — 页面包装器 HOC
js
import { withPageWrapper } from '@/hocs'
const MyPage = withPageWrapper(({ initState }) => {
// 等待 initState === true 后执行进店规则
return <View>...</View>
})核心逻辑:云店进店规则检查(distributor_code → shop_assistant → shop_white → shop_assistant_pro)。
withBackToTop — 回到顶部 HOC
js
@withBackToTop
class MyPage extends Component {
// 注入 this.state.scrollTop 和 this.state.showBackToTop
// 滚动超过 300px 显示按钮
}withPointitem — 积分商品 HOC
js
@withPointitem
class MyPage extends Component {
// this.isPointitem() 判断是否积分商品
// this.transformUrl(url, isPointitem) 拼装参数
}自定义 Hooks
src/hooks/index.js 导出 16 个 Hooks:
js
export {
useLogin, // 用户登录
useQwLogin, // 企微登录
usePage, // 分页
useDepChange, // 依赖变更检测
useAsyncCallback, // 异步 setState + callback
usePayment, // 支付
useNavigation, // 导航栏
useDebounce, // 防抖
useThrottle, // 节流
useDianWuLogin, // 店务登录
useModal, // 弹窗
useSyncCallback, // 同步回调
useLocation, // 定位
useThemsColor, // 主题色
useEffectAsync, // 异步 useEffect
useFirstMount // 首次挂载检测
}useLogin
js
const { isLogin, login, logout, setToken, getUserInfo } = useLogin({
autoLogin: true, // 无 Token 时自动登录
loginSuccess: () => {} // 登录成功回调
})usePayment
js
const { cashierPayment, payError } = usePayment()
// 支持的支付通道:
// wxpay, adapay/bspay, wxpayh5, wxpayjs, deposit/point, offline_pay
// 实际可用通道由 standard(云店 B2C)或 platform(ECShopX BBC)的后端配置决定usePage
js
const { page, nextPage, resetPage } = usePage({
fetch: async (params) => {
const data = await api.getList(params)
return { total: data.total }
},
auto: true, // 自动执行
pageSize: 10
})useNavigation
js
const { setNavigationBarTitle } = useNavigation()
setNavigationBarTitle('商品详情')useLocation
js
const { updateAddress, calculateDistance } = useLocation()
await updateAddress() // 获取定位 + 更新地址
const dist = calculateDistance(lat1, lon1, lat2, lon2) // Haversine 距离useEffectAsync
js
useEffectAsync(async () => {
const data = await api.getData()
setData(data)
}, [id])useAsyncCallback
js
const [state, setStateAsync] = useAsyncCallback(initialState)
setStateAsync({ count: 1 }, () => {
// state 更新后回调
})useDebounce / useThrottle
js
const debouncedFn = useDebounce(fn, 300)
const throttledFn = useThrottle(fn, 300)useModal
js
const { showModal, hideModal } = useModal()
showModal({ title: '提示', content: '确认删除?' })组件使用规范
导入方式
js
// 统一从 components/index 导入
import { SpButton, SpGoodsItem, SpPage } from '@/components'
// 或直接从组件目录导入(按需)
import SpButton from '@/components/sp-button'SpPage 页面容器
jsx
import { SpPage } from '@/components'
function MyPage() {
return (
<SpPage
navBar={{ title: '页面标题' }}
footer={<View>底部操作栏</View>}
>
<View>页面内容</View>
</SpPage>
)
}SpPage 提供 usePageContext() 获取 scrollTop 等上下文:
js
import { usePageContext } from '@/hooks'
const { scrollTop } = usePageContext()新增组件步骤
- 在
src/components/下创建sp-my-component/目录 - 创建
index.jsx(组件逻辑)和index.scss(样式) - 创建
index.config.js(如有平台特定配置) - 在
src/components/index.js中添加导出 - 使用
@/components或直接路径导入
