【Nova UI】十三、打造组件库之按钮组件(中):样式雕琢全攻略

序言

在上一篇文章中,我们已成功搭建起 Vue 按钮组件的基本架构 🏗️,赋予其强大的核心功能与流畅的交互逻辑。此刻,一个功能完备的按钮雏形已然呈现。然而,在追求卓越用户体验的道路上,仅有功能远远不够,样式的精心雕琢同样关键。就如同打造一辆超级跑车,强大的引擎是基础,但炫酷的外观才是吸引众人目光的焦点。接下来,我们将一同踏入按钮组件样式的奇幻世界,探索如何通过色彩 🌈、形状 🔳、阴影 🖤 等元素,赋予按钮独特魅力,使其在前端界面中脱颖而出。

样式 UI 图:设计蓝图引领方向 🗺️

在正式动工之前,还是先给大家展示一下 Element 样式 UI 图。从不同场景下按钮的颜色搭配,到按钮的整体形状,每一个细节都一目了然。

按钮基础样式实现:构建坚实的基石 🧱

在组件库的开发中,为了保证一致性,有些样式往往是统一规范的,例如高度、内外边距以及字体大小等。我们先实现按钮组件那些基本不变的样式,代码如下:

scss 复制代码
@include b(button) {
  display: inline-flex;
  vertical-align: middle;
  justify-content: center;
  align-items: center;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  outline: none;
  user-select: none;
  transition: 0.1s;
  
  padding: 0 getVariableValue('space');
  height: getVariableValue('size');
  font-size: getVariableValue('font-size');
  
  border-width: getVariableValue('border-width');
  border-style: getVariableValue('border-style');
  border-radius: getVariableValue('border-radius');

  & + & {
    margin-left: getVariableValue('space');
  }
}

这里利用了全局定义的变量,通过 getVariableValue 函数来获取对应的属性值,就如同从一个装满各种样式配件的宝库中,精准地取出我们需要的零件,为按钮打造出统一、规范的基础样式。实现后的样式效果如下图,可以看到,按钮已经初步具备了整齐、有序的外观,为后续的个性化样式设计奠定了坚实的基础。

实现思路:颜色变幻的魔法密码 🔮

我们知道,按钮在不同场景下的样式区别主要体现在边框颜色、字体颜色以及背景颜色上,并且在默认、禁用、悬停这三种情况下,会展示出不同深度的颜色。那如何实现这种神奇的颜色变化呢?答案就是通过定义变量,巧妙地修改变量的颜色来实现各种情况下的样式变化。接下来,让我们一步步揭开这个魔法的奥秘。

初始化变量、默认值:为魔法准备材料 📦

scss 复制代码
$button: () !default;
$button: map.merge(
  (
    'font-color': getVariableValue('font-color'),
    'border-color': getVariableValue('border-color'),
    'background-color': getVariableValue('fill-color'),

    'hover-font-color': getVariableValue('font-color', 'hover'),
    'hover-border-color': getVariableValue('color', 'primary', 'light-7'),
    'hover-background-color': getVariableValue('color', 'primary', 'light-9'),

    'disabled-font-color': getVariableValue('font-color', 'disabled'),
    'disabled-border-color': getVariableValue('border-color', 'light'),
    'disabled-background-color': getVariableValue('fill-color'),
  ),
  $button
);
@include b(button) {
  @include set-all-variable-from-map('button', $button);
}

首先,咱们来看看代码开头部分的变量定义与合并操作。
$button: ()!default; 这行代码声明了一个名为 $button 的 SCSS 变量,初始它被设置为空映射(map),这里的 !default 标记意味着如果这个变量在别处已经被定义过了,那它就会保留之前的值,否则就使用当前这个空映射的初始设定,这样的写法增加了代码的灵活性和可扩展性。

紧接着,$button: map.merge(...) 这部分可是关键所在。map.merge 是将两个映射合并成一个新的映射,并且后面传入的映射参数会覆盖前面相同键名的值。

然后各个属性通过getVariableValue函数获取默认值。最后通过 set-all-variable-from-map('button', $button)将这些映射的属性设置成变量,如'font-color': getVariableValue('font-color'),属性将会编译成--n-button-font-color: var(--n-font-color)var(--n-font-color)就是getVariableValue('font-color')拿到的具体的变量值。

设置初始样式:点亮魔法的第一束光 🌟

scss 复制代码
@include b(button) {
  color: getVariableValue('button', 'font-color');
  border-color: getVariableValue('button', 'border-color');
  background-color: getVariableValue('button', 'background-color');
  &:hover {
    color: getVariableValue('button', 'hover-font-color');
    border-color: getVariableValue('button', 'hover-border-color');
    background-color: getVariableValue('button', 'hover-background-color');
  }}

