perf: improve modal and drawer component documentation and fix known problems (#4264)

* feat: improve modal and drawer component documentation and fix known problems

* chore: update ci
This commit is contained in:
Vben
2024-08-28 22:26:35 +08:00
committed by GitHub
parent 84816ef769
commit 36e7ca19a1
54 changed files with 882 additions and 176 deletions

View File

@@ -154,7 +154,11 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
items: [
{
link: 'common-ui/vben-modal',
text: 'Modal 弹窗',
text: 'Vben Modal 模态框',
},
{
link: 'common-ui/vben-drawer',
text: 'Vben Drawer 抽屉',
},
],
},

View File

@@ -0,0 +1,108 @@
---
outline: deep
---
# Vben Drawer 抽屉
框架提供的抽屉组件,支持`自动高度``loading`等功能。
## 基础用法
使用 `useVbenDrawer` 创建最基础的模态框。
<DemoPreview dir="demos/vben-drawer/basic" />
## 组件抽离
Drawer 内的内容一般业务中,会比较复杂,所以我们可以将 drawer 内的内容抽离出来,也方便复用。通过 `connectedComponent` 参数,可以将内外组件进行连接,而不用其他任何操作。
<DemoPreview dir="demos/vben-drawer/extra" />
## 自动计算高度
弹窗会自动计算内容高度,超过一定高度会出现滚动条,同时结合 `loading` 效果以及使用 `prepend-footer` 插槽。
<DemoPreview dir="demos/vben-drawer/auto-height" />
## 使用 Api
通过 `drawerApi` 可以调用 drawer 的方法以及使用 `setState` 更新 drawer 的状态。
<DemoPreview dir="demos/vben-drawer/dynamic" />
## 数据共享
如果你使用了 `connectedComponent` 参数,那么内外组件会共享数据,比如一些表单回填等操作。可以用 `drawerApi` 来获取数据和设置数据,配合 `onOpenChange`,可以满足大部分的需求。
<DemoPreview dir="demos/vben-drawer/shared-data" />
::: info 注意
- `VbenDrawer` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenDrawer参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenDrawer`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onComfirm`,那么以内部的 `onComfirm` 为准。`onOpenChange`事件除外,内外都会触发。
:::
## API
```ts
// Drawer 为弹窗组件
// drawerApi 为弹窗的方法
const [Drawer, drawerApi] = useVbenDrawer({
// 属性
// 事件
});
```
### Props
所有属性都可以传入 `useVbenDrawer` 的第一个参数中。
| 属性名 | 描述 | 类型 | 默认值 |
| ------------------ | ------------------- | --------------- | ------- |
| title | 标题 | `string\|slot` | - |
| titleTooltip | 标题提示信息 | `string\|slot` | - |
| description | 描述信息 | `string\|slot` | - |
| isOpen | 弹窗打开状态 | `boolean` | `false` |
| loading | 弹窗加载状态 | `boolean` | `false` |
| closable | 显示关闭按钮 | `boolean` | `true` |
| modal | 显示遮罩 | `boolean` | `true` |
| header | 显示header | `boolean` | `true` |
| footer | 显示footer | `boolean\|slot` | `true` |
| confirmLoading | 确认按钮loading状态 | `boolean` | `false` |
| closeOnClickModal | 点击遮罩关闭弹窗 | `boolean` | `true` |
| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |
| confirmText | 确认按钮文本 | `boolean\|slot` | `确认` |
| cancelText | 取消按钮文本 | `boolean\|slot` | `取消` |
### Event
以下事件,只有在 `useVbenDrawer({onCancel:()=>{}})` 中传入才会生效。
| 事件名 | 描述 | 类型 |
| --- | --- | --- |
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` |
| onCancel | 点击取消按钮触发 | `()=>void` |
| onConfirm | 点击确认按钮触发 | `()=>void` |
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` |
### Slots
除了上面的属性类型包含`slot`,还可以通过插槽来自定义弹窗的内容。
| 插槽名 | 描述 |
| -------------- | ------------------- |
| default | 默认插槽 - 弹窗内容 |
| prepend-footer | 取消按钮左侧 |
| append-footer | 取消按钮右侧 |
### modalApi
| 事件名 | 描述 | 类型 |
| --- | --- | --- |
| setState | 动态设置弹窗状态属性 | `setState(props) \| setState((prev)=>(props))` |
| open | 打开弹窗 | `()=>void` |
| close | 关闭弹窗 | `()=>void` |
| setData | 设置共享数据 | `<T>(data:T)=>void` |
| getData | 获取共享数据 | `<T>()=>T` |
| useStore | 获取可响应式状态 | - |

