<p align="center">
  <a href="https://themusecatcher.github.io/vue-amazing-ui/">
    <img width="200" src="https://themusecatcher.github.io/vue-amazing-ui/amazing-logo.svg">
  </a>
</p>

<h1 align="center">Vue Amazing UI</h1>
<p align="center">一个 Vue 3 组件库</p>
<p align="center"><b>主题可调，明暗双主题，全量使用 TypeScript 和 SFC，支持 tree shaking</b></p>
<p align="center">有点意思</p>
<p align="center">
  <a href="https://www.npmjs.com/package/vue-amazing-ui"><img src="https://img.shields.io/npm/v/vue-amazing-ui" alt="npm version"></a>
  <a href="https://www.npmjs.com/package/vue-amazing-ui"><img src="https://img.shields.io/npm/dm/vue-amazing-ui" alt="npm downloads"></a>
  <a href="https://github.com/themusecatcher/vue-amazing-ui/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/vue-amazing-ui" alt="license"></a>
</p>
<p align="center"><a href="README.md">English</a> | 中文</p>

## 文档

[Vue Amazing UI](https://themusecatcher.github.io/vue-amazing-ui/)

## 特性

- 目前共包含 `73` 个基础 `UI` 组件以及 `16` 个工具函数，并且持续探索更新中...
- 主题可调，你只需提供一个主题色，剩下的都交给我
- 支持明暗双主题，可手动切换，也可跟随系统主题自动切换
- 顺便一提，它们全都可以 `treeshaking`
- `Vue Amazing UI` 全量使用 `TypeScript` 编写，和你的 `TypeScript` 项目无缝衔接
- 全部组件均为单文件组件 `SFC`，可直接使用源码
- 支持服务端渲染
- 开箱即用，不墨迹

## 安装

```sh
pnpm add vue-amazing-ui
# or
npm install vue-amazing-ui
# or
yarn add vue-amazing-ui
# or
bun add vue-amazing-ui
```

## 使用组件

**全局完整注册（不推荐）**

_失去 `tree-shaking` 的能力，打包后有冗余代码_

```ts
import { createApp } from 'vue'
import App from './App.vue'
import VueAmazingUI from 'vue-amazing-ui'
import 'vue-amazing-ui/css'

const app = createApp(App)
app.use(VueAmazingUI)
app.mount('#app')
```

**全局部分注册**

_这种情况下，只有导入的组件才会被打包_

```ts
import { createApp } from 'vue'
import App from './App.vue'
import { Button, Tag } from 'vue-amazing-ui'
// 每个组件一个样式入口（推荐写法）：内含全局默认样式 + 组件自身样式 + 其依赖组件样式
import 'vue-amazing-ui/es/button/style'
import 'vue-amazing-ui/es/tag/style'

const app = createApp(App)
app.use(Button).use(Tag)
app.mount('#app')
```

**局部注册组件**

_这种情况下，也只有导入的组件才会被打包_

```vue
<script setup lang="ts">
import { Button, Tag } from 'vue-amazing-ui'
// 每个组件一个样式入口（推荐写法）：内含全局默认样式 + 组件自身样式 + 其依赖组件样式
import 'vue-amazing-ui/es/button/style'
import 'vue-amazing-ui/es/tag/style'
</script>
<template>
  <Button>button</Button>
  <Tag>tag</Tag>
</template>
```

> 样式入口也支持（更显式的）文件写法 `import 'vue-amazing-ui/es/button/style/index.js'`。

**自动按需引入（强烈推荐）**

使用 [`unplugin-vue-components`](https://github.com/unplugin/unplugin-vue-components) 插件来按需自动加载组件，插件会自动解析模板中的使用到的组件，并导入组件和样式

```sh
pnpm add unplugin-vue-components -D
# or
npm install unplugin-vue-components -D
# or
yarn add unplugin-vue-components -D
# or
bun add unplugin-vue-components -D
```

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from 'unplugin-vue-components/vite'
// vue-amazing-ui 按需引入
import { VueAmazingUIResolver } from 'vue-amazing-ui'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [
        // auto import components from VueAmazingUI
        VueAmazingUIResolver({
          cjs: false // whether use commonjs build, default false
        })
      ]
    })
  ]
})
```

然后，你可以在代码中直接使用 `vue-amazing-ui` 的所有组件

```vue
<template>
  <Button>button</Button>
  <Tag>tag</Tag>
</template>
```

## 使用类型

_所有类型均可直接从 `vue-amazing-ui` 中引入使用，无需任何额外安装_

```vue
<script setup lang="ts">
import { ref } from 'vue'
import type { ButtonProps } from 'vue-amazing-ui'
const shape = ref<ButtonProps['shape']>('default')
</script>
<template>
  <Button :shape="shape">button</Button>
</template>
```

## 使用工具函数

```vue
<script setup lang="ts">
import {
  dateFormat,
  formatNumber,
  throttle,
  debounce,
  add,
  downloadFile,
  useEventListener,
  useMutationObserver,
  useScroll,
  useFps,
  useMediaQuery,
  useResizeObserver,
  useSlotsExist,
  useOptionsSupported,
  getScrollParent,
  useScrollParent
} from 'vue-amazing-ui'
</script>
```

## 浏览器支持

_仅支持现代浏览器（`Chrome` / `Edge` / `Safari` / `Firefox`）。不支持 `Opera Mini` / `KaiOS` / `IE` —— 前两者无法运行 `Vue 3`。_

- 组件库要求 `Vue ≥ 3.4`
- 具体最低版本见文档的[「浏览器支持」](https://themusecatcher.github.io/vue-amazing-ui/guide/getting-started.html)
- 少数视觉增强依赖较新的 `CSS` 特性，更低的引擎上会退化为等价的基础布局，功能与可访问性不受影响

## 项目

技术栈：`Vue@3.5.45` + `TypeScript@5.9.3` + `Vite@7.3.7` + `Less@4.9.1`

- 获取项目代码

```sh
git clone https://github.com/themusecatcher/vue-amazing-ui.git
```

- 安装依赖

```sh
cd vue-amazing-ui

