React如何实现一个通用骨架屏组件示例

骨架屏是什么?找到这里的同志,或多或少都对骨架屏有所了解,请容许我先啰嗦一句。骨架屏(Skeleton Screen)是一种优化用户弱网体验的方案,可以有效缓解

骨架屏是什么?

找到这里的同志,或多或少都对骨架屏有所了解,请容许我先啰嗦一句。骨架屏(Skeleton Screen)是一种优化用户弱网体验的方案,可以有效缓解用户等待的焦躁情绪。

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>
    );
  }
};

完整代码及其使用文档

完整代码 obiusm-react-components

文档 https://magic-zhu.github.io/obiusm-react-components-docs/components/skeleton/

到此这篇关于React实现一个通用骨架屏组件示例的文章就介绍到这了,更多相关React 骨架屏内容请搜索好代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持好代码网!

标签: React 骨架屏