vue3+typescript+vite封装自己的UI组件库并上传至npm

简介

在现代化前端工程体系中,封装一套属于自己的 UI 组件库,是提升研发效能与保障产品体验一致性的核心战略。它不仅能够将设计中沉淀的视觉语言和交互规范转化为可执行的代码资产,从根源上消灭每个页面"各自为政"的样式冗余与逻辑碎片;更能通过统一的 API 设计与版本管理,大幅降低跨团队协作的沟通成本与联调风险。当业务需求迭代时,修改一个基础组件的内部逻辑便可实现全局生效,既避免了"牵一发而动全身"的维护噩梦,确保了品牌调性在每一次交互中的稳定传递。长远来看,这更是技术团队积累领域知识、构建工程护城河的关键一步------让开发者从重复造轮子的琐碎中解放出来,专注于业务价值的深度创新。下面是使用vue3+typescript+vite封装自己的UI组件库并上传至npm教程,该框架功能包括边开发组件即时浏览组件效果,使用该组件库包括按需加载引用组件及样式,全量引入组件和样式两种使用模式。

项目结构

css 复制代码
MY-UI/
├── _test_/
│   └── button.test.js
├── command/
│   ├── build.js
│   └── index.d.ts
├── src/
│   ├── assets/
│   │   ├── fonts/
│   │   │   ├── iconfont.css
│   │   │   ├── iconfont.ttf
│   │   │   ├── iconfont.woff
│   │   │   └── iconfont.woff2
│   │   └── styles/
│   │       ├── base.scss
│   │       ├── darkVar.scss
│   │       ├── lightVar.scss
│   │       ├── oldVar.scss
│   │       └── youndVar.scss
│   ├── components/
│   │   ├── button/
│   │   │   ├── index.scss
│   │   │   ├── index.ts
│   │   │   └── index.vue
│   │   ├── dialog/
│   │   │   ├── index.scss
│   │   │   ├── index.ts
│   │   │   └── index.vue
│   │   ├── icon/
│   │   │   ├── index.scss
│   │   │   ├── index.ts
│   │   │   └── index.vue
│   │   └── index.ts
│   ├── images/
│   ├── router/
│   │   └── index.ts
│   ├── types/
│   ├── utils/
│   │   ├── bus.ts
│   │   └── index.ts
│   ├── views/
│   │   ├── button.vue
│   │   ├── dialog.vue
│   │   └── icon.vue
│   ├── App.vue
│   └── main.ts
├── .commitlintrc.js
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .npmignore
├── .prettierignore
├── .prettierrc.js
├── index.html
├── package.json
├── pnpm-lock.yaml
├── postcss.config.js
├── README.md
├── shims-vue.d.ts
├── tsconfig.json
├── version.config.json
└── vite.config.ts

项目技术栈

perl 复制代码
node:v18.20.5

"@commitlint/cli": "^19.6.1",

"@types/node": "^22.10.5",

"@typescript-eslint/eslint-plugin": "^8.19.1",

"@typescript-eslint/parser": "^8.19.1",

"@vitejs/plugin-vue": "5.1.0",

"@vitejs/plugin-vue-jsx": "^4.1.1",

"@vue/compiler-sfc": "^3.5.13",

"@vue/runtime-dom": "^3.5.13",

"autoprefixer": "^10.4.20",

"ava": "^6.2.0",

"eslint": "^9.17.0",

"eslint-config-prettier": "^9.1.0",

"eslint-plugin-prettier": "^5.2.1",

"fs-extra": "^11.2.0",

"husky": "^9.1.7",

"lint-staged": "^15.3.0",

"postcss": "^8.5.1",

"postcss-preset-env": "^10.1.3",

"prettier": "^3.4.2",

"sass-embedded": "^1.83.1",

"ts-node": "^10.9.2",

"tsconfig-paths": "^4.2.0",

"typescript": "^5.7.2",

"vite": "5.2.0",

"vue-cli-plugin-typescript": "^0.0.1",

"vue-tsc": "^2.2.0"

my-ui库构建

arduino 复制代码
npm run lib

my-ui上传npm

shell 复制代码
# 在my-ui/lib文件夹下, 执行命令

npm login

npm publish

my-ui安装

perl 复制代码
npm install my-ui

my-ui组件库按需引入

javascript 复制代码
// 方式一
import { MyButton, MyHeader, MyTab } from 'my-ui'
// 方式二
import MyButton from 'my-ui/button'
import MyHeader from 'my-ui/header'
import MyTab from 'my-ui/tab'
import MyNumgrid from 'my-ui/numgrid'

my-ui组件库全量引入

javascript 复制代码
import myUi from 'my-ui'
import 'my-ui/style.css'
const app = createApp(App)
app.use(myUi).mount('#app')

查看组件效果

示例:

http://localhost:3000/

http://localhost:3000/icon

业务使用组件

xml 复制代码
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <div>
    <my-button :buttonText="'登录'" :bgcolor="'green'"></my-button>
    <my-loading :show="true" :loadColor="'green'"></my-loading>
    <a href="https://vite.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>

<style scoped>

</style>

效果展示

创建项目

perl 复制代码
npm create vite@latest my-vue-app -- --template vue-ts
npm install my-ui

运行项目npm run dev

组件库开发规范

所有类名以 xc- 开头,组件像素采用rem为单位,template-vue3主工程的html, body设置为

