Skip to content

Commit

Permalink
🎭 feat: use drawer hook
Browse files Browse the repository at this point in the history
  • Loading branch information
pdsuwwz committed Apr 16, 2024
1 parent 2eb31c8 commit 94c578f
Show file tree
Hide file tree
Showing 16 changed files with 432 additions and 35 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@



🏄‍♂️ A Starter template built on Vite 5.x + TypeScript + Vue 3.4 + Naive UI + Pinia + UnoCSS + Unplugin Auto Import.
🏄‍♂️ A Starter template built on Vite 5.x + TypeScript + TSX + Vue 3.4 + Naive UI + Pinia + UnoCSS + Unplugin Auto Import.

一个简洁的 Vite5 + Vue3.4 + TypeScript + ESLint(v9) 的 B 端后台原型 Naive UI 模板框架,内置 Pinia 模块化管理代码、路由鉴权、UnoCSS 暗黑模式、Unplugin 自动导入等, 开箱即用, 注重快速高效搭建实际业务场景, 持续更新最新技术栈 🎊
一个简洁的 Vite5 + Vue3.4 + TypeScript + TSX + ESLint(v9) 的 B 端后台原型 Naive UI 模板框架,内置 Pinia 模块化管理代码、路由鉴权、UnoCSS 暗黑模式、Unplugin 自动导入等, 开箱即用, 注重快速高效搭建实际业务场景, 持续更新最新技术栈 🎊

