首页 > 其他分享 >antd 5.0 定制主题如此酷炫,我决定开启 @ant-design/cssinjs 阅读之旅

antd 5.0 定制主题如此酷炫,我决定开启 @ant-design/cssinjs 阅读之旅

时间:2023-12-06 12:31:28浏览次数:32  
标签:5.0 const 样式 prefixCls 酷炫 theme ant token import

前言

antd 5.0 正式发布已经有一段时间了,发布当天,一心二用的看完直播。很喜欢整个设计,有种简约快乐工作的感觉,某些功能设计初衷也给了我一些启发。

antd 5.0 提供的主题定制挺酷炫的,加之我最近对「CSS-in-JS」很感兴趣。于是迫不及待的打开了它的源码,准备研究一番 。

我大部分情况下都是通过碎片化的时间来研究技术,所以时间合理配置和任务合理分块,一直是我常采用的方式。加上对源码阅读的经验不足,所以此次的阅读之旅,我将详细记录阅读前的思考、阅读规划以及收获,并将破冰心得总结之后分享出来。

文章速读

阅读文章,可以有以下收获:

antd 5.0 定制主题如此酷炫,我决定开启 @ant-design/cssinjs 阅读之旅_源码

从 demo 开始

前面有一篇源码总结的经验,对于大型的源码阅读,可以从demo开始。

接下来,我将从antd的demo开启阅读之旅。

antd 5.0 定制主题如此酷炫,我决定开启 @ant-design/cssinjs 阅读之旅_源码_02

混合主题

默认主题样式

// docs/examples/components/theme.tsx

// 默认主题样式
const defaultDesignToken: DesignToken = {
  primaryColor: '#1890ff',
  textColor: '#333333',
  reverseTextColor: '#FFFFFF',

  componentBackgroundColor: '#FFFFFF',

  borderRadius: 2,
  borderColor: 'black',
  borderWidth: 1,
};

这个默认主题样式,通过变量名大致能猜出来各自代表什么。但是具体应用在哪些元素上,还需要通过使用设置才能确定。

按钮组件

// docs/examples/components/Button.tsx

// 按钮组件
import React from 'react';
import classNames from 'classnames';
import { useToken } from './theme';
import type { DerivativeToken } from './theme';
import { useStyleRegister } from '../../../src/';
import type { CSSInterpolation, CSSObject } from '../../../src/';

// 通用框架
const genSharedButtonStyle = (
  prefixCls: string,
  token: DerivativeToken,
): CSSInterpolation => ({
  [`.${prefixCls}`]: {
    borderColor: token.borderColor, // 边框颜色
    borderWidth: token.borderWidth, // 边框宽度
    borderRadius: token.borderRadius, // 边框圆角

    cursor: 'pointer',

    transition: 'background 0.3s',
  },
});

// 实心底色样式
// 返回数组,第一个元素是通用样式,第二个元素是自定义样式,需要调用者传入
const genSolidButtonStyle = (
  prefixCls: string,
  token: DerivativeToken,
  postFn: () => CSSObject,
): CSSInterpolation => [
  genSharedButtonStyle(prefixCls, token),
  {
    [`.${prefixCls}`]: {
      ...postFn(),
    },
  },
];

// 默认样式
const genDefaultButtonStyle = (
  prefixCls: string,
  token: DerivativeToken,
): CSSInterpolation => {
  genSolidButtonStyle(prefixCls, token, () => ({
    backgroundColor: token.componentBackgroundColor, // 默认样式的背景颜色
    color: token.textColor, // 默认样式的字体颜色

    '&:hover': {
      borderColor: token.primaryColor, // 默认样式的经过时边框颜色
      color: token.primaryColor, // 默认样式的经过时字体颜色
    },
  }));
};