css 复制代码
html, body {
  height: 100%;
  font-family: $font-family;
  font-size: $font-size-base; // 默认:10px
  line-height: $line-height-base; // 行高默认为:1
}

组件命名

组件以my-xxxxx 开头小写进行命名,示例:

arduino 复制代码
export default defineComponent({
  name: 'my-tab'
})

组件根节点

组件根节点必须绑定主题,供换肤使用

xml 复制代码
<template>
  <div class="xc-tab" :class="'xc-theme-' + theme">
    <div class="xc-each-grid">hello world</div>
  </div>
</template>

组件样式引入

样式统一使用@use的方式引入到组件中

index.vue文件

xml 复制代码
<style lang="scss" scoped>
// 引入公共样式文件,使用 @use 规则
// 默认标准版
@use './index.scss';
</style>

class命名

以xc-xxxx命名,示例

css 复制代码
<div class="xc-each-grid">hello world</div>

标准版

yaml 复制代码
// 标准版,默认1rem = 10px
$sizes-yound: (
  1: 0.1rem,
  2: 0.2rem,
  3: 0.3rem,
  4: 0.4rem,
  5: 0.5rem,
  6: 0.6rem,
  7: 0.7rem,
  8: 0.8rem,
  9: 0.9rem,
  10: 1.0rem,
  11: 1.1rem,
  12: 1.2rem,
  13: 1.3rem,
  14: 1.4rem,
  15: 1.5rem,
  16: 1.6rem,
  17: 1.7rem,
  18: 1.8rem,
  19: 1.9rem,
  20: 2.0rem,
  21: 2.1rem,
  22: 2.2rem,
  23: 2.3rem,
  24: 2.4rem,
  25: 2.5rem,
  26: 2.6rem,
  27: 2.7rem,
  28: 2.8rem,
  29: 2.9rem,
  30: 3.0rem,
  31: 3.1rem,
  32: 3.2rem,
  33: 3.3rem,
  34: 3.4rem,
  35: 3.5rem,
  36: 3.6rem,
  37: 3.7rem,
  38: 3.8rem,
  39: 3.9rem,
  40: 4.0rem,
  41: 4.1rem,
  42: 4.2rem,
  43: 4.3rem,
  44: 4.4rem,
  45: 4.5rem,
  46: 4.6rem,
  47: 4.7rem,
  48: 4.8rem,
  49: 4.9rem,
  50: 5.0rem,
  51: 5.1rem,
  52: 5.2rem,
  53: 5.3rem,
  54: 5.4rem,
  55: 5.5rem,
  56: 5.6rem,
  57: 5.7rem,
  58: 5.8rem,
  59: 5.9rem,
  60: 6.0rem,
  61: 6.1rem,
  62: 6.2rem,
  63: 6.3rem,
  64: 6.4rem,
  65: 6.5rem,
  66: 6.6rem,
  67: 6.7rem,
  68: 6.8rem,
  69: 6.9rem,
  70: 7.0rem,
  71: 7.1rem,
  72: 7.2rem,
  73: 7.3rem,
  74: 7.4rem,
  75: 7.5rem,
  76: 7.6rem,
  77: 7.7rem,
  78: 7.8rem,
  79: 7.9rem,
  80: 8.0rem,
  81: 8.1rem,
  82: 8.2rem,
  83: 8.3rem,
  84: 8.4rem,
  85: 8.5rem,
  86: 8.6rem,
  87: 8.7rem,
  88: 8.8rem,
  89: 8.9rem,
  90: 9.0rem,
  91: 9.1rem,
  92: 9.2rem,
  93: 9.3rem,
  94: 9.4rem,
  95: 9.5rem,
  96: 9.6rem,
  97: 9.7rem,
  98: 9.8rem,
  99: 9.9rem,
  100: 10rem
);

.xc-young {
  // 使用循环生成字体大小类
  @each $key, $value in $sizes-yound {
    .xc-font-size#{$key} {
      font-size: $value;
    }
    .xc-width#{$key} {
      width: $value;
    }
    .xc-height#{$key} {
      height: $value;
    }
    .xc-margin#{$key} {
      margin: $value;
    }
    .xc-padding#{$key} {
      padding: $value;
    }
    .xc-radius#{$key} {
      border-radius: $value;
    }
    .xc-lineh#{$key} {
      line-height: $value;
    }
  }
}

xc-yound(标准版),xc-old(适老版)继承至主工程template-vue3的body类名,具体组件设置类名示例:

css 复制代码
<button class="xc-font-size10, xc-margin10">{{ buttonText }}</button>

示例说明

xc-font-size12:设置文字大小

xc-margin15:设置边间距

xc-padding20:设置内边距

内填充设置(标准版)

xc-padding10: 内填充设计稿10px,对应为1rem (1rem默认10px)

xc-paddingT10: 上内填充设计稿10px,对应为1rem (1rem默认10px)

xc-paddingR10: 右内填充设计稿10px,对应为1rem (1rem默认10px)

xc-paddingB10: 下内填充设计稿10px,对应为1rem (1rem默认10px)

xc-paddingL10: 左内填充设计稿10px,对应为1rem (1rem默认10px)

外间距设置(标准版)

xc-margin10: 外间距设计稿10px,对应为1rem (1rem默认10px)

xc-marginT10: 上外间距设计稿10px,对应为1rem (1rem默认10px)

xc-marginR0: 右外间距设计稿10px,对应为1rem (1rem默认10px)

