【Nova UI】九、打造组件库第一个组件-图标组件(中):属性、功能与样式的完美融合

序言

在上一篇文章中,我们成功搭建起 SVG 图标组件包的基础架构🏗️,这如同为组件库这座大厦奠定了稳固的基石。如今,我们将目光聚焦于图标组件样式的雕琢工作,思考如何巧妙运用已掌握的 SASS 全局变量管理技巧,赋予图标组件丰富多样且统一协调的外观风格🌈。这不仅是提升组件库视觉一致性的关键🔑,更是增强用户体验的重要一环。让我们一同开启这场图标组件的样式优化之旅🚶‍♂️。

Icon组件

在组件库的持续建设中,Icon 组件的开发是极为关键的一步🌟。为实现对图标组件属性及类型的精准把控,我们在packages/components/icon/src/目录下,新增了icon.tsicon.js文件。其中,icon.ts肩负着定义组件属性与 TypeScript 类型的重任。

icon.ts 剖析

ts 复制代码
import { ExtractPropTypes, PropType } from 'vue'
import { svgs } from '@nova-ui/svgs'

export const iconProps = {
  name: {
    type: String as PropType<(typeof svgs)[number]>,
    required: true,
  },
  color: {
    type: String,
  },
  size: {
    type: [Number, String] as PropType<number | string>,
  },
} as const

export type IconType = ExtractPropTypes<typeof iconProps>

这段代码构建了 Icon 组件的基础属性体系📋。name属性指定图标名称,其取值限定在svgs数组内,确保只有预定义图标可被调用,避免非法名称的使用,就像给图标选择设置了一个 "白名单"🛂。color属性允许开发者通过字符串形式的颜色值对图标进行个性化上色🎨,轻松满足不同的视觉需求。size属性设计灵活,既支持数字形式(默认单位像素),也接受字符串形式的尺寸描述,满足不同场景下对图标大小的精确调整需求,无论是在小巧的移动端界面还是宽大的电脑屏幕上,都能完美适配📱🖥️。

PropType

是 Vue 中用于精确定义组件props类型的工具,通过它可指定复杂属性类型,增强 TypeScript 开发时的类型安全性。\

ts 复制代码
const MyComponent = defineComponent({
  props: {
    value: {
      type: [String, Number] as PropType<string | number>,
      required: false
    }
  },
  setup(props) {
    return () => <div>{props.value}</div>;
  }
});

在上述代码中,value属性可接受stringnumber类型的值,就像给组件的这个 "输入口" 明确了可接收的 "货物种类"🛒。
ExtractPropTypes

用于从props定义对象中提取属性类型信息,同样增强组件的类型安全性。\

ts 复制代码
const props = {
  message: {
    type: String,
    required: true
  }
};
const MessageComponent = defineComponent({
  props,
  setup(props) {
    return () => {
      return <div>{props.message}</div>;
    };
  }
});
type Props = ExtractPropTypes<typeof props/>;
ts 复制代码
const App = defineComponent({
  setup() {
    const myMessage = 'Hello, Vue 3!';
    return () => {
      return <MessageComponent message={myMessage} />;
    };
  }
});

在此例中,TypeScript依据ExtractPropTypes提取的Props类型,检查传递给MessageComponentmessage属性是否符合要求,确保数据传递的准确性和稳定性📡。

icon.vue 解析

icon.vue文件在 Icon 组件整体构建中,承担着实现具体功能的核心任务🧠。

html 复制代码
<template>
  <i
    :class="ns.b()"
    :style="style"
  >
    <component :is="svg" />
  </i>
</template>

template 里,<i> 标签作为图标容器,通过 :class 绑定 ns.b() 生成的特定类名,利用 useNamespace 避免样式冲突。:style 绑定 style 计算属性,用于动态调整图标样式。而 <component :is="svg" /> 依据 svg 计算属性,能动态渲染出对应 SVG 图标组件,增强了复用性与灵活性🎭。

ts 复制代码
<script lang="ts" setup>
  import { computed, CSSProperties } from 'vue'
  import { useNamespace } from '@nova-ui/hooks'
  import { isUndefined, addUnit } from '@nova-ui/utils'
  import * as Svgs from '@nova-ui/svgs'
  import { iconProps } from './icon'

  const ns = useNamespace('icon')
  defineOptions({
    name: 'NIcon',
  })
  const { name, color, size } = defineProps(iconProps)

  const svg = computed(() => {
    return Svgs[name]
  })

  const style = computed<CSSProperties>(() => {
    if (!color && !size) return {}

    return {
      fontSize: isUndefined(size) ? undefined : addUnit(size),
      color: color,
    }
  })
</script>

script部分,通过导入各种必要的模块与工具🛠️,为组件的功能实现提供了有力支持。computed用于创建计算属性,CSSProperties定义样式类型,useNamespace生成命名空间类名,isUndefinedaddUnit分别判断值是否为undefined及添加单位。同时,还导入了 SVG 图标组件与组件属性。

ns 通过 useNamespace 生成 Icon 组件的命名空间实例📍。defineOptions 定义组件名称为 NIcon。通过解构 defineProps(iconProps) 获取父组件传来的 namecolorsize 属性🍱。

svg 计算属性依据 nameSvgs 获取对应图标组件,style 计算属性根据 colorsize 生成样式对象。若无这两个属性传入则返回空对象,否则为 size 添加单位并设置 fontSizecolor 样式✨。

icon.vue 以简洁代码实现高效功能,为 Icon 组件在库中的应用与扩展筑牢根基。部分工具函数实现可在下方提及到的仓库中查看 。

样式

packages/theme-chalk/src目录下,新增icon.scss,用于编写 Icon 组件的样式。再在当前目录下新增index.scss统一导入所有组件样式。

scss 复制代码
@use 'mixins' as *;

@include b(icon) {
  display: inline-flex;
  width: 1em;
  height: 1em;
}

这段样式代码为 Icon 组件设定了基础的展示样式,使其以inline-flex的布局方式呈现,宽度和高度均为1em,确保图标在页面上能够整齐、美观地展示🛍️。

到此,图标组件已经实现完成了🎉。通过从属性定义到功能实现,再到样式设计的一系列精心打造,我们成功地为组件库增添了一个实用且美观的 Icon 组件,为后续的开发工作奠定了更加坚实的基础。

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

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

相关推荐
文心快码BaiduComate10 分钟前
WAVE SUMMIT深度学习开发者大会2025举行 文心大模型X1.1发布
前端·后端·程序员
babytiger11 分钟前
python 通过selenium调用chrome浏览器
前端·chrome
passer98117 分钟前
基于webpack的场景解决
前端·webpack
华科云商xiao徐24 分钟前
Java并发编程常见“坑”与填坑指南
javascript·数据库·爬虫
奶昔不会射手30 分钟前
css3之grid布局
前端·css·css3
举个栗子dhy34 分钟前
解决在父元素上同时使用 onMouseEnter和 onMouseLeave时导致下拉菜单无法正常展开或者提前收起问题
前端·javascript·react.js
Coding_Doggy40 分钟前
苍穹外卖前端Day1 | vue基础、Axios、路由vue-router、状态管理vuex、TypeScript
前端
前端与小赵41 分钟前
vue3和vue2生命周期的区别
前端·javascript·vue.js