View File

@@ -2,44 +2,117 @@
outline: deep
---
# vben-modal
# Vben Modal 模态框
::: tip
文档还在完善中,敬请期待。
:::
框架提供的模态框组件,支持`拖拽``全屏``自定义`等功能。
框架提供的模态框组件,支持`拖拽``全屏``自动高度``loading`等功能。
## 基础用法
使用 `useVbenModal` 创建最基的模态框。
使用 `useVbenModal` 创建最基的模态框。
<DemoPreview dir="demos/vben-modal/basic" />
## 组件抽离
modal 内的内容一般业务中,会比较复杂,所以我们可以将 modal 内的内容抽离出来。
Modal 内的内容一般业务中,会比较复杂,所以我们可以将 modal 内的内容抽离出来,也方便复用。通过 `connectedComponent` 参数,可以将内外组件进行连接,而不用其他任何操作
<DemoPreview dir="demos/vben-modal/extra" />
## 开启拖拽
通过 `draggable` 参数,可开启拖拽功能。
<DemoPreview dir="demos/vben-modal/draggable" />
## 自动计算高度
弹窗会自动计算内容高度,超过一定高度会出现滚动条,同时结合 `loading` 效果以及使用 `prepend-footer` 插槽。
<DemoPreview dir="demos/vben-modal/auto-height" />
## 使用 Api
通过 `modalApi` 可以调用 modal 的方法以及使用 `setState` 更新 modal 的状态。
<DemoPreview dir="demos/vben-modal/dynamic" />
## 数据共享
如果你使用了 `connectedComponent` 参数,那么内外组件会共享数据,比如一些表单回填等操作。可以用 `modalApi` 来获取数据和设置数据,配合 `onOpenChange`,可以满足大部分的需求。
<DemoPreview dir="demos/vben-modal/shared-data" />
::: info 注意
- `VbenModal` 组件对与参数的处理优先级是 `slot` > `props` > `state`(通过api更新的状态以及useVbenModal参数)。如果你已经传入了 `slot` 或者 `props`,那么 `setState` 将不会生效,这种情况下你可以通过 `slot` 或者 `props` 来更新状态。
- 如果你使用到了 `connectedComponent` 参数,那么会存在 2 个`useVbenModal`, 此时,如果同时设置了相同的参数,那么以内部为准(也就是没有设置 connectedComponent 的代码)。比如 同时设置了 `onComfirm`,那么以内部的 `onComfirm` 为准。`onOpenChange`事件除外,内外都会触发。
:::
## API
### 属性
```ts
// Modal 为弹窗组件
// modalApi 为弹窗的方法
const [Modal, modalApi] = useVbenModal({
// 属性
// 事件
});
```
| 属性名 | 描述 | 类型 | 默认值 |
| ------ | ----- | -------- | ------ |
| title | 标题. | `string` | — |
### Props
### 事件
所有属性都可以传入 `useVbenModal` 的第一个参数中。
| 属性名 | 描述 | 类型 | 默认值 |
| ------------------ | ------------------- | --------------- | ------- |
| title | 标题 | `string\|slot` | - |
| titleTooltip | 标题提示信息 | `string\|slot` | - |
| description | 描述信息 | `string\|slot` | - |
| isOpen | 弹窗打开状态 | `boolean` | `false` |
| loading | 弹窗加载状态 | `boolean` | `false` |
| fullscreen | 全屏显示 | `boolean` | `false` |
| fullscreenButton | 显示全屏按钮 | `boolean` | `true` |
| draggable | 可拖拽 | `boolean` | `false` |
| closable | 显示关闭按钮 | `boolean` | `true` |
| centered | 居中显示 | `boolean` | `false` |
| modal | 显示遮罩 | `boolean` | `true` |
| header | 显示header | `boolean` | `true` |
| footer | 显示footer | `boolean\|slot` | `true` |
| confirmLoading | 确认按钮loading状态 | `boolean` | `false` |
| closeOnClickModal | 点击遮罩关闭弹窗 | `boolean` | `true` |
| closeOnPressEscape | esc 关闭弹窗 | `boolean` | `true` |
| confirmText | 确认按钮文本 | `boolean\|slot` | `确认` |
| cancelText | 取消按钮文本 | `boolean\|slot` | `取消` |
### Event
以下事件,只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。
| 事件名 | 描述 | 类型 |
| ------ | ---- | ---- |
| TODO | TODO | TODO |
| --- | --- | --- |
| onBeforeClose | 关闭前触发,返回 `false`则禁止关闭 | `()=>boolean` |
| onCancel | 点击取消按钮触发 | `()=>void` |
| onConfirm | 点击确认按钮触发 | `()=>void` |
| onOpenChange | 关闭或者打开弹窗时触发 | `(isOpen:boolean)=>void` |
### 插槽
### Slots
| 插槽名 | 描述 |
| ------- | ---- |
| default | xx. |
除了上面的属性类型包含`slot`,还可以通过插槽来自定义弹窗的内容。
| 插槽名 | 描述 |
| -------------- | ------------------- |
| default | 默认插槽 - 弹窗内容 |
| prepend-footer | 取消按钮左侧 |
| append-footer | 取消按钮右侧 |
### modalApi
| 事件名 | 描述 | 类型 |
| --- | --- | --- |
| setState | 动态设置弹窗状态属性 | `setState(props) \| setState((prev)=>(props))` |
| open | 打开弹窗 | `()=>void` |
| close | 关闭弹窗 | `()=>void` |
| setData | 设置共享数据 | `<T>(data:T)=>void` |
| getData | 获取共享数据 | `<T>()=>T` |
| useStore | 获取可响应式状态 | - |