xc-marginB10: 下外间距设计稿10px,对应为1rem (1rem默认10px)

xc-marginL10: 左外间距设计稿10px,对应为1rem (1rem默认10px)

宽度、高度设置(标准版)

xc-width10: 宽设计稿10px,对应为1rem (1rem默认10px)

xc-height10: 高设计稿10px,对应为1rem (1rem默认10px)

arduino 复制代码
.xc-width#{$key} {
  width: $value;
}
.xc-height#{$key} {
  height: $value;
}

最小宽度、高度设置(标准版)

arduino 复制代码
.xc-min-width#{$key} {
  min-width: $value;
}
.xc-min-height#{$key} {
  min-height: $value;
}

换肤

通过公共方法获取主题,组件根节点中设置获取的主题。

xml 复制代码
<script lang="ts">
  import { getTheme } from '@/utils/index'
  export default defineComponent({
    setup(props, { emit }) {
      // 获取主题色
      const theme = ref<string>('')
      theme.value = getTheme()

      return {
        theme
      }
    }
  })
</script>
yaml 复制代码
// 品牌色
$brand-light-colors: (
  0: #E54C3A,
  1: #FF5541,
  2: #FF6654,
  3: #FF7767,
  4: #FF887A,
  5: #FF998D,
  6: #FFAAA0,
  7: #FFBBB3,
  8: #FFCCC6,
  9: #FFDDD9,
  10: #FFF6F4
);
// 功能色--涨
$advance-light-colors: (
  0: #D9424E,
  1: #F14957,
  2: #F25B67,
  3: #F46D79,
  4: #F57F89,
  5: #F7929A,
  6: #F8A4AB,
  7: #F9B6BC,
  8: #FAC8CC,
  9: #FAC8CC,
  10: #FFF4F6
);
// 功能色--跌
$dip-light-colors: (
  0: #09956D,
  1: #0BAF80,
  2: #23B78C,
  3: #3CBF99,
  4: #54C7A6,
  5: #6DCFB3,
  6: #85D7BF,
  7: #9DDFCC,
  8: #B5E7D8,
  9: #CEEFE6,
  10: #EEFFFA
);
// 功能色--亏、卖
$sell-light-colors: (
  0: #356BB8,
  1: #3E7ED9,
  2: #518ADC,
  3: #6598E1,
  4: #77A4E4,
  5: #8BB2E8,
  6: #9EBEEC,
  7: #B2CBF0,
  8: #C5D8F3,
  9: #D8E5F7,
  10: #F3FAFF
);
// 辅助色--金
$king-light-colors: (
  0: #A47752,
  1: #C18C60,
  2: #C7976F,
  3: #CDA380,
  4: #D3AE8F,
  5: #DABAA0,
  6: #E0C5AF,
  7: #E6D1BF,
  8: #ECDCCF,
  9: #F3E8DF,
  10: #F8F3EF
);
// 辅助色--警示
$warn-light-colors: (
  0: #E59B32,
  1: #FFAC37,
  2: #FFB44B,
  3: #FFBD5F,
  4: #FFC473,
  5: #FFCD87,
  6: #FFD59B,
  7: #FFDEAF,
  8: #FFE6C3,
  9: #FFEED7,
  10: #FFF6EB
);

// 文本颜色
$text-light-colors: map-merge(
  (
    1: #2F313C,
    2: #797B85,
    3: #AAACB8,
    4: #F1F3F6,
    5: #FFFFFF,
  ),
  (
    6: map-get($brand-light-colors, 0),
    7: map-get($brand-light-colors, 1),
    8: map-get($brand-light-colors, 5),
    9: map-get($brand-light-colors, 10),
    10: map-get($advance-light-colors, 0),
    11: map-get($advance-light-colors, 1),
    12: map-get($advance-light-colors, 5),
    13: map-get($advance-light-colors, 10),
    14: map-get($dip-light-colors, 0),
    15: map-get($dip-light-colors, 1),
    16: map-get($dip-light-colors, 5),
    17: map-get($dip-light-colors, 10),
    18: map-get($sell-light-colors, 0),
    19: map-get($sell-light-colors, 1),
    20: map-get($sell-light-colors, 5),
    21: map-get($sell-light-colors, 10),
    22: map-get($king-light-colors, 0),
    23: map-get($king-light-colors, 1),
    24: map-get($king-light-colors, 5),
    25: map-get($king-light-colors, 10),
    26: map-get($warn-light-colors, 0),
    27: map-get($warn-light-colors, 1),
    28: map-get($warn-light-colors, 5),
    29: map-get($warn-light-colors, 10)
  )
);

// 背景颜色
$bg-light-colors: map-merge(
  /* 这里重复的原因是和黑色主题一一对应 */
  (
    1: #1E2B3F,
    2: #797B85,
    3: #AAACB8,
    4: #F1F3F6,
    5: #F7F8FA,
    6: #FFFFFF,
    7: #F1F3F6,
    8: #FFFFFF,
    9: #FFFFFF00,
    10: rgba(0, 0, 0, 0.5),
  ),
  (
    11: map-get($brand-light-colors, 0),
    12: map-get($brand-light-colors, 1),
    13: map-get($brand-light-colors, 5),
    14: map-get($brand-light-colors, 10),
    15: map-get($advance-light-colors, 0),
    16: map-get($advance-light-colors, 1),
    17: map-get($advance-light-colors, 5),
    18: map-get($advance-light-colors, 10),
    19: map-get($dip-light-colors, 0),
    20: map-get($dip-light-colors, 1),
    21: map-get($dip-light-colors, 5),
    22: map-get($dip-light-colors, 10),
    23: map-get($sell-light-colors, 0),
    24: map-get($sell-light-colors, 1),
    25: map-get($sell-light-colors, 5),
    26: map-get($sell-light-colors, 10),
    27: map-get($king-light-colors, 0),
    28: map-get($king-light-colors, 1),
    29: map-get($king-light-colors, 5),
    30: map-get($king-light-colors, 10),
    31: map-get($warn-light-colors, 0),
    32: map-get($warn-light-colors, 1),
    33: map-get($warn-light-colors, 5),
    34: map-get($warn-light-colors, 10)
  )
);