// 主色样式
const genPrimaryButtonStyle = (
  prefixCls: string,
  token: DerivativeToken,
): CSSInterpolation =>
  genSolidButtonStyle(prefixCls, token, () => ({
    backgroundColor: token.primaryColor, // 主色样式的背景颜色
    border: `${token.borderWidth}px solid ${token.primaryColor}`, // 主色样式的边框样式
    color: token.reverseTextColor, // 主色样式的字体样式

    '&:hover': {
      backgroundColor: token.primaryColorDisabled, // 主色样式的经过时背景颜色
    },
  }));

// 透明按钮
const genGhostButtonStyle = (
  prefixCls: string,
  token: DerivativeToken,
): CSSInterpolation => [
  genSharedButtonStyle(prefixCls, token),
  {
    [`.${prefixCls}`]: {
      backgroundColor: 'transparent', // 透明样式的背景颜色
      color: token.primaryColor, // 透明样式的字体颜色
      border: `${token.borderWidth}px solid ${token.primaryColor}`, // 透明样式的边框颜色

      '&:hover': {
        borderColor: token.primaryColor, // 透明样式的经过时背景颜色
        color: token.primaryColor,
      },
    },
  },
];

interface ButtonProps
  extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
  type?: 'primary' | 'ghost' | 'dashed' | 'link' | 'text' | 'default';
}

const Button = ({ className, type, ...restProps }: ButtonProps) => {
  const prefixCls = 'ant-btn';

  // 【自定义】制造样式
  const [theme, token, hashId] = useToken();

  // default 添加默认样式选择器后可以省很多冲突解决问题
  const defaultCls = `${prefixCls}-default`;
  const primaryCls = `${prefixCls}-primary`;
  const ghostCls = `${prefixCls}-ghost`;

  // 全局注册,内部会做缓存优化
	// 目前是三种类型的样式:默认样式、主色样式、透明样式
  const wrapSR = useStyleRegister(
    { theme, token, hashId, path: [prefixCls] },
    () => [
      genDefaultButtonStyle(defaultCls, token),
      genPrimaryButtonStyle(primaryCls, token),
      genGhostButtonStyle(ghostCls, token),
    ],
  );

  const typeCls =
    (
      {
        primary: primaryCls,
        ghost: ghostCls,
      } as any
    )[type as any] || defaultCls;

  return wrapSR(
    <button
      className={classNames(prefixCls, typeCls, hashId, className)}
      {...restProps}
    />,
  );
};

export default Button;

按钮组件中,主要包含三种主题,样式做了通用设置。从目前的代码看 genGhostButtonStyle 的设置其实和另外两个是一样的。

而通用样式时的取值来自 useToken,useToken则是采用组件树间进行数据传递的方式。

组件间传递样式

// docs/examples/components/theme.tsx

// 创建一个 Context 对象 ThemeContext
export const ThemeContext = React.createContext(createTheme(derivative));

// 创建一个 Context 对象 DesignTokenContext
export const DesignTokenContext = React.createContext<{
  token?: Partial<DesignToken>;
  hashed?: string | boolean;
}>({
  token: defaultDesignToken,
});

/**
 * 创建默认样式,并缓存 token
 * @returns 包含 theme, token, hashed 的数组对象
 */
export function useToken(): [Theme<any, any>, DerivativeToken, string] {
  // 订阅 DesignTokenContext
	// 将此处的 token 重命名为 rootDesignToken,并设置默认值 defaultDesignToken
  const { token: rootDesignToken = defaultDesignToken, hashed } =
    React.useContext(DesignTokenContext);
  // 订阅 ThemeContext
  const theme = React.useContext(ThemeContext);

  // 将 theme 派生的 token 缓存为全局共享 token
	// 实际 token 的取值
  const [token, hashId] = useCacheToken<DerivativeToken, DesignToken>(
    theme,
    [defaultDesignToken, rootDesignToken],
    {
      salt: typeof hashed === 'string' ? hashed : '',
    },
  );

  return [theme, token, hashed ? hashId : ''];
}

这里有一处处理需要注意

标签:5.0,const,样式,prefixCls,酷炫,theme,ant,token,import
From: https://blog.51cto.com/u_15838863/8702093

