Concis组件库封装——Avatar头像

960 阅读2分钟

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

头像组件文档如下:

在这里插入图片描述 在这里插入图片描述 所提供的的API能力如下: 在这里插入图片描述

封装思路主要由Avatar和AvatarGroup两个组件完成,用户可以单Avatar来使用,当头像比较多可以采用AvatarGroup进行控制,因此还是由Group创建Context上下文,来对Avatar进行整体控制。

源码如下: Avatar.tsx:

import React, { FC, useContext, useEffect, memo, useMemo, useRef } from 'react';
import { ctx } from './group';
import { avatarProps, avatarStyles } from './interface';
import './styles/avatar.module.less';

const Avatar: FC<avatarProps> = (props) => {
  const {
    children,
    style = {},
    size = 40,
    shape,
    autoFixFontSize = true,
    triggerType = 'button',
    triggerIcon,
    triggerClick,
  } = props;

  const groupProps = useContext(ctx);
  const textRef = useRef(null);

  useEffect(() => {
    autoFixFontSizeHandler();
  }, []);
  const autoFixFontSizeHandler = () => {
    if (autoFixFontSize) {
      //如果用户配置了文本自适应
      if (textRef.current) {
        const textDomWidth = (textRef.current as HTMLElement).clientWidth;
        const avatarSize = groupProps.size || size || 40;
        if (textDomWidth - avatarSize > 0) {
          //文本不够,需要自适应
          (textRef.current as HTMLElement).style.transform = `scale(${
            1 - (textDomWidth - avatarSize + 5) / 100
          })`;
          console.log(textDomWidth, avatarSize);
        }
      }
    }
  };
  const formatStyle = useMemo(() => {
    //整合所有头像传参样式
    const returnStyle: avatarStyles = { ...groupProps.groupStyle, ...style };
    if (Object.keys(groupProps).length > 0) {
      //头像组
      if (groupProps.size) {
        returnStyle.width = `${groupProps.size}px`;
        returnStyle.height = `${groupProps.size}px`;
        returnStyle.fontSize = `${groupProps.size / 3}px`;
      }
    } else {
      //单头像
      if (size) {
        returnStyle.width = `${size}px`;
        returnStyle.height = `${size}px`;
        returnStyle.fontSize = `${size / 3}px`;
      }
    }
    if (shape && shape === 'square') {
      returnStyle.borderRadius = '5px';
    }
    return returnStyle;
  }, [style, shape, size, groupProps]);
  const buttonDialogTransform = useMemo(() => {
    return shape == 'square' ? { right: '-2px', bottom: '-2px' } : { right: '2px', bottom: '-2px' };
  }, [triggerType]);
  const handleClick = () => {
    triggerClick && triggerClick();
  };

  return (
    <div className="avatar" style={formatStyle}>
      {children && (children as any).type === 'img' ? (
        children
      ) : (
        <div ref={textRef} className="text-ref">
          {children}
        </div>
      )}
      {
        //按钮式dialog
        triggerType === 'button' && triggerIcon && (
          <div className="button-dialog" style={buttonDialogTransform} onClick={handleClick}>
            {triggerIcon}
          </div>
        )
      }
      {
        //内嵌式dialog
        triggerType === 'mask' && triggerIcon && (
          <div className="dialog">
            <div className="icon" onClick={handleClick}>
              {triggerIcon}
            </div>
          </div>
        )
      }
    </div>
  );
};

export default memo(Avatar);

AvatarGroup.tsx:

import React, { createContext, FC, memo } from 'react';
import { groupProps } from './interface';
import './styles/group.module.less';

export const ctx = createContext<any>({} as any); //顶层通信装置
const AvatarGroup: FC<groupProps> = (props) => {
  const { children, size, groupStyle = {} } = props;

  const groupProps = props;
  return (
    <ctx.Provider value={groupProps}>
      <div className="avatar-group">{children}</div>
    </ctx.Provider>
  );
};

export default memo(AvatarGroup);

组件库目前也是完成了一部分了,也慢慢开始成型了,上文加入了组件埋点+后端管理信息,最后留一下组件库的信息:

开源不易,欢迎学习和体验,喜欢请多多支持,有问题请留言。