// 分隔线和线框颜色
$line-light-colors: map-merge(
  (
    1: #82848F,
    2: #E5E6EB,
    3: #F1F3F6
  ),
  (
    4: map-get($brand-light-colors, 0),
    5: map-get($brand-light-colors, 1),
    6: map-get($brand-light-colors, 5),
    7: map-get($brand-light-colors, 10),
    8: map-get($advance-light-colors, 0),
    9: map-get($advance-light-colors, 1),
    10: map-get($advance-light-colors, 5),
    11: map-get($advance-light-colors, 10),
    12: map-get($dip-light-colors, 0),
    13: map-get($dip-light-colors, 1),
    14: map-get($dip-light-colors, 5),
    15: map-get($dip-light-colors, 10),
    16: map-get($sell-light-colors, 0),
    17: map-get($sell-light-colors, 1),
    18: map-get($sell-light-colors, 5),
    19: map-get($sell-light-colors, 10),
    20: map-get($king-light-colors, 0),
    21: map-get($king-light-colors, 1),
    22: map-get($king-light-colors, 5),
    23: map-get($king-light-colors, 10),
    24: map-get($warn-light-colors, 0),
    25: map-get($warn-light-colors, 1),
    26: map-get($warn-light-colors, 5),
    27: map-get($warn-light-colors, 10)
  )
);

.xc-theme-light {
  // 文本颜色
  @each $keyText, $valueText in $text-light-colors {
    .xc-font-color#{$keyText} {
      color: $valueText;
    }
  }
  // 字体图标颜色
  @each $keyIcon, $valueIcon in $bg-light-colors {
    .xc-icon-color#{$keyIcon} {
      color: $valueIcon;
    }
  }
  // 背景色
  @each $keyBg, $valueBg in $bg-light-colors {
    .xc-bg-color#{$keyBg} {
      background-color: $valueBg;
    }
  }
  // 分割线颜色
  @each $keyLine, $valueLine in $line-light-colors {
    .xc-line-color#{$keyLine} {
      background-color: $valueLine;
    }
  }
  // 边框线颜色
  @each $keyBorder, $valueBorder in $line-light-colors {
    .xc-border-color#{$keyBorder} {
      border-color: $valueBorder;
    }
  }
}

组件封装换肤示例

xml 复制代码
<template>
  <div class="xc-tab" :class="'xc-theme-' + theme">
    <p class="xc-font-color1">1234</p>
  </div>
</template>

示例说明

xc-font-color1:控制文字颜色

xc-bg-color1:控制背景色

xc-border-color1:控制边框颜色

字体图标

使用参考

css 复制代码
<i class="iconfont icon-dianzan-xuanzhong2"></i>

示例说明:

class="iconfont"为必须的图标基础类,icon-dianzan-xuanzhong2为具体的某个图标

props属性

要求对属性进行注释说明,参考示例

php 复制代码
interface TabItem {
  title: string, // tab标题
  active: boolean, // tab是否激活
  key: string, // 唯一标识
  needIcon: boolean, // 是否需要图标
  iconName: string // 图标class名称
}
export default defineComponent({
  name: 'my-tab',
  props: {
    tabList: {
      type: Array as PropType<TabItem[]>,
      required: true,
      default: () => []
    }
  }
})

老年版

老年版下的字号大小、内间距、外间距,宽度、高度先暂定与标准版保持一致,根据实际需要修改对应关系,示例如下:

