核心是父组件统一管理加载状态并透传props,子组件通过事件回调驱动更新:loading控制动画、noMore禁用触发、error支持重试,page由父组件递增,子组件只读不改,事件触发后父组件执行请求与状态更新。

核心在于父组件统一管理加载状态(如 loading、noMore、error),并通过 props 向子组件透传,同时子组件通过事件回调通知父组件状态变更,形成单向数据流+事件驱动的闭环。
父组件集中维护状态与逻辑
所有关键状态必须由父组件定义并响应式管理,避免子组件自行维护导致不一致:
- loading:标识当前是否处于加载中,控制加载指示器显隐
- noMore:标识数据已全部加载完毕,禁用后续触发
- error:标识上一次加载失败,可支持重试逻辑
- page / offset:分页参数,由父组件递增并传入请求函数
子组件仅接收 props,不修改状态
无限滚动子组件(如 <infinite-loading></infinite-loading> 或自定义封装)应严格遵循“只读 props”原则:
- 通过
:loading="loading"控制内部 loading 动画 - 通过
:disabled="noMore || error"禁用自动触发或显示“到底了”提示 - 不直接修改
loading或noMore,而是调用$emit('load')通知父组件 - 若使用
vue-infinite-loading,其on-infinite回调接收的是StateChanger实例,仅用于标记结果($state.loaded()/$state.complete()),不改变父组件原始状态变量
事件回调驱动状态更新与副作用
子组件触发加载时,应通过标准事件将意图抛出,由父组件执行真实逻辑:
- 监听子组件的
@load或@infinite事件 - 在事件处理器中:设置
loading = true→ 发起 API 请求 → 根据响应更新data、noMore、error - 示例逻辑:
handleLoad() { this.loading = true; fetchMore(this.page + 1) .then(res => { this.list = [...this.list, ...res.items]; this.noMore = res.total <= this.list.length; this.error = false; }) .catch(() => { this.error = true; }) .finally(() => { this.loading = false; }); }
边界状态需显式透传与反馈
用户感知依赖清晰的状态映射,不能靠子组件“猜”:
- 当
noMore === true,子组件应显示“没有更多了”,而非静默忽略滚动 - 当
error === true,提供重试按钮,并绑定@retry事件重新触发handleLoad - 首次加载失败时,
loading应为false,避免骨架屏长期挂起;错误态需独立控制 - 下拉刷新与上拉加载共存时,建议拆分为
refreshing和loading两个独立状态,分别透传

