View File

@@ -1,6 +1,6 @@
# 介绍
::: tip README
::: info README
该文档介绍的是框架组件的使用方法、属性、事件等。如果你觉得组件封装的不好,或者不符合你的需求,你可以直接使用原生的组件,或者自己封装一个组件,不需要拘泥于框架提供的组件。我们只是提供了一些常用的组件,方便你快速开发。是否使用,取决于你的需求。

View File

@@ -0,0 +1,45 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
const list = ref<number[]>([]);
const [Drawer, drawerApi] = useVbenDrawer({
onCancel() {
drawerApi.close();
},
onConfirm() {
console.log('onConfirm');
},
onOpenChange(isOpen) {
if (isOpen) {
handleUpdate(10);
}
},
});
function handleUpdate(len: number) {
drawerApi.setState({ loading: true });
setTimeout(() => {
list.value = Array.from({ length: len }, (_v, k) => k + 1);
drawerApi.setState({ loading: false });
}, 2000);
}
</script>
<template>
<Drawer title="自动计算高度">
<div
v-for="item in list"
:key="item"
class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
>
{{ item }}
</div>
<template #prepend-footer>
<VbenButton type="link" @click="handleUpdate(6)">
点击更新数据
</VbenButton>
</template>
</Drawer>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
import ExtraDrawer from './drawer.vue';
const [Drawer, drawerApi] = useVbenDrawer({
// 连接抽离的组件
connectedComponent: ExtraDrawer,
});
function open() {
drawerApi.open();
}
</script>
<template>
<div>
<Drawer />
<VbenButton @click="open">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,11 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
const [Drawer, drawerApi] = useVbenDrawer();
</script>
<template>
<div>
<VbenButton @click="() => drawerApi.open()">Open</VbenButton>
<Drawer class="w-[600px]" title="基础示例"> drawer content </Drawer>
</div>
</template>

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
const [Drawer, drawerApi] = useVbenDrawer({
onCancel() {
drawerApi.close();
},
onConfirm() {
console.info('onConfirm');
},
title: '动态修改配置示例',
});
function handleUpdateTitle() {
drawerApi.setState({ title: '内部动态标题' });
}
</script>
<template>
<Drawer>
<div class="flex-col-center">
<VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
内部动态修改标题
</VbenButton>
</div>
</Drawer>
</template>

View File

@@ -0,0 +1,30 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
import ExtraDrawer from './drawer.vue';
const [Drawer, drawerApi] = useVbenDrawer({
// 连接抽离的组件
connectedComponent: ExtraDrawer,
});
function open() {
drawerApi.open();
}
function handleUpdateTitle() {
drawerApi.setState({ title: '外部动态标题' });
drawerApi.open();
}
</script>
<template>
<div>
<Drawer />
<VbenButton @click="open">Open</VbenButton>
<VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
从外部修改标题并打开
</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,8 @@
<script lang="ts" setup>
import { useVbenDrawer } from '@vben/common-ui';
const [Drawer] = useVbenDrawer();
</script>
<template>
<Drawer title="组件抽离示例"> extra drawer content </Drawer>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
import ExtraDrawer from './drawer.vue';
const [Drawer, drawerApi] = useVbenDrawer({
// 连接抽离的组件
connectedComponent: ExtraDrawer,
});
function open() {
drawerApi.open();
}
</script>
<template>
<div>
<Drawer />
<VbenButton @click="open">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
const data = ref();
const [Drawer, drawerApi] = useVbenDrawer({
onCancel() {
drawerApi.close();
},
onConfirm() {
console.info('onConfirm');
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = drawerApi.getData<Record<string, any>>();
}
},
});
</script>
<template>
<Drawer title="数据共享示例">
<div class="flex-col-center">外部传递数据 {{ data }}</div>
</Drawer>
</template>

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { useVbenDrawer, VbenButton } from '@vben/common-ui';
import ExtraDrawer from './drawer.vue';
const [Drawer, drawerApi] = useVbenDrawer({
// 连接抽离的组件
connectedComponent: ExtraDrawer,
});
function open() {
drawerApi.setData({
content: '外部传递的数据 content',
payload: '外部传递的数据 payload',
});
drawerApi.open();
}
</script>
<template>
<div>
<Drawer />
<VbenButton @click="open">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import { useVbenModal, VbenButton } from '@vben/common-ui';
import ExtraModal from './modal.vue';
const [Modal, modalApi] = useVbenModal({
// 连接抽离的组件
connectedComponent: ExtraModal,
});
function openModal() {
modalApi.open();
}
</script>
<template>
<div>
<Modal />
<VbenButton @click="openModal">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,45 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal, VbenButton } from '@vben/common-ui';
const list = ref<number[]>([]);
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
onConfirm() {
console.log('onConfirm');
},
onOpenChange(isOpen) {
if (isOpen) {
handleUpdate(10);
}
},
});
function handleUpdate(len: number) {
modalApi.setState({ loading: true });
setTimeout(() => {
list.value = Array.from({ length: len }, (_v, k) => k + 1);
modalApi.setState({ loading: false });
}, 2000);
}
</script>
<template>
<Modal title="自动计算高度">
<div
v-for="item in list"
:key="item"
class="even:bg-heavy bg-muted flex-center h-[220px] w-full"
>
{{ item }}
</div>
<template #prepend-footer>
<VbenButton type="link" @click="handleUpdate(6)">
点击更新数据
</VbenButton>
</template>
</Modal>
</template>

View File

@@ -5,7 +5,7 @@ const [Modal, modalApi] = useVbenModal();
</script>
<template>
<div>
<VbenButton @click="() => modalApi.open()">打开弹窗</VbenButton>
<Modal title="基础示例"> modal content </Modal>
<VbenButton @click="() => modalApi.open()">Open</VbenButton>
<Modal class="w-[600px]" title="基础示例"> modal content </Modal>
</div>
</template>

View File

@@ -0,0 +1,21 @@
<script lang="ts" setup>
import { useVbenModal, VbenButton } from '@vben/common-ui';
import ExtraModal from './modal.vue';
const [Modal, modalApi] = useVbenModal({
// 连接抽离的组件
connectedComponent: ExtraModal,
});
function openModal() {
modalApi.open();
}
</script>
<template>
<div>
<Modal />
<VbenButton @click="openModal">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,10 @@
<script lang="ts" setup>
import { useVbenModal } from '@vben/common-ui';
const [Modal] = useVbenModal({
draggable: true,
});
</script>
<template>
<Modal title="拖拽示例"> modal content </Modal>
</template>

View File

@@ -0,0 +1,30 @@
<script lang="ts" setup>
import { useVbenModal, VbenButton } from '@vben/common-ui';
import ExtraModal from './modal.vue';
const [Modal, modalApi] = useVbenModal({
// 连接抽离的组件
connectedComponent: ExtraModal,
});
function openModal() {
modalApi.open();
}
function handleUpdateTitle() {
modalApi.setState({ title: '外部动态标题' });
modalApi.open();
}
</script>
<template>
<div>
<Modal />
<VbenButton @click="openModal">Open</VbenButton>
<VbenButton class="ml-2" type="primary" @click="handleUpdateTitle">
从外部修改标题并打开
</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,38 @@
<script lang="ts" setup>
import { useVbenModal, VbenButton } from '@vben/common-ui';
const [Modal, modalApi] = useVbenModal({
draggable: true,
onCancel() {
modalApi.close();
},
onConfirm() {
console.info('onConfirm');
},
title: '动态修改配置示例',
});
const state = modalApi.useStore();
function handleUpdateTitle() {
modalApi.setState({ title: '内部动态标题' });
}
function handleToggleFullscreen() {
modalApi.setState((prev) => {
return { ...prev, fullscreen: !prev.fullscreen };
});
}
</script>
<template>
<Modal>
<div class="flex-col-center">
<VbenButton class="mb-3" type="primary" @click="handleUpdateTitle()">
内部动态修改标题
</VbenButton>
<VbenButton class="mb-3" @click="handleToggleFullscreen()">
{{ state.fullscreen ? '退出全屏' : '打开全屏' }}
</VbenButton>
</div>
</Modal>
</template>

View File