[🔥 Live Demo 在线体验](https://pdsuwwz.github.io/vite-naive-template)

Expand All @@ -33,7 +33,7 @@

## 🎉 Features

* 支持 __Vite 5 + Vue 3.4 + TypeScript__
* 支持 __Vite 5 + Vue 3.4 + TypeScript + TSX__
* UI 框架: __Naive UI 2.x__
* 状态管理: __Pinia__
* 单元测试框架: __Vitest__
Expand All @@ -42,7 +42,8 @@
* 内置 __ESlint____Stylelint__, 可在此基础上扩充你想要的 Lint 配置规范
* 内置封装了一个**可能比较好用的** Axios , 需要时配合 Pinia Actions 一起食用
* 封装了 \<IconFont \/> 组件, 可直接使用 IconFont 图标
* 服务式 service 挂载全局对象 [**window.$ModalXxxx**](https://github.com/pdsuwwz/vite-naive-template/blob/main/src/NaiveProvider.vue#L4-L7) 插件, 更方便的插件调用方式
* 简化了 naive-ui 库中[抽屉 drawer](https://www.naiveui.com/zh-CN/os-theme/components/drawer) 的创建过程, 支持全局调用 [window.$ModalDrawer.create](./src/components/Drawer/README.md) 方法管理多个抽屉
* 服务式 service 挂载全局对象 [**window.$ModalXxxx**](https://github.com/pdsuwwz/vite-naive-template/blob/main/src/NaiveProvider.vue#L6-L10) 插件, 更方便的插件调用方式
* 路由鉴权已帮你封装好,同时配合 Nprogress, 只需要修改 [permission.ts](./src/router/permission.ts) 文件即可
* 自带一个模块化的组件开发环境,可按照 modules 目录解耦页面组件、路由组件、样式等文件
* 高度封装但不失灵活,内部抽象出了一个完整的业务流程供你参考,涉及三个核心页面:登录、列表和明细
Expand Down
2 changes: 2 additions & 0 deletions components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ declare module 'vue' {
LayoutView: typeof import('./src/components/Layout/LayoutView.vue')['default']
NavBar: typeof import('./src/components/Navigation/NavBar.vue')['default']
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDatePicker: typeof import('naive-ui')['NDatePicker']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
Expand All @@ -30,6 +31,7 @@ declare module 'vue' {
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NSpace: typeof import('naive-ui')['NSpace']
NSpin: typeof import('naive-ui')['NSpin']
NSwitch: typeof import('naive-ui')['NSwitch']
NTooltip: typeof import('naive-ui')['NTooltip']
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"@typescript-eslint/eslint-plugin": "^7.5.0",
"@typescript-eslint/parser": "^7.5.0",
"@vitejs/plugin-vue": "^5.0.4",
"@vitejs/plugin-vue-jsx": "^3.1.0",
"@vitest/coverage-v8": "^1.4.0",
"@vue/compiler-sfc": "^3.4.21",
"@vue/test-utils": "2.4.5",
Expand Down
72 changes: 72 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 15 additions & 10 deletions src/NaiveProvider.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<script setup lang="ts">
import { DrawerProvider, useDrawer } from '@/components/Drawer'
function registerNaiveTools () {
window.$ModalMessage = useMessage()
window.$ModalNotification = useNotification()
window.$ModalDialog = useDialog()
window.$ModalLoadingBar = useLoadingBar()
window.$ModalDrawer = useDrawer()
}
const NaiveProviderWrapper = defineComponent({
Expand All @@ -19,14 +22,16 @@ const NaiveProviderWrapper = defineComponent({
</script>

<template>
<NLoadingBarProvider>
<NDialogProvider>
<NNotificationProvider>
<NMessageProvider>
<slot></slot>
<NaiveProviderWrapper />
</NMessageProvider>
</NNotificationProvider>
</NDialogProvider>
</NLoadingBarProvider>
<DrawerProvider>
<NLoadingBarProvider>
<NDialogProvider>
<NNotificationProvider>
<NMessageProvider>
<slot></slot>
<NaiveProviderWrapper />
</NMessageProvider>
</NNotificationProvider>
</NDialogProvider>
</NLoadingBarProvider>
</DrawerProvider>
</template>
36 changes: 36 additions & 0 deletions src/components/Drawer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
## $ModalDrawer 示例用法

```tsx
const inst = window.$ModalDrawer.create({
blockScroll: false,
title: '测试标题',
placement: 'left',
width: '70vw',
render: () => {
return <div>
<p>点击遮罩/右上角关闭按钮触发 onAsyncMaskClick</p>
<n-button onClick={() => inst.hide()}>直接关闭</n-button>
</div>
},
renderFooter: () => {
return <n-space>
<n-button
type='primary'
onClick={() => inst.hide()}
>
直接关闭
</n-button>
</n-space>
},
onAsyncMaskClick () {
// 异步处理
const loading = window.$ModalMessage.loading('异步关闭中')
return new Promise((resolve) => {
setTimeout(() => {
loading.destroy()
resolve()
}, 1000)
})
}
})
```
4 changes: 4 additions & 0 deletions src/components/Drawer/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { InjectionKey } from 'vue'
import { DrawerApiInjection } from './type'

export const drawerProviderInjectionKey: InjectionKey<DrawerApiInjection> = Symbol()
111 changes: 111 additions & 0 deletions src/components/Drawer/environment.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import {
type DrawerProps,
NDrawer,
NDrawerContent,
drawerProps
} from 'naive-ui'

interface DrawerExtraTypes {
/**
* 抽屉标题
*/
title: string

/**
* 抽屉内容渲染 VNode
* @example render: () => h(NButton)
*/
render?: () => VNode

/**
* 抽屉底部内容渲染 VNode
* @example renderFooter: () => h(NButton)
*/
renderFooter?: () => VNode

/**
* 点击遮罩/右上角关闭按钮触发的异步关闭回调
*/
onAsyncMaskClick?: () => Promise<void> | void
}

const propsDrawerExtraTypes = {
internalKey: {
type: String,
default: ''
},
title: {
type: String,
default: ''
},
render: {
type: Function as PropType<() => VNode>,
default() {
return () => <div></div>
}
},
renderFooter: {
type: Function as PropType<() => VNode>
},
onAsyncMaskClick: {
type: Function
},
onInternalAfterLeave: {
type: Function,
required: true
}
}


export type DrawerCreateOptions = DrawerProps & DrawerExtraTypes

export const DrawerEnvironment = defineComponent({
name: 'DrawerEnvironment',
props: {
...drawerProps,
...propsDrawerExtraTypes
},
setup(props) {

const visible = ref(false)
setTimeout(() => {
visible.value = true
})

const hideDrawer = async () => {
visible.value = false
Promise.resolve(() => {
props.onInternalAfterLeave!(props.internalKey)
})
}

return {
visible,
hideDrawer
}
},
render() {

return <NDrawer
{...this.$props}
show={this.visible}
autoFocus={false}
onUpdateShow={async () => {
await this.onAsyncMaskClick?.()
this.hideDrawer()
}}
>
<NDrawerContent
title={this.title}
closable
>
{{
default: () => this.render(),
footer: this.renderFooter
? () => this.renderFooter?.()
: undefined
}}
</NDrawerContent>
</NDrawer>
}
})
6 changes: 6 additions & 0 deletions src/components/Drawer/hook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { drawerProviderInjectionKey } from './context'

export function useDrawer() {
const drawerInstance = inject(drawerProviderInjectionKey)
return drawerInstance!
}
3 changes: 3 additions & 0 deletions src/components/Drawer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './context'
export * from './hook'
export * from './provider'
Loading

0 comments on commit 94c578f

Please sign in to comment.