yaml 复制代码
// 老年版下的字号大小、内间距、外间距,宽度、高度 先暂定与标准版保持一致,根据实际需要修改对应关系
// 标准版,默认1rem = 10px
$sizes-old: (
  1: 0.1rem,
  2: 0.2rem,
  3: 0.3rem,
  4: 0.4rem,
  5: 0.5rem,
  6: 0.6rem,
  7: 0.7rem,
  8: 0.8rem,
  9: 0.9rem,
  10: 1.0rem,
  11: 1.1rem,
  12: 1.2rem,
  13: 1.3rem,
  14: 1.4rem,
  15: 1.5rem,
  16: 1.6rem,
  17: 1.7rem,
  18: 1.8rem,
  19: 1.9rem,
  20: 2.0rem,
  21: 2.1rem,
  22: 2.2rem,
  23: 2.3rem,
  24: 2.4rem,
  25: 2.5rem,
  26: 2.6rem,
  27: 2.7rem,
  28: 2.8rem,
  29: 2.9rem,
  30: 3.0rem,
  31: 3.1rem,
  32: 3.2rem,
  33: 3.3rem,
  34: 3.4rem,
  35: 3.5rem,
  36: 3.6rem,
  37: 3.7rem,
  38: 3.8rem,
  39: 3.9rem,
  40: 4.0rem,
  41: 4.1rem,
  42: 4.2rem,
  43: 4.3rem,
  44: 4.4rem,
  45: 4.5rem,
  46: 4.6rem,
  47: 4.7rem,
  48: 4.8rem,
  49: 4.9rem,
  50: 5.0rem,
  51: 5.1rem,
  52: 5.2rem,
  53: 5.3rem,
  54: 5.4rem,
  55: 5.5rem,
  56: 5.6rem,
  57: 5.7rem,
  58: 5.8rem,
  59: 5.9rem,
  60: 6.0rem,
  61: 6.1rem,
  62: 6.2rem,
  63: 6.3rem,
  64: 6.4rem,
  65: 6.5rem,
  66: 6.6rem,
  67: 6.7rem,
  68: 6.8rem,
  69: 6.9rem,
  70: 7.0rem,
  71: 7.1rem,
  72: 7.2rem,
  73: 7.3rem,
  74: 7.4rem,
  75: 7.5rem,
  76: 7.6rem,
  77: 7.7rem,
  78: 7.8rem,
  79: 7.9rem,
  80: 8.0rem,
  81: 8.1rem,
  82: 8.2rem,
  83: 8.3rem,
  84: 8.4rem,
  85: 8.5rem,
  86: 8.6rem,
  87: 8.7rem,
  88: 8.8rem,
  89: 8.9rem,
  90: 9.0rem,
  91: 9.1rem,
  92: 9.2rem,
  93: 9.3rem,
  94: 9.4rem,
  95: 9.5rem,
  96: 9.6rem,
  97: 9.7rem,
  98: 9.8rem,
  99: 9.9rem,
  100: 10rem
);

.xc-old {
  // 使用循环生成字体大小类
  @each $key, $value in $sizes-old {
    .xc-font-size#{$key} {
      font-size: $value;
    }
    .xc-width#{$key} {
      width: $value;
    }
    .xc-height#{$key} {
      height: $value;
    }
    .xc-margin#{$key} {
      margin: $value;
    }
    .xc-marginT#{$key} {
      margin-top: $value;
    }
    .xc-marginR#{$key} {
      margin-right: $value;
    }
    .xc-marginB#{$key} {
      margin-bottom: $value;
    }
    .xc-marginL#{$key} {
      margin-left: $value;
    }
    .xc-padding#{$key} {
      padding: $value;
    }
    .xc-paddingT#{$key} {
      padding-top: $value;
    }
    .xc-paddingR#{$key} {
      padding-right: $value;
    }
    .xc-paddingB#{$key} {
      padding-bottom: $value;
    }
    .xc-paddingL#{$key} {
      padding-left: $value;
    }
    .xc-radius#{$key} {
      border-radius: $value;
    }
    .xc-lineh#{$key} {
      line-height: $value;
    }
  }
}

定位设置

bash 复制代码
.xc-positionT#{$key} {
  top: $value;
}
.xc-positionR#{$key} {
  right: $value;
}
.xc-positionB#{$key} {
  bottom: $value;
}
.xc-positionL#{$key} {
  left: $value;
}

边框设置

xml 复制代码
<div class="xc-border xc-borderW4 xc-border-color4">边框设置</div>
<style>
  .xc-border {
    border-style: solid;
  }
</style>

上边框设置

xml 复制代码
<div class="xc-border xc-borderW4 xc-border-color4">边框设置</div>
<style>
  .xc-border {
    border-top-style: solid;
  }
</style>

圆角设置

php 复制代码
// 四个角
.xc-radius#{$key} {
  border-radius: $value;
}
// 下左
.xc-radiusBL#{$key} {
  border-bottom-left-radius: $value
}
// 下右
.xc-radiusBR#{$key} {
  border-bottom-right-radius: $value
}
// 左上
.xc-radiusTL#{$key} {
  border-top-left-radius: $value
}
// 右上
.xc-radiusTR#{$key} {
  border-top-right-radius: $value
}

浅色主题

yaml 复制代码
@use 'sass:map';
// 品牌色
$brand-light-colors: (
  0: #e54c3a,
  1: #ff5541,
  2: #ff6654,
  3: #ff7767,
  4: #ff887a,
  5: #ff998d,
  6: #ffaaa0,
  7: #ffbbb3,
  8: #ffccc6,
  9: #ffddd9,
  10: #fff6f4
);
// 功能色--涨
$advance-light-colors: (
  0: #d9424e,
  1: #f14957,
  2: #f25b67,
  3: #f46d79,
  4: #f57f89,
  5: #f7929a,
  6: #f8a4ab,
  7: #f9b6bc,
  8: #fac8cc,
  9: #fac8cc,
  10: #fff4f6
);
// 功能色--跌
$dip-light-colors: (
  0: #09956d,
  1: #0baf80,
  2: #23b78c,
  3: #3cbf99,
  4: #54c7a6,
  5: #6dcfb3,
  6: #85d7bf,
  7: #9ddfcc,
  8: #b5e7d8,
  9: #ceefe6,
  10: #eefffa
);
// 功能色--亏、卖
$sell-light-colors: (
  0: #356bb8,
  1: #3e7ed9,
  2: #518adc,
  3: #6598e1,
  4: #77a4e4,
  5: #8bb2e8,
  6: #9ebeec,
  7: #b2cbf0,
  8: #c5d8f3,
  9: #d8e5f7,
  10: #f3faff
);
// 辅助色--金
$king-light-colors: (
  0: #a47752,
  1: #c18c60,
  2: #c7976f,
  3: #cda380,
  4: #d3ae8f,
  5: #dabaa0,
  6: #e0c5af,
  7: #e6d1bf,
  8: #ecdccf,
  9: #f3e8df,
  10: #f8f3ef
);
// 辅助色--警示
$warn-light-colors: (
  0: #e59b32,
  1: #ffac37,
  2: #ffb44b,
  3: #ffbd5f,
  4: #ffc473,
  5: #ffcd87,
  6: #ffd59b,
  7: #ffdeaf,
  8: #ffe6c3,
  9: #ffeed7,
  10: #fff6eb
);

