You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

464 lines
7.8 KiB

---
description: module | plugins 模块、插件
globs:
---
# 模块/插件开发
## 目录结构
在 `src/modules` 或 `src/plugins` 下添加一个目录 `demo`:
```js
demo
├──pages // 页面路由
├──views // 视图路由
├──hooks // 常用函数
├──components // 常用组件
├──directives // 指令
├──static // 静态文件目录
├──store // 状态管理
├──... // 其他自定义文件
├──config.ts // 配置文件
└──index.ts // 入口文件
```
::: warning
约定的目录名称不可修改,但可自行添加或者删除。
:::
## pages、views
1. 页面参与权限控制,所以不主动注册目录下的路由,通过 `菜单列表` 中配置注册。或者在 `config.ts` 中手动配置:
```js
import { type ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
views: [
{
path: "/demo",
meta: {
label: "测试",
},
component: () => import("./views/demo.vue"),
},
],
pages: [
{
path: "/demo2",
meta: {
label: "测试",
},
component: () => import("./pages/demo.vue"),
},
],
};
};
```
2. 使页面参与路由缓存,配置 `name` 参数
:::warning
`path` 与 `name` 的匹配规则:
- /demo/t1 = demo-t1
- /demo/t1-det = demo-t1-det
:::
方式 1:
```html
<script lang="ts" setup>
defineOptions({
name: "demo",
});
</script>
```
方式 2:
```html
<script lang="ts">
export default defineComponent({
name: "demo",
});
</script>
```
## components
目录下的组件,全局注册配置方法如下:
```js
import { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
components: [
import("./components/demo.vue"),
import("./components/demo1.vue"),
],
};
};
```
## directives
`directives` 会以目录下的文件名分别注册指令
```ts
// demo/directives/test.ts
export default {
created(el, binding) {},
mounted() {},
...
};
```
使用
```html
<div v-test></div>
```
## store
使用 `pinia` 的推荐写法:
```ts
import { defineStore } from "pinia";
import { ref } from "vue";
export const useTestStore = defineStore("test", function () {
const count = ref(0);
function add() {
count.value += 1;
}
return {
count,
add,
};
});
```
使用
```ts
import { useTestStore } from "/$/demo/store";
const test = useTestStore();
test.add();
console.log(test.count); // 1
```
::: tip
参考 `base` 模块下 `store` 的导出方式
:::
## config.ts
模块的配置,程序运行时会读取该文件。
- 全局组件、路由的导入
- 事件钩子
输入 `module-config` 关键字,`vscode` 中会自动生成:
```ts
import { ModuleConfig } from "/@/cool";
import { Vue } from "vue";
export default (): ModuleConfig => {
return {
// 是否启用
enable: true,
// 插件名称
label: "插件名称",
// 插件描述
description: "插件描述",
// 作者
author: "作者",
version: "1.0.0",
updateTime: "2024-02-02",
logo: "",
// 忽略
ignore: {
// 忽略进度条的请求
NProgress: [
"/base/open/eps",
"/base/comm/person",
"/base/comm/permmenu",
"/base/comm/upload",
"/base/comm/uploadMode",
],
// 忽略 token 的路由
token: ["/login", "/401", "/403", "/404", "/500", "/502"],
},
// 排序
order: 0,
// 配置参数
options: {
name: "神仙",
},
// 示例页面
demo: [
{
name: "基础用法",
component: () => import("..."),
},
],
// 注册全局组件
components: [],
// 视图路由
views: [],
// 页面路由
pages: [],
// 顶部工具栏
toolbar: {
order: 1,
pc: true, // 是否在 pc 端显示
h5: true, // 是否在 h5 端显示
component: import("./components/index.vue"),
},
// 注入全局组件
index: {
component: import("./components/index.vue"),
},
// 安装时触发
install(app: Vue) {},
// 加载时触发
onLoad(events) {},
};
};
```
- order 模块加载顺序,值越大越先
- options 提供给外部使用的参数配置:
```ts
import { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
options: {
// 尺寸
size: 120,
// 显示文案
text: "选择文件",
// 限制
limit: {
// 上传最大数量
upload: 9,
// 文件空间选择数
select: 9,
// 上传大小限制
size: 100,
},
},
};
};
```
获取方式:
```ts
import { module } from "/@/cool";
const config = module.config("模块名");
```
- components 提供全局的组件:
```ts
import type { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
components: [import("./components/test.vue")],
};
};
```
批量导入可以使用 [import.meta.glob](mdc:https:/vitejs.dev/guide/features.html#glob-import) 方法:
```ts
import { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
components: Object.values(import.meta.glob("./components/**/*")),
};
};
```
- views 全局注册的视图路由,存放在 `/` 中的子路由 `children`:
```ts
import { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
views: [
{
path: "/test",
meta: {
label: "测试中心",
},
component: () => import("./views/test.vue"),
},
],
};
};
```
- pages 全局注册的页面路由:
```ts
import { ModuleConfig } from "/@/cool";
export default (): ModuleConfig => {
return {
pages: [
{
path: "/test",
meta: {
label: "测试中心",
},
component: () => import("./views/test.vue"),
},
],
};
};
```
- install 模块安装时触发。用于预先处理:
```ts
import { ModuleConfig } from "/@/cool";
import { Vue } from "vue";
export default (): ModuleConfig => {
return {
install(app: Vue) {
// 注册组件
app.component("test", Test);
// 注册指令
app.directive("focus", {
created(el, bind) {},
});
},
};
};
```
- onLoad 模块安装时触发,预先加载数据,如菜单配置、用户信息:
1. 使用 `await` 等待加载完成后往下执行
2. 可往下模块导出某个方法和变量,如 `hasToken` 验证是否有登陆
```ts
import { ModuleConfig } from "/@/cool";
import { Vue } from "vue";
export default (): ModuleConfig => {
return {
async onLoad() {
const { user, menu } = useStore();
if (user.token) {
// 获取用户信息
user.get();
// 获取菜单权限
await menu.get();
}
return {
async hasToken(cb: () => Promise<any> | void) {
if (user.token) {
if (cb) await cb();
}
},
};
},
};
};
```
其他模块中接收 `hasToken` 方法:
```ts
import { ModuleConfig } from "/@/cool";
import { useDict } from "./index";
export default (): ModuleConfig => {
return {
onLoad({ hasToken }) {
const { dict } = useDict();
hasToken(() => {
dict.refresh();
});
},
};
};
```
## index.ts
该模块需要对外开放的变量及方法,方便于别人直接使用:
```ts
// modules/test/index.ts
import { useStore } from "./store";
export function useTest() {
return {
// 导出 pinia
...useStore(),
// 自定义方法
test() {},
// 自定义变量
data: {
description: "数据描述",
},
};
}
```
导出命名规则 `useBase` `useDemo` `useDict` use + 模块名
使用:
```ts
import { useTest } from "/$/test";
const { data, test } = useTest();
```