实现一个React通用骨架屏组件(vue骨架屏组件)
Demo
先看个demo 大概了解下最终的产物及其使用方式
npm install obiusm-react-components 复制代码
import { Skeleton } from 'obiusm-react-components'; 复制代码
<Skeleton isVisible={true}> <div className="wrapper"> <div className="content1"></div> <div data-skeleton-ignore={true}>123456</div> <div className="content2"></div> <div className="content3" data-skeleton-style={{ width: '50%' }}></div> </div> </Skeleton> 复制代码
只需要在自己写的组件外面包一层决定其是否显示就可以了
设计思路
骨架可以在真实内容没有加载出来前让用户提前感知,可以提高用户体验 如果我们每次写组件的时候都要为其定制骨架,那就显得相当繁琐
得益于React props
的这种数据数据传递方式,我们在props
中可以轻松拿到整颗ReactElement
的树。 那么我们只需要去递归遍历这个树从而去模仿其结构,复制其class就可以实现自动生成骨架了。
但在具体的使用上,我们可能只需要结构前几层的结构而不需要模拟整颗树的结构,也有可能自动生成的样式太丑我们需要定制其节点样式,还有可能我们不需要关注一些浮层类的内容或者说想忽略某一个节点
所以大概需要实现以下几个功能
设定递归深度
提供忽略节点的方法
提供定制骨架节点样式的方法
具体实现
首先定义一个组件函数来决定是渲染骨架屏还是真实元素
function Skeleton(props: Props) { if (!props) { return <div />; } if (props.isVisible) { return createModal(props.children, props.depth || 4, 0); } else { return props.children ? props.children : <div />; } } 复制代码
createModal
对Skeleton
下面包住的div进行递归遍历, 每次递归的时候将current+1
并传递下去,这样我们可以判断已经递归了几层了 判断一下每个节点上data-skeleton-ignore
是否有data-skeleton-style
从而特殊处理就可以了
const createModal = (child: ReactElement, depth: number, current: number) => { if ( depth === current || (child && child.props && child.props['data-skeleton-ignore']) ) { return; } if ( child && child.props && child.props.children && Array.isArray(child.props.children) && current < depth - 1 ) { return ( <div className={`${ child.props.className !== undefined ? child.props.className : '' } ${'react-skeleton'}`} style={ child.props && child.props['data-skeleton-style'] ? child.props['data-skeleton-style'] : {} } key={Math.random() * 1000} > {child.props.children && child.props.children.length > 0 ? child.props.children.map((child: any) => { return createModal(child, depth, current + 1); }) : '*'} </div> ); } else { return ( <div className={`${ child.props && child.props.className ? child.props.className : '' } ${'react-skeleton2'}`} style={ child.props && child.props['data-skeleton-style'] ? child.props['data-skeleton-style'] : {} } key={Math.random() * 1000} > * </div> ); } }; 复制代码
完整代码及其使用文档
作者:magic_zhu
链接:https://juejin.cn/post/7038221975902240805
伪原创工具 SEO网站优化 https://www.237it.com/