// 文本颜色
$text-light-colors: map.merge(
  (
    1: #2f313c,
    2: #797b85,
    3: #aaacb8,
    4: #f1f3f6,
    5: #ffffff
  ),
  (
    6: map.get($brand-light-colors, 0),
    // #E54C3A
    7: map.get($brand-light-colors, 1),
    // #FF5541
    8: map.get($brand-light-colors, 5),
    // #FF998D
    9: map.get($brand-light-colors, 10),
    // #FFF6F4
    10: map.get($advance-light-colors, 0),
    // #D9424E
    11: map.get($advance-light-colors, 1),
    12: map.get($advance-light-colors, 5),
    13: map.get($advance-light-colors, 10),
    14: map.get($dip-light-colors, 0),
    // #09956d
    15: map.get($dip-light-colors, 1),
    //  #0Baf80
    16: map.get($dip-light-colors, 5),
    17: map.get($dip-light-colors, 10),
    18: map.get($sell-light-colors, 0),
    19: map.get($sell-light-colors, 1),
    20: map.get($sell-light-colors, 5),
    21: map.get($sell-light-colors, 10),
    22: map.get($king-light-colors, 0),
    23: map.get($king-light-colors, 1),
    24: map.get($king-light-colors, 5),
    25: map.get($king-light-colors, 10),
    26: map.get($warn-light-colors, 0),
    27: map.get($warn-light-colors, 1),
    28: map.get($warn-light-colors, 5),
    29: map.get($warn-light-colors, 10)
  )
);

// 字体图标及背景颜色
$bg-light-colors: map.merge(
  /* 这里重复的原因是和黑色主题一一对应 */
    (
      1: #1e2b3f,
      2: #797b85,
      3: #aaacb8,
      4: #f1f3f6,
      5: #f7f8fa,
      6: #ffffff,
      7: #f1f3f6,
      8: #ffffff,
      9: #ffffff00,
      10: rgba(0, 0, 0, 0.5)
    ),
  (
    11: map.get($brand-light-colors, 0),
    // #E54C3A
    12: map.get($brand-light-colors, 1),
    // #FF5541
    13: map.get($brand-light-colors, 5),
    // #FF998D
    14: map.get($brand-light-colors, 10),
    // #FFF6F4
    15: map.get($advance-light-colors, 0),
    // #D93434
    16: map.get($advance-light-colors, 1),
    // #FF3D3D
    17: map.get($advance-light-colors, 5),
    // #FF8B8B
    18: map.get($advance-light-colors, 10),
    // #FFECEC
    19: map.get($dip-light-colors, 0),
    // #09956D
    20: map.get($dip-light-colors, 1),
    // #0BAF80
    21: map.get($dip-light-colors, 5),
    // #6DCFB3
    22: map.get($dip-light-colors, 10),
    // #EEFFFA
    23: map.get($sell-light-colors, 0),
    // #356BB8
    24: map.get($sell-light-colors, 1),
    // #3E7ED9
    25: map.get($sell-light-colors, 5),
    // #8BB2E8
    26: map.get($sell-light-colors, 10),
    // #F3FAFF
    27: map.get($king-light-colors, 0),
    // #A47752
    28: map.get($king-light-colors, 1),
    // #C18C60
    29: map.get($king-light-colors, 5),
    // #DABAA0
    30: map.get($king-light-colors, 10),
    // #F8F3EF
    31: map.get($warn-light-colors, 0),
    // #E59B32
    32: map.get($warn-light-colors, 1),
    // #FFAC37
    33: map.get($warn-light-colors, 5),
    // #FFCD87
    34: map.get($warn-light-colors, 10) // #FFF6EB
  )
);

// 分隔线和线框颜色
$line-light-colors: map.merge(
  (
    1: #82848f,
    2: #e5e6eb,
    3: #f1f3f6
  ),
  (
    4: map.get($brand-light-colors, 0),
    5: map.get($brand-light-colors, 1),
    6: map.get($brand-light-colors, 5),
    7: map.get($brand-light-colors, 10),
    8: map.get($advance-light-colors, 0),
    9: map.get($advance-light-colors, 1),
    10: map.get($advance-light-colors, 5),
    11: map.get($advance-light-colors, 10),
    12: map.get($dip-light-colors, 0),
    13: map.get($dip-light-colors, 1),
    14: map.get($dip-light-colors, 5),
    15: map.get($dip-light-colors, 10),
    16: map.get($sell-light-colors, 0),
    17: map.get($sell-light-colors, 1),
    18: map.get($sell-light-colors, 5),
    19: map.get($sell-light-colors, 10),
    20: map.get($king-light-colors, 0),
    21: map.get($king-light-colors, 1),
    22: map.get($king-light-colors, 5),
    23: map.get($king-light-colors, 10),
    24: map.get($warn-light-colors, 0),
    25: map.get($warn-light-colors, 1),
    26: map.get($warn-light-colors, 5),
    27: map.get($warn-light-colors, 10)
  )
);