color: getVariableValue('button', 'font-color')这个属性举例,最后会编译成color: var(--n-button-font-color)。这段代码让按钮在默认状态下呈现出我们设定的颜色,并且在鼠标悬停时,能够巧妙地变换颜色,给用户带来直观的交互反馈。到此我们的基本工作已经做完。实现的效果如下图:

scene场景样式具体实现:场景变换的魔法盛宴 🎉

接下来,我们要为按钮在不同场景下赋予独特的色彩风格,让它能够根据不同的使用场景,展现出最合适的外观。

辅助混入:魔法配方的秘籍 📜

scss 复制代码
@mixin button-action-scene-color($scene) {
  $scene-color-types: (
    '': (
      'font-color': (
        'color',
        'white'
      ),
      'border-color': (
        'color',
        $scene
      ),
      'background-color': (
        'color',
        $scene,
      ),
    ),
    'hover': (
      'font-color': (
        'color',
        'white'
      ),
      'border-color': (
        'color',
        $scene,
        'light-3',
      ),
      'background-color': (
        'color',
        $scene,
        'light-3',
      ),
    ),
    'disabled': (
      'font-color': (
        'color',
        'white'
      ),
      'border-color': (
        'color',
        $scene,
        'light-5',
      ),
      'background-color': (
        'color',
        $scene,
        'light-5',
      ),
    )
  );
  @each $action, $colorMap in $scene-color-types {
    @each $color, $list in $colorMap {
      @include set-variable-from-global((button, $action, $color), $list);
    }
  }
}

这个名为 button-action-scene-color 的混入接收 $scene 参数,用来指定具体场景。

在混入内部,定义了 $scene-color-types 这个映射,它划分了默认、悬停、禁用三种状态,且针对每种状态设置了字体、边框、背景颜色的相关取值规则。比如默认状态下,边框和背景颜色会依据 $scene 参数来确定,悬停和禁用状态则在此基础上结合如 light-3light-5 等深浅标识获取相应颜色值。

而后通过两层嵌套的 @each 循环,调用 set-variable-from-global ,将各状态下设定好的颜色值应用到按钮对应的属性上,从而实现不同场景及状态下按钮颜色的准确呈现,助力打造出美观又符合交互逻辑的按钮样式。

场景循环:魔法的华丽绽放 🔥

在按钮组件样式设定中,下面这段 "场景循环" 代码有着关键作用。

scss 复制代码
@each $scene in $sceneTypes {
    @include m($scene) {
      @include button-action-scene-color($scene);
    }
  }

这里的 @each 循环会遍历 $sceneTypes 里的元素。在每次循环时,先是通过 @include m($scene),接着 @include button-action-scene-color($scene) 会依据该场景进一步设置如默认、悬停、禁用等不同状态下的颜色样式,以此让按钮在各个场景下都能展现出合适的外观,整体实现了场景样式的有序且合理的应用。

编译后的代码大致如下:

scss 复制代码
.n-button--primary {
  --n-button-font-color: var(--n-color-white);
  --n-button-border-color: var(--n-color-primary);
  --n-button-background-color: var(--n-color-primary);
  --n-button-hover-font-color: var(--n-color-white);
  --n-button-hover-border-color: var(--n-color-primary-light-3);
  --n-button-hover-background-color: var(--n-color-primary-light-3);
  --n-button-disabled-font-color: var(--n-color-white);
  --n-button-disabled-border-color: var(--n-color-primary-light-5);
  --n-button-disabled-background-color: var(--n-color-primary-light-5);
}

不同场景下的样式如下图: 可以看到,按钮在不同场景下,如 primarysuccess 等,都展现出了独特的颜色风格,无论是正常状态、悬停还是禁用,都能给用户带来清晰的视觉区分和良好的交互体验。

完整组件样式:魔法成品的惊艳呈现 🌟

其它的样式实现与上文实现类似,具体的不一一赘述了,可以到下方提到的仓库中查看具体代码。最后完整实现如下图:

此时的按钮组件,已经成为了一个功能与颜值并存的完美作品,它在不同场景下都能展现出独特的魅力,为用户带来流畅、美观的交互体验。

最后在packages/components/button目录下新增index.ts作为组件的入口文件,负责整合组件。

🦀🦀感谢看官看到这里,如果觉得文章不错的话🙌,点个关注不迷路⭐。

诚邀您加入我的微信技术交流群🎉,群里都是志同道合的开发者👨‍💻,大家能一起交流分享摸鱼🐟。期待与您在群里相见🚀,咱们携手在开发路上共同进步✨ ! 👉点我
感谢各位大侠一路相伴,实在感激! 不瞒您说,在下还有几个开源项目 📦,它们就像精心培育的幼苗 🌱,急需您的浇灌。要是您瞧着还不错,麻烦动动手指,给它们点亮几颗 Star ⭐,您的支持就是它们成长的最大动力,在此谢过各位大侠啦!

相关推荐
却尘6 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare8 分钟前
浅浅看一下设计模式
前端
Lee川11 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix38 分钟前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人41 分钟前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空1 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust