前言
笔者目前业务主要围绕ant design mobile
组件库来交付H5前端工作。
故此出此专栏来解读每一个组件是如何实现的。
本文基于AI来解读image组件。
文档链接:
mobile.ant.design/zh/componen...
源码:
设计prompt
arduino
解读antd-mobile image组件,结构化思维输出整个组件实现流程,并且解读lazy-detector.tsx是如何实现组件懒加载的
// 附组件代码
实现步骤
1. antd-mobile Image 组件实现流程(结构化步骤+关键代码)
步骤 1:参数和默认属性合并
- 支持图片各种参数:src、alt、尺寸、fit、懒加载、占位图、失败图、事件等
- 合并默认属性(如 fit、placeholder、fallback、lazy、draggable)
关键代码:
jsx
const defaultProps = {
fit: 'fill',
placeholder: (
<div className={`${classPrefix}-tip`}>
<ImageIcon />
</div>
),
fallback: (
<div className={`${classPrefix}-tip`}>
<BrokenImageIcon />
</div>
),
lazy: false,
draggable: false,
}
const props = mergeProps(defaultProps, p)
步骤 2:声明状态和ref
- 维护加载/失败状态 loaded/failed
- 维护组件根节点ref和img标签ref
- 懒加载初始化状态:
initialized
(lazy模式初始为false,否则为true)
关键代码:
jsx
const [loaded, setLoaded] = useState(false)
const [failed, setFailed] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const imgRef = useRef<HTMLImageElement>(null)
const [initialized, setInitialized] = useState(!props.lazy)
步骤 3:决定是否加载图片资源
- 组件未初始化(未在 viewport/lazy时)则不传 src 给 img(浏览器不会自动加载图片)。
- 只有当 initialized==true,src/srcSet 才真正传给 img 标签。
关键代码:
jsx
src = initialized ? props.src : undefined
srcSet = initialized ? props.srcSet : undefined
步骤 4:图片状态/事件处理
- 图片加载成功 setLoaded(true)
- 加载失败 setFailed(true)
- 加载未完成时显示 placeholder,占位图标
- 加载失败时显示 fallback 故障图片
关键代码:
jsx
onLoad={e => {
setLoaded(true)
props.onLoad?.(e)
}}
onError={e => {
setFailed(true)
props.onError?.(e)
}}
步骤 5:图片显示逻辑
renderInner()
:如果 failed 或没有资源,返回 fallback。否则渲染<img>
- 显示顺序:未 loaded -> 先显示占位图,loaded -> 显示图片
关键代码:
jsx
function renderInner() {
if (failed || (src === undefined && !srcSet)) {
return <>{props.fallback}</>
}
// ...img code
return (
<>
{!loaded && props.placeholder}
{img}
</>
)
}
步骤 6:调整尺寸样式
- 支持 width/height 用 CSS 变量和 style 生效,适配灵活布局
关键代码:
jsx
if (props.width) { style['--width'] = toCSSLength(props.width); style['width'] = toCSSLength(props.width) }
if (props.height) { style['--height'] = toCSSLength(props.height); style['height'] = toCSSLength(props.height) }
步骤 7:懒加载处理逻辑
- 如果 lazy 为 true 且 initialized 为 false,渲染一个专门的
LazyDetector
- 只有当 LazyDetector 触发
onActive
,才激活图片资源加载
关键代码:
jsx
{props.lazy && !initialized && (
<LazyDetector
onActive={() => setInitialized(true) }
/>
)}
步骤 8:主结构渲染
- 组件整体为 div 包裹,挂载所有自定义事件和样式
- withNativeProps 让原生属性/变量支持自动注入
关键代码:
jsx
return withNativeProps(
props,
<div ref={ref} className={classPrefix} style={style} onClick={props.onContainerClick}>
{props.lazy && !initialized && <LazyDetector onActive={() => setInitialized(true)} />}
{renderInner()}
</div>
)
2. LazyDetector 的懒加载实现方式解读
功能:
检测当前 LazyDetector 元素是否进入视口,进入视口时自动触发图片加载
实现机制
- 内部用
ref
挂载一个空 div - 用
ahooks
的useInViewport(ref)
检测此 div 是否在视口 - 监听 inViewport 状态变化,只要进入视口则执行 props.onActive(钩子里 setInitialized(true))
- 整个组件渲染时无需监听 scroll/resize,完全用 IntersectionObserver 封装好的钩子自动化
关键代码:
jsx
const ref = useRef<HTMLDivElement>(null)
const [inViewport] = useInViewport(ref)
useEffect(() => {
if (inViewport) {
props.onActive()
}
}, [inViewport])
return <div ref={ref} />
流程概览
- Image 组件初始为 lazy、未初始化状态,渲染
- LazyDetector 渲染后,ahooks/useInViewport 自动观察该 ref 是否进入可见区域
- 一旦进入,调用 onActive,Image组件 setInitialized(true)
- initialized == true,重新渲染,传 src 给 img,触发图片加载
3. 整体简要流程串联
- 初始化参数与状态(合并props/loaded/failed/initialized)
- 渲染时根据 initialized 决定是否加载图片资源
- 懒加载模式下先渲染 LazyDetector
- 图片进入视口,自动触发 onActive,更新initialized
- 图片进入加载流程,根据加载状态显示 loading/图片/fallback
- 响应所有原生事件和自定义样式
以上就是笔者基于AI返回的解读信息稍加了一些补充和修改,结合起来看源码提效真是太多了,对于前端本身就是基于视图所完成编码,因此把组件逻辑层交给AI来解读太适合不过了。
希望对大家有所帮助,共同学习源码。