.xc-theme-light {
  // 文本颜色
  @each $keyText, $valueText in $text-light-colors {
    .xs-font-color#{$keyText} {
      color: $valueText;
    }
  }
  // 字体图标颜色
  @each $keyIcon, $valueIcon in $bg-light-colors {
    .xs-icon-color#{$keyIcon} {
      color: $valueIcon;
    }
  }
  // 背景色
  @each $keyBg, $valueBg in $bg-light-colors {
    .xs-bg-color#{$keyBg} {
      background-color: $valueBg;
    }
  }
  // 分割线颜色
  @each $keyLine, $valueLine in $line-light-colors {
    .xs-line-color#{$keyLine} {
      background-color: $valueLine;
    }
  }
  // 边框线颜色
  @each $keyBorder, $valueBorder in $line-light-colors {
    .xs-border-color#{$keyBorder} {
      border-color: $valueBorder;
    }
  }

  // 左边边框线颜色
  @each $keyBorder, $valueBorder in $line-light-colors {
    .xs-border-left-color#{$keyBorder} {
      border-left-color: $valueBorder;
    }
  }
}

黑色主题

yaml 复制代码
@use 'sass:map';
// 品牌色
$brand-dark-colors: (
  0: #e54c3a,
  1: #ff5541,
  2: #ff6654,
  3: #ff7767,
  4: #ff887a,
  5: #9f3931,
  6: #ffaaa0,
  7: #ffbbb3,
  8: #ffccc6,
  9: #ffddd9,
  10: #321b1f
);
// 功能色--涨
$advance-dark-colors: (
  0: #d9424e,
  1: #f14957,
  2: #f25b67,
  3: #f46d79,
  4: #f57f89,
  5: #97323e,
  6: #f8a4ab,
  7: #f9b6bc,
  8: #fac8cc,
  9: #fac8cc,
  10: #301922
);
// 功能色--跌
$dip-dark-colors: (
  0: #09956d,
  1: #0baf80,
  2: #23b78c,
  3: #3cbf99,
  4: #54c7a6,
  5: #0d6f57,
  6: #85d7bf,
  7: #9ddfcc,
  8: #b5e7d8,
  9: #ceefe6,
  10: #0e2828
);
// 功能色--亏、卖
$sell-dark-colors: (
  0: #356bb8,
  1: #3e7ed9,
  2: #518adc,
  3: #6598e1,
  4: #77a4e4,
  5: #2b528c,
  6: #9ebeec,
  7: #b2cbf0,
  8: #c5d8f3,
  9: #d8e5f7,
  10: #152136
);
// 辅助色--金
$king-dark-colors: (
  0: #a47752,
  1: #c18c60,
  2: #c7976f,
  3: #cda380,
  4: #d3ae8f,
  5: #7a5a44,
  6: #e0c5af,
  7: #e6d1bf,
  8: #ecdccf,
  9: #f3e8df,
  10: #201d20
);
// 辅助色--警示
$warn-dark-colors: (
  0: #e59b32,
  1: #ffac37,
  2: #ffb44b,
  3: #ffbd5f,
  4: #ffc473,
  5: #9f6d2b,
  6: #ffd59b,
  7: #ffdeaf,
  8: #ffe6c3,
  9: #ffeed7,
  10: #27201c
);

// 文本颜色
$text-dark-colors: map.merge(
  (
    1: #e4e9fd,
    2: #939baf,
    3: #6f7888,
    4: #1a1d24,
    5: #ffffff
  ),
  (
    6: map.get($brand-dark-colors, 0),
    7: map.get($brand-dark-colors, 1),
    8: map.get($brand-dark-colors, 5),
    9: map.get($brand-dark-colors, 10),
    10: map.get($advance-dark-colors, 0),
    11: map.get($advance-dark-colors, 1),
    12: map.get($advance-dark-colors, 5),
    13: map.get($advance-dark-colors, 10),
    14: map.get($dip-dark-colors, 0),
    15: map.get($dip-dark-colors, 1),
    16: map.get($dip-dark-colors, 5),
    17: map.get($dip-dark-colors, 10),
    18: map.get($sell-dark-colors, 0),
    19: map.get($sell-dark-colors, 1),
    20: map.get($sell-dark-colors, 5),
    21: map.get($sell-dark-colors, 10),
    22: map.get($king-dark-colors, 0),
    23: map.get($king-dark-colors, 1),
    24: map.get($king-dark-colors, 5),
    25: map.get($king-dark-colors, 10),
    26: map.get($warn-dark-colors, 0),
    27: map.get($warn-dark-colors, 1),
    28: map.get($warn-dark-colors, 5),
    29: map.get($warn-dark-colors, 10)
  )
);

