Sass 封装组件级项目样式:手写 ElementPlus

一、前言

设计一个组件库的样式最重要的就是一点就是样式的高复用性和低耦合度。在一个项目中每个组件会用大量的公共样式,为了确保组件在不同的场景、布局中的样式保持统一,减少样式干扰的可能性。组件样式的命名也是非常需要统一管理的,一个优秀的命名能够增加样式的可读性,组件库中的组件可能会嵌套使用,所以封装公共样式和统一命名规范由为重要,它也直接决定了组件的易用性和扩展性。

这篇文章我将详细的向你介绍 Element Plus 中样式是如何封装设计的。

二、组件样式设计思路

Element Plus 中使用了 BEM 来给组件样式的类名来命名,整个组件库中所共有的 sass变量也是大致按照这个来命名的,统一命名规则,可以使整个组件库的样式架构复用性和拓展性变得更强。正是因为采用了 BEM 命名规则命名类名,所以在封装样式类名也需要遵循这个规则来封装。

Element Plus 在 packages\components目录下创建一个 base目录来导入 packages\theme-chalk 目录下的公共样式( root)和一些基本公共样式,这个目录下packages\components\base\style\css.ts 的文件可以导入打包好的全局 css 样式,加快渲染速度。采用这种目录结果管理样式是为了分支管理,尽可能的降低各个项目之间的耦合度。而packages/components 目录下的组件可以引用 components/base 目录下的公共样式。

每个组件下都可以创建 style文件夹来导入公共样式和组件自身的样式,组件还需要将打包好的 css 样式在 css.ts 文件下导入,这样可以提前加载出 css 样式,优化了性能。

三、组件库封装样式的具体实现

一)、类名 BEM 实现

我们再 packages\hooks 目录下创建一个 use-namespace 文件,在这个目录下来完成组件的命名规范函数封装。


const _bem = (
  namespace: string,
  block: string,
  blockSuffix: string,
  element: string,
  modifier: string
) => {
  let cls = `${namespace}-${block}`
  if (blockSuffix) {
    cls += `-${blockSuffix}`
  }
  if (element) {
    cls += `__${element}`
  }
  if (modifier) {
    cls += `--${modifier}`
  }
  return cls
}
  • namespace: 命名空间,一般用于区分不同的模块。
  • block: BEM 中的块(Block),表示组件的名称。
  • blockSuffix: 块后缀(Block Suffix),通常用于进一步细化块的分类。
  • element: BEM 中的元素(Element),表示块内部的某个具体部分。
  • modifier: BEM 中的修饰符(Modifier),用于描述块或元素的状态或属性。

根据这命名函数的条件分支,我们可以再细分一些处理函数,可以使用更加方便再一些特定的情况下。我们将这三个条件进行组合,生成六个处理函数,因为有些组件需要设计某些字段是否存在,存在就添加上对应的样式,我们可以通过 is 来实现。 这些就已经包括了组件中可能会用到的 class 类名称。

export const useNamespace = (
  block: string,
  namespaceOverrides?: Ref<string | undefined>
) => {
  const namespace = ref('fz')
 
  /**
   * 生成 BEM 格式的块级类名
   * 示例:
   * 如果 block 为 'button',调用 b() 将返回 'fz-button'
   */
  const b = (blockSuffix = '') =>
    _bem(namespace.value, block, blockSuffix, '', '')

  /**
   * 生成 BEM 格式的元素类名
   * 示例:
   * 如果 block 为 'button',调用 e('icon') 将返回 'fz-button__icon'
   */
  const e = (element?: string) =>
    element ? _bem(namespace.value, block, '', element, '') : ''

  /**
   * 生成 BEM 格式的修饰符类名
   * 示例:
   * 如果 block 为 'button',调用 m('disabled') 将返回 'fz-button--disabled'
   */
  const m = (modifier?: string) =>
    modifier ? _bem(namespace.value, block, '', '', modifier) : ''

  /**
   * 生成 BEM 格式的块级后缀和元素类名
   * 示例:
   * 如果 block 为 'button',调用 be('primary', 'icon') 将返回 'fz-button-primary__icon'
   */
  const be = (blockSuffix?: string, element?: string) =>
    blockSuffix && element
      ? _bem(namespace.value, block, blockSuffix, element, '')
      : ''

  /**
   * 生成 BEM 格式的元素和修饰符类名
   * 示例:
   * 如果 block 为 'button',调用 em('icon', 'active') 将返回 'fz-button__icon--active'
   */
  const em = (element?: string, modifier?: string) =>
    element && modifier
      ? _bem(namespace.value, block, '', element, modifier)
      : ''

  /**
   * 生成 BEM 格式的块级后缀和修饰符类名
   * 示例:
   * 如果 block 为 'button',调用 bm('primary', 'disabled') 将返回 'fz-button-primary--disabled'
   */
  const bm = (blockSuffix?: string, modifier?: string) =>
    blockSuffix && modifier
      ? _bem(namespace.value, block, blockSuffix, '', modifier)
      : ''

  /**
   * 生成 BEM 格式的完整类名
   * 示例:
   * 如果 block 为 'button',调用 bem('primary', 'icon', 'active') 将返回 'fz-button-primary__icon--active'
   */
  const bem = (blockSuffix?: string, element?: string, modifier?: string) =>
    blo
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值