相关文章

  • Kali Linux 2023.4 发布 (Cloud ARM64, Vagrant Hyper-V & Raspberry Pi 5)
    KaliLinux2023.4发布(CloudARM64,VagrantHyper-V&RaspberryPi5)请访问原文链接:https://sysin.org/blog/kali-linux-2023/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org更新说明今天(2023-12-05),KaliLinux2023.4镜像下载已经可用,但是发行说明未知,官方......
  • ReenTrantLock可重入锁(和synchronized的区别)总结
    可重入性:从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入的,两者关于这个的区别不大。两者都是同一个线程没进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。锁的实现:Synchronized是依赖于JVM实现的,而ReenTra......
  • pydantic.errors.PydanticImportError,'pydantic:compiled' 在 Pydantic 版本 2 中已被
    今天编译python程序时pyinstaller-F--version-filefile_version_info.txtMelliferaCMD.py收到错误:58759INFO:Loadingmodulehook'hook-pydantic.py'from'D:\\env\\fbt\\Lib\\site-packages\\_pyinstaller_hooks_contrib\\hooks\\stdhooks&......
  • ant design使用,批量添加单词,修改单个单词
    backend项目页面路径:/Users/songximing/backend/src/pages/app/listen/Words/index.tsx弹窗修改单个单词,列表的input没变,解决办法参考:https://blog.csdn.net/weixin_42881588/article/details/124406364reactinput的defaultValue不会变化给input加了个key:{ti......
  • AntDesignBlazor示例——列表查询条件
    本示例是AntDesignBlazor的入门示例,在学习的同时分享出来,以供新手参考。示例代码仓库:https://gitee.com/known/AntDesignDemo1.学习目标重构项目文件结构添加日期查询条件实现查询业务逻辑2.重构项目结构在实现列表查询条件功能之前,我们先重构一下项目结构,创建天气Mod......
  • Ant Design Vue2表单验证失效、select下拉框验证失效
    简述AntDesignVue2表单验证失效、表单校验三个下拉框,级联联动,动态赋值,第一项changge之后2,3需要=null或者='',但是发现明明第二个select已经选择了而且this.form.b不是空为啥还是校验不通过前情提示系统:一说部分截图、链接等因过期、更换域名、MD语法等可能不显示,可联系反馈(备注......
  • Ant Design Vue2表单验证失效、select下拉框验证失效
    简述AntDesignVue2表单验证失效、表单校验三个下拉框,级联联动,动态赋值,第一项changge之后2,3需要=null或者='',但是发现明明第二个select已经选择了而且this.form.b不是空为啥还是校验不通过前情提示系统:一说部分截图、链接等因过期、更换域名、MD语法等可能不显示,可联系反馈(备注......
  • AntDesignBlazor示例——创建列表页
    本示例是AntDesignBlazor的入门示例,在学习的同时分享出来,以供新手参考。示例代码仓库:https://gitee.com/known/AntDesignDemo1.学习目标使用Table组件创建列表页面使用DisplayName特性显示中文表头使用模板和Tag组件显示高温数据使用TitleTemplate自定义栏位表头2.创......
  • MAC系统通过vagrant的安装虚拟机
    brewinstallvagrant#使用brew进行安装brewinstallVirtualBox#安装虚拟机vagrant-v#先检查一下是否安装成功初始化项目文件夹mkdirvagrant_getting_startedcdvagrant_getting_startedvagrantinitcentos/7使用centos7初始化一个虚拟机vagrantup启动虚拟......
  • 华为平板M3 BTV-DL09 亲测成功升级官方EMUI5.0-安卓7.0刷机包SD卡刷包
    调包离山之计,完成的可用组合包。试装了无数的TWRP,只有一个版本的能用。可用twrp_BTV-DL09_lte.img、即是TWRP3.0.2版,这个TWRP可以刷入降级包。但试了很多包都刷不上系统,当时以为要变砖了。还好没放弃。主要是包的目录结构的问题。还有很多卡刷包没有讲清怎么用。后面刷......