// 背景颜色
$bg-dark-colors: map.merge(
  /* 这里重复的原因是和黑色主题一一对应 */
    (
      1: #cfd3e6,
      2: #939baf,
      3: #6f7887,
      4: #1a1d24,
      5: #14171d,
      6: #0f1119,
      7: #040406,
      8: #ffffff,
      9: #ffffff00,
      10: rgba(0, 0, 0, 0.5)
    ),
  (
    11: map.get($brand-dark-colors, 0),
    // #e54c3a
    12: map.get($brand-dark-colors, 1),
    // #ff5541
    13: map.get($brand-dark-colors, 5),
    // #9f3931
    14: map.get($brand-dark-colors, 10),
    // 321b1f
    15: map.get($advance-dark-colors, 0),
    16: map.get($advance-dark-colors, 1),
    17: map.get($advance-dark-colors, 5),
    18: map.get($advance-dark-colors, 10),
    19: map.get($dip-dark-colors, 0),
    20: map.get($dip-dark-colors, 1),
    21: map.get($dip-dark-colors, 5),
    22: map.get($dip-dark-colors, 10),
    23: map.get($sell-dark-colors, 0),
    24: map.get($sell-dark-colors, 1),
    25: map.get($sell-dark-colors, 5),
    26: map.get($sell-dark-colors, 10),
    27: map.get($king-dark-colors, 0),
    28: map.get($king-dark-colors, 1),
    29: map.get($king-dark-colors, 5),
    30: map.get($king-dark-colors, 10),
    31: map.get($warn-dark-colors, 0),
    32: map.get($warn-dark-colors, 1),
    33: map.get($warn-dark-colors, 5),
    34: map.get($warn-dark-colors, 10)
  )
);

// 分隔线和线框颜色
$line-dark-colors: map.merge(
  (
    1: #939baf,
    2: #6f7888,
    3: #222730
  ),
  (
    4: map.get($brand-dark-colors, 0),
    5: map.get($brand-dark-colors, 1),
    6: map.get($brand-dark-colors, 5),
    7: map.get($brand-dark-colors, 10),
    8: map.get($advance-dark-colors, 0),
    9: map.get($advance-dark-colors, 1),
    10: map.get($advance-dark-colors, 5),
    11: map.get($advance-dark-colors, 10),
    12: map.get($dip-dark-colors, 0),
    13: map.get($dip-dark-colors, 1),
    14: map.get($dip-dark-colors, 5),
    15: map.get($dip-dark-colors, 10),
    16: map.get($sell-dark-colors, 0),
    17: map.get($sell-dark-colors, 1),
    18: map.get($sell-dark-colors, 5),
    19: map.get($sell-dark-colors, 10),
    20: map.get($king-dark-colors, 0),
    21: map.get($king-dark-colors, 1),
    22: map.get($king-dark-colors, 5),
    23: map.get($king-dark-colors, 10),
    24: map.get($warn-dark-colors, 0),
    25: map.get($warn-dark-colors, 1),
    26: map.get($warn-dark-colors, 5),
    27: map.get($warn-dark-colors, 10)
  )
);

.xc-theme-dark {
  // 文本颜色
  @each $keyText, $valueText in $text-dark-colors {
    .xs-font-color#{$keyText} {
      color: $valueText;
    }
  }
  // 字体图标颜色
  @each $keyIcon, $valueIcon in $bg-dark-colors {
    .xs-icon-color#{$keyIcon} {
      color: $valueIcon;
    }
  }
  // 背景色
  @each $keyBg, $valueBg in $bg-dark-colors {
    .xs-bg-color#{$keyBg} {
      background-color: $valueBg;
    }
  }
  // 分割线颜色
  @each $keyLine, $valueLine in $line-dark-colors {
    .xs-line-color#{$keyLine} {
      background-color: $valueLine;
    }
  }
  // 边框线颜色
  @each $keyBorder, $valueBorder in $line-dark-colors {
    .xs-border-color#{$keyBorder} {
      border-color: $valueBorder;
    }
  }

  // 左边边框线颜色
  @each $keyBorder, $valueBorder in $line-dark-colors {
    .xs-border-left-color#{$keyBorder} {
      border-left-color: $valueBorder;
    }
  }
}

具体代码

bash 复制代码
git clone https://gitee.com/yuqifang/my-ui.git
相关推荐
leoZ23110 小时前
Claude 驱动的全栈开发:Spring Boot + Vue 的 BS 架构实践
vue.js·spring boot·架构
荒诞英雄14 小时前
从 17MB Vendor 大包到按需加载:Vite 多入口 Vue 组件库首屏优化实践
vue.js·vite
jsonbro14 小时前
手把手带你实现发布订阅模式
前端·vue.js·设计模式
Cobyte16 小时前
23.Vue Vapor 组件 attrs 的实现
前端·javascript·vue.js
斯特凡今天也很帅17 小时前
xml页面可以打开,不报错,但是显示数据的地方也不显示,我是怎么解决的
xml·vue.js
柯克七七18 小时前
给老项目加了 TypeScript,本来只想自己爽,结果全公司代码审查标准被我抬高了
前端·vue.js·typescript
不才难以繁此生19 小时前
HarmonyOS ArkUI NavPathStack 实战:中式美食详情页多入口返回栈怎么设计
harmonyos·arkts·arkui·navigation·中式美食·navpathstack·路由栈
不才难以繁此生20 小时前
HarmonyOS ResourceStr 实战:中式美食菜谱封面怎么统一注册、兜底和缓存
harmonyos·arkts·image·arkui·中式美食·resourcestr·图片缓存
自然 醒20 小时前
前端如何实现在线预览office常见文件功能?
前端·vue.js
肉肉不吃 肉21 小时前
前端调试跨域如何解决
前端·vue.js