@@ -4,7 +4,7 @@ import { useVbenModal, VbenButton } from '@vben/common-ui';
import ExtraModal from './modal.vue';
const [Modal, modalApi] = useVbenModal({
// 接抽离的组件
// 接抽离的组件
connectedComponent: ExtraModal,
});
@@ -16,7 +16,6 @@ function openModal() {
<template>
<div>
<Modal />
<VbenButton @click="openModal">打开弹窗</VbenButton>
<VbenButton @click="openModal">Open</VbenButton>
</div>
</template>

View File

@@ -4,5 +4,5 @@ import { useVbenModal } from '@vben/common-ui';
const [Modal] = useVbenModal();
</script>
<template>
<Modal title="基础示例"> extra modal content </Modal>
<Modal title="组件抽离示例"> extra modal content </Modal>
</template>

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { useVbenModal, VbenButton } from '@vben/common-ui';
import ExtraModal from './modal.vue';
const [Modal, modalApi] = useVbenModal({
// 连接抽离的组件
connectedComponent: ExtraModal,
});
function openModal() {
modalApi.setData({
content: '外部传递的数据 content',
payload: '外部传递的数据 payload',
});
modalApi.open();
}
</script>
<template>
<div>
<Modal />
<VbenButton @click="openModal">Open</VbenButton>
</div>
</template>

View File

@@ -0,0 +1,26 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
const data = ref();
const [Modal, modalApi] = useVbenModal({
onCancel() {
modalApi.close();
},
onConfirm() {
console.info('onConfirm');
},
onOpenChange(isOpen: boolean) {
if (isOpen) {
data.value = modalApi.getData<Record<string, any>>();
}
},
});
</script>
<template>
<Modal title="数据共享示例">
<div class="flex-col-center">外部传递数据 {{ data }}</div>
</Modal>
</template>

View File

@@ -72,6 +72,8 @@ pnpm install
### 运行项目
#### 选择项目
执行以下命运行项目:
```bash
@@ -84,12 +86,24 @@ pnpm dev
```bash
◆ Select the app you need to run [dev]:
@vben/web-antd
@vben/web-antd
│ ○ @vben/web-ele
│ ○ @vben/web-naive
│ ○ @vben/docs
@vben/playground
@vben/playground
```
现在,你可以在浏览器访问 `http://localhost:5555` 查看项目。
#### 运行指定项目
如果你不想选择项目,可以直接运行以下命令运行你需要的应用:
```bash
pnpm run dev:antd
pnpm run dev:ele
pnpm run dev:naive
pnpm run dev:docs
pnpm run dev:play
```

View File

@@ -2,27 +2,27 @@
::: info 你正在阅读的是 [Vben Admin](https://github.com/vbenjs/vue-vben-admin) `5.0`版本的文档!
- Vben Admin 2.x 目前已存档,只修复一些严重的问题
- Vben Admin 2.x 目前已存档,仅进行重大问题修复
- 新版本与旧版本不兼容如果你使用的是旧版本v2、v3请查看 [Vue Vben Admin 2.x 文档](https://doc.vvbin.cn)
- 如发现文档有误,欢迎提Issue 帮助我们改进。
- 如果你只是想体验一下,你可以查看 [快速开始](./quick-start.md)。
- 如发现文档有误,欢迎提交 [issue](https://github.com/vbenjs/vue-vben-admin/issues) 帮助我们改进。
- 如果你只是想体验一下,你可以查看[快速开始](./quick-start.md)。
:::
[Vben Admin](https://github.com/vbenjs/vue-vben-admin) 是一个基于 [Vue3.0](https://github.com/vuejs/core)、[Vite](https://github.com/vitejs/vite)、 [TypeScript](https://www.typescriptlang.org/) 的后台解决方案目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈可以作为项目的启动模,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 `vue3``vite``ts` 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
[Vben Admin](https://github.com/vbenjs/vue-vben-admin) 是一个基于 [Vue3.0](https://github.com/vuejs/core)、[Vite](https://github.com/vitejs/vite)、 [TypeScript](https://www.typescriptlang.org/) 的后台解决方案目标是为开发中大型项目提供开箱即用的解决方案。包括二次封装组件、utils、hooks、动态菜单、权限校验、多主题配置、按钮级别权限控制等功能。项目会使用前端较新的技术栈可以作为项目的启动模,以帮助你快速搭建企业级中后台产品原型。也可以作为一个示例,用于学习 `vue3``vite``ts` 等主流技术。该项目会持续跟进最新技术,并将其应用在项目中。
## 特点
- **最新技术栈**:使用 `Vue3``Vite``TypeScript` 等前端前沿技术开发。
- **国际化**:内置完善的国际化方案,支持多语言切换。
- **权限验证**:完善的权限验证方案,按钮级别权限控制。
- **多主题**:内置多种主题配置&黑暗模式,满足个性化需求。
- **多主题**:内置多种主题配置黑暗模式,满足个性化需求。
- **动态菜单**:支持动态菜单,可以根据权限配置显示菜单。
- **Mock 数据**:基于 Nitro 的本地高性能 Mock 数据方案。
- **组件丰富**:提供了丰富的组件,可以满足大部分的业务需求。
- **规范**:代码规范,使用 `ESLint``Prettier``Stylelint``Publint``CSpell` 等工具保证代码质量。
- **工程化**:使用 `Pnpm Monorepo``TurboRepo``Changeset` 等工具,提高开发效率。
- **多UI库支持**:支持 `Ant Design Vue``Element Plus``Vuetify` 等主流 UI 库,不再限制于特定框架。
- **多UI库支持**:支持 `Ant Design Vue``Element Plus``Naive` 等主流 UI 库,不再限制于特定框架。
## 浏览器支持
@@ -32,17 +32,15 @@
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png" alt="IE" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)IE | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt=" Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)Safari |
| :-: | :-: | :-: | :-: | :-: |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
| 不支持 | last 2 versions | last 2 versions | last 2 versions | last 2 versions |
## 贡献
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) 还在持续更新中,本项目欢迎您的参与,共同维护,逐步完善,打造更好的中后台解决方案。
- 如果你想加入我们,可以提供一些好的建议或者提交 pr,我们会根据你的活跃度邀请你加入。
- 如果你想加入我们,可以提供有价值的建议或者参与讨论,协助解决 issue- 如果你想加入我们,可以提供有价值的建议或者参与讨论,协助解决 issue,我们会根据你的活跃度邀请你加入。
::: info 加入我们
如果你想加入我们,你可以从以下几个方面开始,我们会根据你的活跃度邀请你加入:
- 长期提交 `PR`
- 提供一些好的建议。
- 参与讨论,帮助解决一些 `issue`

View File

@@ -1,9 +1,23 @@
# 为什么选择我们?
首先,我们不会去和其他框架做比较。我们认为每个框架都有自己的特点,适合不同的场景。我们的目标是提供一个简单、易用的框架,让开发者可以快速上手,专注于业务逻辑的开发。所以我们只会不断完善和优化我们的框架,提供更好的体验。
::: info 写在前面
我们不会去和其他框架做比较。我们认为每个框架都有自己的特点,适合不同的场景。我们的目标是提供一个简单、易用的框架,让开发者可以快速上手,专注于业务逻辑的开发。所以我们只会不断完善和优化我们的框架,提供更好的体验。
:::
我们致力于为开发者提供一个高效、现代、易用的前端框架。我们的解决方案基于最新的技术栈,如 Vue3、Vite 和 TypeScript确保您在构建项目时始终走在技术的前沿。同时我们注重代码的质量与规范通过严格的工具链保证代码的一致性和可维护性。无论是初创项目还是企业级应用我们的框架都能帮助您快速构建、迭代和部署。
## 框架历程
从 Vue Vben Admin 1.x 版本开始,框架经历了许多迭代和优化。从一开始使用 `Vite 0.x` 版本,没有现成的插件,开发了很多自定义插件来弥合 Webpack 和 Vite 之间的差异。虽然很多现在已经被代替,但是我们的初衷一直没有变,就是提供一个简单、易用的框架。
虽然中间有段时间由社区维护,但我们一直密切关注 Vue Vben Admin 的发展。见证了许多开发者使用 Vben Admin并提供了许多宝贵的建议和反馈。非常感谢大家的支持和贡献这些都是我们持续改进 Vben Admin 的动力。新版本中,我们持续收集用户反馈,重新开始,不断优化框架,以提供更好的用户体验。我们的目标是让开发者能够快速上手,专注于业务逻辑的开发。
## 单元测试
单元测试是确保代码质量的基石。在开发过程中编写和执行单元测试,以捕捉潜在的错误并提升代码的可靠性。框架核心逻辑使用 `vitest` 做了单元测试,并在逐步增加覆盖率。通过单元测试,可以放心地进行代码重构,减少回归问题,从而提高整体开发效率。
## 质量与规范
我们始终高度重视代码的质量与规范。通过使用 ESLint、Prettier、Stylelint、Publint、CSpell 等工具来确保代码质量。我们的代码规范基于 Vue3、Vite、TypeScript 等现代前端技术制定,旨在提供一个简洁、易用的框架,使开发者能够快速上手并专注于业务逻辑的开发。