pnpm i
```

- 启动项目

```sh
pnpm dev
```

- 启动文档

```sh
pnpm docs:dev
```

## 参与贡献

`Vue Amazing UI` 的每一次成长，都离不开每一位贡献者。无论是新增组件、修复缺陷，还是完善文档与示例，都欢迎参与。

提交代码前，请先阅读[贡献指南](CONTRIBUTING.zh-CN.md)。

## 博客

[My CSDN Blogs](https://themusecatcher.blog.csdn.net)

## 赞助

`Vue Amazing UI` 是采用 `MIT` 许可的开源项目，使用完全免费。组件库及文档所有工作均由作者一人完成，开发迭代过程实属不易...为了组件库的健康可持续发展，非常期望能获得您的支持与赞助。

#### [成为赞助者](https://themusecatcher.github.io/vue-amazing-ui/sponsor/charge.html)

## 赞助者 🫡

所有的赞助者都将出现在此处，非常感谢你们的支持与赞助 ❤️

<img width="64" height="64" src="./docs/public/avatar_1.jpeg" alt="WeChat@Ant" title="WeChat@Ant" /> <a href="https://github.com/nizhensh-i" target="_blank"><img width="64" height="64" src="./docs/public/avatar_2.jpg" alt="GitHub@nizhensh-i" title="GitHub@nizhensh-i"></a> <a href="https://github.com/beijin1949" target="_blank"><img width="64" height="64" src="./docs/public/avatar_3.png" alt="GitHub@beijin1949" title="GitHub@beijin1949"></a> <a href="https://github.com/JinZemin" target="_blank"><img width="64" height="64" src="./docs/public/avatar_4.png" alt="GitHub@JinZemin" title="GitHub@JinZemin"></a> <a href="https://github.com/ye5840" target="_blank"><img width="64" height="64" src="./docs/public/avatar_5.png" alt="GitHub@ye5840" title="GitHub@ye5840"></a><img width="64" height="64" src="./docs/public/avatar_6.jpg" alt="WeChat@**洋" title="WeChat@**洋"> <img width="64" height="64" src="./docs/public/avatar_default.svg" alt="WeChat@*梦" title="WeChat@*梦"> <img width="64" height="64" src="./docs/public/avatar_default.svg" alt="Alipay@**山" title="Alipay@**山">

## 组件

| 名称            | 说明       | 名称            | 说明       | 名称            | 说明       |
| :-------------- | :--------- | :-------------- | :--------- | :-------------- | :--------- |
| Alert           | 警告提示   | AutoComplete    | 自动完成   | Avatar          | 头像       |
| BackTop         | 回到顶部   | Badge           | 徽标       | Breadcrumb      | 面包屑     |
| Button          | 按钮       | Calendar        | 日历       | Card            | 卡片       |
| Carousel        | 轮播图     | Cascader        | 级联选择   | Checkbox        | 复选框     |
| Collapse        | 折叠面板   | ColorPicker     | 颜色选择器 | Comment         | 评论       |
| ConfigProvider  | 全局化配置 | Countdown       | 倒计时     | DatePicker      | 日期选择器 |
| Descriptions    | 描述列表   | Dialog          | 对话框     | Divider         | 分割线     |
| Drawer          | 抽屉       | Dropdown        | 下拉菜单   | Ellipsis        | 文本省略   |
| Empty           | 空状态     | Flex            | 弹性布局   | FloatButton     | 浮动按钮   |
| GradientText    | 渐变文字   | Grid            | 栅格       | Highlight       | 高亮文本   |
| Image           | 图片       | Input           | 输入框     | InputNumber     | 数字输入框 |
| InputSearch     | 搜索框     | Layout          | 布局       | List            | 列表       |
| LoadingBar      | 加载条     | Menu            | 导航菜单   | Message         | 全局提示   |
| Modal           | 模态框     | Notification    | 通知提醒   | NumberAnimation | 数值动画   |
| Pagination      | 分页       | Popconfirm      | 弹出确认   | Popover         | 气泡卡片   |
| Progress        | 进度条     | QRCode          | 二维码     | Radio           | 单选框     |
| Rate            | 评分       | Result          | 结果       | Scrollbar       | 滚动条     |
| Segmented       | 分段控制器 | Select          | 选择器     | Skeleton        | 骨架屏     |
| Slider          | 滑动输入条 | Space           | 间距       | Spin            | 加载中     |
| Statistic       | 统计数值   | Steps           | 步骤条     | Swiper          | 触摸滑动   |
| Switch          | 开关       | Table           | 表格       | Tabs            | 标签页     |
| Tag             | 标签       | Textarea        | 文本域     | TextScroll      | 文字滚动   |
| Timeline        | 时间轴     | TimePicker      | 时间选择器 | Tooltip         | 文字提示   |
| Upload          | 上传       | Video           | 播放器     | Waterfall       | 瀑布流     |
| Watermark       | 水印       |                 |            |                 |            |

## 工具函数

| 名称 | 说明 | 类型 |
| :-- | :-- | :-- |
| dateFormat | 格式化日期时间字符串函数 | (value: number &#124; string &#124; Date = Date.now(), format: string = 'YYYY-MM-DD HH:mm:ss') => string |
| formatNumber | 数字格式化函数 | (value: number &#124; string, precision: number = 2, separator: string = ',', decimal: string = '.', prefix?: string, suffix?: string) => string |
| throttle | 节流函数 | (fn: Function, delay: number = 300) => Function |
| debounce | 防抖函数 | (fn: Function, delay: number = 300) => Function |
| add | 消除 `js` 加减精度问题的加法函数 | (num1: number, num2: number) => number |
| downloadFile | 下载文件并自定义文件名，内置同源 `anchor` 与跨域 `iframe` 双下载策略，未传 `fileName` 时，从文件地址中自动提取文件名称 | (url: string, fileName?: string, options?: { target?: '_self' &#124; '_blank'; strategy?: 'auto' &#124; 'anchor' &#124; 'iframe' }) => Promise&lt;void&gt; |
| useEventListener | 使用 `Vue` 的生命周期钩子添加和移除事件监听器 | (target: HTMLElement &#124; Window &#124; Document, event: string, callback: Function) => void |
| useMutationObserver | 使用 `MutationObserver` 观察 `DOM` 元素的变化 | (target: Ref &#124; Ref[] &#124; HTMLElement &#124; HTMLElement[], callback: MutationCallback, options: object = {}) => { start: \() => void, stop: \() => void } |
| useScroll | 实时监测滚动位置、方向与边界状态 | (target?: MaybeRefOrGetter\<HTMLElement &#124; Window &#124; Document &#124; null>, options?: UseScrollOptions) => { x: Ref\<number>, y: Ref\<number>, maxX: Ref\<number>, maxY: Ref\<number>, isScrolling: Ref\<boolean>, direction: Ref\<'left' &#124; 'right' &#124; 'top' &#124; 'bottom' &#124; null>, atLeft: Ref\<boolean>, atRight: Ref\<boolean>, atTop: Ref\<boolean>, atBottom: Ref\<boolean>, refresh: \() => void, start: \() => void, stop: \() => void } |
| useFps | 实时监测浏览器刷新率FPS | () => { fps: Ref\<number> } |
| useMediaQuery | 使用媒体查询来判断当前环境是否符合指定的媒体查询条件 | (mediaQuery: string) => { match: Ref\<boolean> } |
| useResizeObserver | 使用 `ResizeObserver` 观察 `DOM` 元素尺寸变化 | (target: Ref &#124; Ref[] &#124; HTMLElement &#124; HTMLElement[], callback: ResizeObserverCallback, options: object = {}) => { start: \() => void, stop: \() => void } |
| useSlotsExist | 监听给定名称或名称数组的插槽是否存在，支持监听单个插槽或一组插槽的存在 | <T extends string &#124; string[] = 'default'>(slotsName: T) => T extends string ? ComputedRef\<boolean> : Reactive\<Record\<string, boolean>> |
| useOptionsSupported | 检查浏览器是否支持给定的事件监听器选项 | (option: 'capture' &#124; 'once' &#124; 'passive' &#124; 'signal') => { isSupported: Ref\<boolean> } |
| getScrollParent | 向上查找元素最近的可滚动父元素函数 | (el: HTMLElement &#124; null) => HTMLElement &#124; null |
| useScrollParent | 查询并监听最近可滚动父元素，响应视口 `resize` 的组合式函数 | (contentRef: Ref\<HTMLElement &#124; null>, onScroll: () => void, options: ScrollParentOptions = {}) => { scrollTarget: Ref\<HTMLElement &#124; null>, viewportWidth: Ref\<number>, viewportHeight: Ref\<number>, observeScroll: \() => void, cleanup: \() => void } |
