This commit is contained in:
ray_wuhao 2023-06-24 20:09:20 +08:00
parent a82c042fe9
commit ed9fb0eb23
34 changed files with 546 additions and 53 deletions

View File

@ -1,5 +1,15 @@
# CHANGE LOG
## 3.3.7
### Feats
- 新增全局指令目前仅有v-copy、v-debounce、v-throttle
### Fixes
- 修复错误的插件命名导致项目构建失败viteComponents
## 3.3.6
### Feats

1
components.d.ts vendored
View File

@ -7,6 +7,7 @@ export {}
declare module '@vue/runtime-core' {
export interface GlobalComponents {
RayTransitionComponent: typeof import('./src/components/RayTransitionComponent/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
TransitionComponent: typeof import('./src/components/RayTransitionComponent/TransitionComponent.vue')['default']

View File

@ -22,6 +22,7 @@
"dependencies": {
"@vueuse/core": "^9.1.0",
"axios": "^1.2.0",
"clipboard": "^2.0.11",
"crypto-js": "^4.1.1",
"currency.js": "^2.0.4",
"dayjs": "^1.11.7",

View File

@ -24,8 +24,8 @@
import useRequest from '@/axios/instance'
interface AxiosTestResponse extends IUnknownObjectKey {
data: IUnknownObjectKey[]
interface AxiosTestResponse extends UnknownObjectKey {
data: UnknownObjectKey[]
city?: string
}

View File

@ -59,6 +59,7 @@ const RayCollapseGrid = defineComponent({
default: () => (
<NGrid
class="ray-collapse-grid"
{...this.$props}
collapsed={this.modelCollapsed}
xGap={this.xGap || 12}
yGap={this.yGap || 18}

View File

@ -1 +1 @@
export type CollapseToggleText = [string, string]
export type CollapseToggleText = [string | number, string | number]

38
src/directives/README.md Normal file
View File

@ -0,0 +1,38 @@
## 说明
> 全局自定义指令入口。
## 规范
- 指令应该为全局的通用性指令
- 如果指令需要与系统的数据进行关联,应该注意数据的管理与指令注册使用时机
## 添加指令说明
- 模板视 modules 中每一个文件包为一个模板的指令(全局),并且每个文件包的名称,也被视为该指令名称
- 添加文件包后,强制要求 index.ts 为指令的输出文件名
- modules 包中所有指令都会被自动合并到模板中
```ts
/**
*
* 示例添加 demo 指令
*/
// 1. modules 中添加文件包
// 2. modules/demo 目录下创建 index.ts 文件
// 3. 进行自定义指令开发
import type { Directive } from 'vue'
import type { RoleBindingValue } from './type'
const demoDirective: Directive<HTMLElement, RoleBindingValue> = {
beforeMount: (el, binding) => {
console.log(el, binding)
},
}
export default demoDirective
// 4. 按照上述步骤执行后,会自动在模板中创建一个 v-demo 的指令供全局使用
```

View File

@ -0,0 +1,137 @@
## 全局自定义指令
### v-copy
- 参数类型: any参数会强制被 String 方法转换)
- 默认值: ''
#### 示例
```tsx
import { NSpace, NCard, NInput, NInputGroup, NButton, NSwitch } from 'naive-ui'
const Demo = defineComponent({
name: 'Demo',
setup() {
const dmeoCopyValue = ref('hello copy')
return {
dmeoCopyValue,
}
},
render() {
return (
<NInputGroup>
<NInput v-model:value={this.dmeoCopyValue} />
<NButton v-copy={this.dmeoCopyValue}>复制</NButton>
</NInputGroup>
)
},
})
```
### v-debounce
- 参数类型: DebounceBindingOptions
- 默认值:
```ts
{
trigger: 'click',
wait: 500,
options: null
}
```
#### 示例
```tsx
import { NSpace, NCard, NInput, NInputGroup, NButton, NSwitch } from 'naive-ui'
const Demo = defineComponent({
name: 'Demo',
setup() {
const demoValue = ref(0)
const updateDemoValue = () => {
demoValue.value++
}
return {
demoValue,
updateDemoValue,
}
},
render() {
return (
<NSpace wrapItem={true} vertical>
<NButton
v-debounce={{
func: this.updateDemoValue,
trigger: 'click',
wait: 1000,
options: {},
}}
>
点击执行
</NButton>
<p>我执行了{this.demoValue}次</p>
<p>该方法将延迟 1s 执行</p>
</NSpace>
)
},
})
```
### v-throttle
- 参数类型: ThrottleBindingOptions
- 默认值:
```ts
{
trigger: 'click',
wait: 500,
options: null
}
```
#### 示例
```tsx
import { NSpace, NCard, NInput, NInputGroup, NButton, NSwitch } from 'naive-ui'
const Demo = defineComponent({
name: 'Demo',
setup() {
const demoValue = ref(0)
const updateDemoValue = () => {
demoValue.value++
}
return {
demoValue,
updateDemoValue,
}
},
render() {
return (
<NSpace wrapItem={true} vertical>
<NButton
v-throttle={{
func: this.updateDemoValue,
trigger: 'click',
wait: 1000,
options: {},
}}
>
点击执行
</NButton>
<p>我执行了{this.demoValue}次</p>
<p>该方法 1s 内仅会执行一次</p>
</NSpace>
)
},
})
```

View File

@ -0,0 +1,27 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
import type { Directive } from 'vue'
import type { DirectiveModules } from '@/directives/type'
export const mergerDirective = (
directiveModules: Record<string, DirectiveModules>,
) => {
const directives = Object.keys(directiveModules).reduce((pre, curr) => {
const value = directiveModules[curr].default
pre[curr] = value
return pre
}, {} as Record<string, Directive>)
return directives
}

31
src/directives/index.ts Normal file
View File

@ -0,0 +1,31 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
import { mergerDirective } from './helper/merger'
import { forIn } from 'lodash-es'
import type { App } from 'vue'
import type { DirectiveModules } from '@/directives/type'
/** 初始化全局自定义指令 */
export const setupDirective = (app: App<Element>) => {
const modules = import.meta.glob('./modules/**/index.ts', {
eager: true,
}) as Record<string, DirectiveModules>
const directives = mergerDirective(modules)
const reg = /(?<=modules\/).*(?=\/index\.ts)/
forIn(directives, (value, key) => {
const directiveName = key.match(reg)?.[0] as string
app.directive(directiveName, value)
})
}

View File

@ -0,0 +1,54 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
/**
*
* directive name: copy
*/
import ClipboardJS from 'clipboard'
import type { Directive } from 'vue'
import type { CopyElement } from './type'
let clipboard: ClipboardJS | null
const copyDirective: Directive<CopyElement, string> = {
mounted: (el, binding) => {
const value = binding.value
clipboard = new ClipboardJS(el, {
text: () => String(value),
})
clipboard?.on('success', () => {
window.$message.success('复制成功')
})
clipboard?.on('error', () => {
window.$message.error('复制失败')
})
},
updated: (el, binding) => {
/** 其实这块代码写的挺蠢的, 但是我目前不知道怎么去优化, 阿巴阿巴阿巴 */
const value = binding.value
clipboard = new ClipboardJS(el, {
text: () => String(value),
})
},
beforeUnmount: () => {
clipboard?.destroy()
clipboard = null
},
}
export default copyDirective

View File

@ -0,0 +1,3 @@
export interface CopyElement extends Element, UnknownObjectKey {
$value: string
}

View File

@ -0,0 +1,48 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
/**
*
* directive name: debounce
*/
import { debounce } from 'lodash-es'
import { on, off } from '@use-utils/element'
import type { Directive } from 'vue'
import type { DebounceBindingOptions } from './type'
let debounceFunction: AnyFunc | null
const debounceDirective: Directive<HTMLElement, DebounceBindingOptions> = {
beforeMount: (el, binding) => {
const { func, trigger = 'click', wait = 500, options } = binding.value
if (typeof func !== 'function') {
throw new Error('debounce directive value must be a function')
}
debounceFunction = debounce(func, wait, Object.assign({}, {}, options))
on(el, trigger, debounceFunction)
},
beforeUnmount: (el, binding) => {
const { trigger = 'click' } = binding.value
if (debounceFunction) {
off(el, trigger, debounceFunction)
}
debounceFunction = null
},
}
export default debounceDirective

View File

@ -0,0 +1,8 @@
import type { DebounceSettings } from 'lodash-es'
export interface DebounceBindingOptions {
func: AnyFunc
trigger: string
wait: number
options: DebounceSettings
}

View File

@ -0,0 +1,48 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
/**
*
* directive name: throttle
*/
import { throttle } from 'lodash-es'
import { on, off } from '@use-utils/element'
import type { Directive } from 'vue'
import type { ThrottleBindingOptions } from './type'
let throttleFunction: AnyFunc | null
const throttleDirective: Directive<HTMLElement, ThrottleBindingOptions> = {
beforeMount: (el, binding) => {
const { func, trigger = 'click', wait = 500, options } = binding.value
if (typeof func !== 'function') {
throw new Error('throttle directive value must be a function')
}
throttleFunction = throttle(func, wait, Object.assign({}, {}, options))
on(el, trigger, throttleFunction)
},
beforeUnmount: (el, binding) => {
const { trigger = 'click' } = binding.value
if (throttleFunction) {
off(el, trigger, throttleFunction)
}
throttleFunction = null
},
}
export default throttleDirective

View File

@ -0,0 +1,8 @@
import type { ThrottleSettings } from 'lodash-es'
export interface ThrottleBindingOptions {
func: AnyFunc
trigger: string
wait: number
options: ThrottleSettings
}

5
src/directives/type.ts Normal file
View File

@ -0,0 +1,5 @@
import type { Directive } from 'vue'
export interface DirectiveModules extends Object {
default: Directive
}

View File

@ -6,7 +6,7 @@ export interface IconEventMapOptions {
export type IconEventMap = keyof IconEventMapOptions
export interface IconDropdownOptions extends IUnknownObjectKey {
export interface IconDropdownOptions extends UnknownObjectKey {
event?: string
switch: boolean
options: DropdownOption[]

View File

@ -14,5 +14,6 @@
"Office_Document": "Document",
"Office_Presentation": "Presentation",
"Office_Spreadsheet": "Spreadsheet",
"CalculatePrecision": "Precision"
"CalculatePrecision": "Precision",
"Directive": "Directive"
}

View File

@ -14,5 +14,6 @@
"Office_Document": "文档",
"Office_Presentation": "演示",
"Office_Spreadsheet": "表格",
"CalculatePrecision": "数字精度"
"CalculatePrecision": "数字精度",
"Directive": "指令"
}

View File

@ -3,7 +3,6 @@ import type { App as AppType } from 'vue'
import '@/styles/base.scss'
import 'virtual:svg-icons-register' // `vite-plugin-svg-icons` 脚本, 如果不使用此插件注释即可
import 'dayjs/locale/zh-cn'
import App from './App'
@ -11,6 +10,7 @@ import { setupRouter } from './router/index'
import { setupStore } from './store/index'
import { setupI18n } from './locales/index'
import { setupDayjs } from './dayjs/index'
import { setupDirective } from './directives/index'
/**
*
@ -20,12 +20,10 @@ const setupTemplate = async () => {
const app = createApp(App)
await setupI18n(app)
await setupStore(app)
setupRouter(app)
setupDayjs()
setupDirective(app)
app.mount('#app')
}
@ -42,11 +40,8 @@ const setupWujieTemplate = async () => {
instance = createApp(App)
await setupI18n(instance)
await setupStore(instance)
setupRouter(instance)
setupDayjs()
instance.mount('#app')

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const axios: AppRouteRecordRaw = {
path: '/axios',
name: 'Axios',
name: 'RAxios',
component: () => import('@/views/axios/index'),
meta: {
i18nKey: t('menu.Axios'),

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const dashboard: AppRouteRecordRaw = {
path: '/dashboard',
name: 'Dashboard',
name: 'RDashboard',
component: () => import('@/views/dashboard/index'),
meta: {
i18nKey: t('menu.Dashboard'),

View File

@ -0,0 +1,16 @@
import { t } from '@/locales/useI18n'
import type { AppRouteRecordRaw } from '@/router/type'
const directive: AppRouteRecordRaw = {
path: '/directive',
name: 'RDirective',
component: () => import('@/views/directive/index'),
meta: {
i18nKey: t('menu.Directive'),
icon: 'rely',
order: 3,
},
}
export default directive

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const docLocal: AppRouteRecordRaw = {
path: '/doc',
name: 'DocLocal',
name: 'RDocLocal',
component: () => import('@/views/doc/index'),
meta: {
i18nKey: t('menu.DocLocal'),

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const doc: AppRouteRecordRaw = {
path: '/doc',
name: 'Doc',
name: 'RDoc',
component: () => import('@/views/doc/index'),
meta: {
i18nKey: t('menu.Doc'),

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const echart: AppRouteRecordRaw = {
path: '/echart',
name: 'Echart',
name: 'REchart',
component: () => import('@/views/echart/index'),
meta: {
i18nKey: t('menu.Echart'),

View File

@ -4,7 +4,7 @@ import type { AppRouteRecordRaw } from '@/router/type'
const office: AppRouteRecordRaw = {
path: '/office',
name: 'Office',
name: 'ROffice',
component: () => import('@/views/office/index'),
meta: {
i18nKey: t('menu.Office'),

View File

@ -6,7 +6,7 @@ import { LAYOUT } from '@/router/constant/index'
const rely: AppRouteRecordRaw = {
path: '/rely',
name: 'Rely',
name: 'RelyAbout',
component: LAYOUT,
meta: {
i18nKey: t('menu.Rely'),

View File

@ -1,15 +1,15 @@
export interface SigninForm extends IUnknownObjectKey {
export interface SigninForm extends UnknownObjectKey {
name: string
pwd: string
}
export interface SigninCallback extends IUnknownObjectKey {
export interface SigninCallback extends UnknownObjectKey {
role: string
name: string
avatar?: string
}
export interface SigninResponse extends IUnknownObjectKey {
export interface SigninResponse extends UnknownObjectKey {
code: number
data: SigninCallback
message: string

View File

@ -5,7 +5,7 @@ import type CryptoJS from 'crypto-js'
import type { VNodeChild } from 'vue'
export global {
declare interface IUnknownObjectKey {
declare interface UnknownObjectKey {
[propName: string]: any
}

View File

@ -15,7 +15,7 @@ const Axios = defineComponent({
name: 'RAxios',
setup() {
const state = reactive({
weatherData: [] as IUnknownObjectKey[],
weatherData: [] as UnknownObjectKey[],
inputCityValue: '',
})
const columns = [

View File

@ -0,0 +1,86 @@
/**
*
* @author Ray <https://github.com/XiaoDaiGua-Ray>
*
* @date 2023-06-24
*
* @workspace ray-template
*
* @remark
*/
import { NSpace, NCard, NInput, NInputGroup, NButton, NSwitch } from 'naive-ui'
const RDirective = defineComponent({
name: 'RDirective',
setup() {
const state = reactive({
copyValueOne: '我是待复制内容区域一',
copyValueTwo: '我是待复制内容区域二',
throttleBtnClickCount: 0,
debounceBtnClickCount: 0,
})
const updateDemoValue = (key: keyof typeof state) => {
state[key]++
}
return {
...toRefs(state),
updateDemoValue,
}
},
render() {
return (
<NSpace wrapItem={false}>
<NCard title="指令示代码">使</NCard>
<NCard title="文本复制示例一">
<NInputGroup>
<NInput v-model:value={this.copyValueOne} />
<NButton v-copy={this.copyValueOne}></NButton>
</NInputGroup>
</NCard>
<NCard title="文本复制示例二">
<NInputGroup>
<NInput v-model:value={this.copyValueTwo} />
<NButton v-copy={this.copyValueTwo}></NButton>
</NInputGroup>
</NCard>
<NCard title="节流指令">
<NSpace wrapItem={true} vertical>
<NButton
v-throttle={{
func: this.updateDemoValue.bind(null, 'throttleBtnClickCount'),
trigger: 'click',
wait: 1000,
options: {},
}}
>
</NButton>
<p>{this.throttleBtnClickCount}</p>
<p> 1s </p>
</NSpace>
</NCard>
<NCard title="防抖指令">
<NSpace wrapItem={true} vertical>
<NButton
v-debounce={{
func: this.updateDemoValue.bind(null, 'debounceBtnClickCount'),
trigger: 'click',
wait: 1000,
options: {},
}}
>
</NButton>
<p>{this.debounceBtnClickCount}</p>
<p> 1s </p>
</NSpace>
</NCard>
</NSpace>
)
},
})
export default RDirective

View File

@ -1,7 +1,7 @@
import path from 'node:path'
import autoImport from 'unplugin-auto-import/vite' // 自动导入
import viteComponents from 'unplugin-vue-components/vite' // 自动按需导入
import unpluginViteComponents from 'unplugin-vue-components/vite' // 自动按需导入
import vueI18nPlugin from '@intlify/unplugin-vue-i18n/vite' // i18n
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons' // `svg icon`
@ -57,7 +57,7 @@ export const viteComponents = async (
resolvers: (ComponentResolver | ComponentResolver[])[] = [],
types: TypeImport[] = [],
) =>
viteComponents({
unpluginViteComponents({
dts: true,
resolvers: [...resolvers],
types: [
@ -131,32 +131,6 @@ export const buildOptions = (mode: string): BuildOptions => {
}
}
/**
*
* @param options
*
* @remark console debugger , console ,
* @remark console , 使
*/
export const useViteBuildPlugin = (options?: BuildOptions) => {
const defaultPlugin: BuildOptions = {
outDir: 'dist', // 打包后文件输出路径
assetsDir: 'assets', // 指定静态资源存放路径
assetsInlineLimit: 4096, // 小于这个数字(字节)的静态资产文件将被内联为(base64)
cssCodeSplit: true, // 拆分css代码
minify: 'esbuild', // 指定使用混淆器 (terser | esbuild)
sourcemap: false,
terserOptions: {
compress: {
drop_console: true, // 打包后移除console
drop_debugger: true, // 打包后移除debugger
},
},
}
return Object.assign({}, defaultPlugin, options)
}
/**
*
* @param options css