module.mdc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. ---
  2. description: module | plugins 模块、插件
  3. globs:
  4. ---
  5. # 模块/插件开发
  6. ## 目录结构
  7. 在 `src/modules` 或 `src/plugins` 下添加一个目录 `demo`:
  8. ```js
  9. demo
  10. ├──pages // 页面路由
  11. ├──views // 视图路由
  12. ├──hooks // 常用函数
  13. ├──components // 常用组件
  14. ├──directives // 指令
  15. ├──static // 静态文件目录
  16. ├──store // 状态管理
  17. ├──... // 其他自定义文件
  18. ├──config.ts // 配置文件
  19. └──index.ts // 入口文件
  20. ```
  21. ::: warning
  22. 约定的目录名称不可修改,但可自行添加或者删除。
  23. :::
  24. ## pages、views
  25. 1. 页面参与权限控制,所以不主动注册目录下的路由,通过 `菜单列表` 中配置注册。或者在 `config.ts` 中手动配置:
  26. ```js
  27. import { type ModuleConfig } from "/@/cool";
  28. export default (): ModuleConfig => {
  29. return {
  30. views: [
  31. {
  32. path: "/demo",
  33. meta: {
  34. label: "测试",
  35. },
  36. component: () => import("./views/demo.vue"),
  37. },
  38. ],
  39. pages: [
  40. {
  41. path: "/demo2",
  42. meta: {
  43. label: "测试",
  44. },
  45. component: () => import("./pages/demo.vue"),
  46. },
  47. ],
  48. };
  49. };
  50. ```
  51. 2. 使页面参与路由缓存,配置 `name` 参数
  52. :::warning
  53. `path` 与 `name` 的匹配规则:
  54. - /demo/t1 = demo-t1
  55. - /demo/t1-det = demo-t1-det
  56. :::
  57. 方式 1:
  58. ```html
  59. <script lang="ts" setup>
  60. defineOptions({
  61. name: "demo",
  62. });
  63. </script>
  64. ```
  65. 方式 2:
  66. ```html
  67. <script lang="ts">
  68. export default defineComponent({
  69. name: "demo",
  70. });
  71. </script>
  72. ```
  73. ## components
  74. 目录下的组件,全局注册配置方法如下:
  75. ```js
  76. import { ModuleConfig } from "/@/cool";
  77. export default (): ModuleConfig => {
  78. return {
  79. components: [
  80. import("./components/demo.vue"),
  81. import("./components/demo1.vue"),
  82. ],
  83. };
  84. };
  85. ```
  86. ## directives
  87. `directives` 会以目录下的文件名分别注册指令
  88. ```ts
  89. // demo/directives/test.ts
  90. export default {
  91. created(el, binding) {},
  92. mounted() {},
  93. ...
  94. };
  95. ```
  96. 使用
  97. ```html
  98. <div v-test></div>
  99. ```
  100. ## store
  101. 使用 `pinia` 的推荐写法:
  102. ```ts
  103. import { defineStore } from "pinia";
  104. import { ref } from "vue";
  105. export const useTestStore = defineStore("test", function () {
  106. const count = ref(0);
  107. function add() {
  108. count.value += 1;
  109. }
  110. return {
  111. count,
  112. add,
  113. };
  114. });
  115. ```
  116. 使用
  117. ```ts
  118. import { useTestStore } from "/$/demo/store";
  119. const test = useTestStore();
  120. test.add();
  121. console.log(test.count); // 1
  122. ```
  123. ::: tip
  124. 参考 `base` 模块下 `store` 的导出方式
  125. :::
  126. ## config.ts
  127. 模块的配置,程序运行时会读取该文件。
  128. - 全局组件、路由的导入
  129. - 事件钩子
  130. 输入 `module-config` 关键字,`vscode` 中会自动生成:
  131. ```ts
  132. import { ModuleConfig } from "/@/cool";
  133. import { Vue } from "vue";
  134. export default (): ModuleConfig => {
  135. return {
  136. // 是否启用
  137. enable: true,
  138. // 插件名称
  139. label: "插件名称",
  140. // 插件描述
  141. description: "插件描述",
  142. // 作者
  143. author: "作者",
  144. version: "1.0.0",
  145. updateTime: "2024-02-02",
  146. logo: "",
  147. // 忽略
  148. ignore: {
  149. // 忽略进度条的请求
  150. NProgress: [
  151. "/base/open/eps",
  152. "/base/comm/person",
  153. "/base/comm/permmenu",
  154. "/base/comm/upload",
  155. "/base/comm/uploadMode",
  156. ],
  157. // 忽略 token 的路由
  158. token: ["/login", "/401", "/403", "/404", "/500", "/502"],
  159. },
  160. // 排序
  161. order: 0,
  162. // 配置参数
  163. options: {
  164. name: "神仙",
  165. },
  166. // 示例页面
  167. demo: [
  168. {
  169. name: "基础用法",
  170. component: () => import("..."),
  171. },
  172. ],
  173. // 注册全局组件
  174. components: [],
  175. // 视图路由
  176. views: [],
  177. // 页面路由
  178. pages: [],
  179. // 顶部工具栏
  180. toolbar: {
  181. order: 1,
  182. pc: true, // 是否在 pc 端显示
  183. h5: true, // 是否在 h5 端显示
  184. component: import("./components/index.vue"),
  185. },
  186. // 注入全局组件
  187. index: {
  188. component: import("./components/index.vue"),
  189. },
  190. // 安装时触发
  191. install(app: Vue) {},
  192. // 加载时触发
  193. onLoad(events) {},
  194. };
  195. };
  196. ```
  197. - order 模块加载顺序,值越大越先
  198. - options 提供给外部使用的参数配置:
  199. ```ts
  200. import { ModuleConfig } from "/@/cool";
  201. export default (): ModuleConfig => {
  202. return {
  203. options: {
  204. // 尺寸
  205. size: 120,
  206. // 显示文案
  207. text: "选择文件",
  208. // 限制
  209. limit: {
  210. // 上传最大数量
  211. upload: 9,
  212. // 文件空间选择数
  213. select: 9,
  214. // 上传大小限制
  215. size: 100,
  216. },
  217. },
  218. };
  219. };
  220. ```
  221. 获取方式:
  222. ```ts
  223. import { module } from "/@/cool";
  224. const config = module.config("模块名");
  225. ```
  226. - components 提供全局的组件:
  227. ```ts
  228. import type { ModuleConfig } from "/@/cool";
  229. export default (): ModuleConfig => {
  230. return {
  231. components: [import("./components/test.vue")],
  232. };
  233. };
  234. ```
  235. 批量导入可以使用 [import.meta.glob](mdc:https:/vitejs.dev/guide/features.html#glob-import) 方法:
  236. ```ts
  237. import { ModuleConfig } from "/@/cool";
  238. export default (): ModuleConfig => {
  239. return {
  240. components: Object.values(import.meta.glob("./components/**/*")),
  241. };
  242. };
  243. ```
  244. - views 全局注册的视图路由,存放在 `/` 中的子路由 `children`:
  245. ```ts
  246. import { ModuleConfig } from "/@/cool";
  247. export default (): ModuleConfig => {
  248. return {
  249. views: [
  250. {
  251. path: "/test",
  252. meta: {
  253. label: "测试中心",
  254. },
  255. component: () => import("./views/test.vue"),
  256. },
  257. ],
  258. };
  259. };
  260. ```
  261. - pages 全局注册的页面路由:
  262. ```ts
  263. import { ModuleConfig } from "/@/cool";
  264. export default (): ModuleConfig => {
  265. return {
  266. pages: [
  267. {
  268. path: "/test",
  269. meta: {
  270. label: "测试中心",
  271. },
  272. component: () => import("./views/test.vue"),
  273. },
  274. ],
  275. };
  276. };
  277. ```
  278. - install 模块安装时触发。用于预先处理:
  279. ```ts
  280. import { ModuleConfig } from "/@/cool";
  281. import { Vue } from "vue";
  282. export default (): ModuleConfig => {
  283. return {
  284. install(app: Vue) {
  285. // 注册组件
  286. app.component("test", Test);
  287. // 注册指令
  288. app.directive("focus", {
  289. created(el, bind) {},
  290. });
  291. },
  292. };
  293. };
  294. ```
  295. - onLoad 模块安装时触发,预先加载数据,如菜单配置、用户信息:
  296. 1. 使用 `await` 等待加载完成后往下执行
  297. 2. 可往下模块导出某个方法和变量,如 `hasToken` 验证是否有登陆
  298. ```ts
  299. import { ModuleConfig } from "/@/cool";
  300. import { Vue } from "vue";
  301. export default (): ModuleConfig => {
  302. return {
  303. async onLoad() {
  304. const { user, menu } = useStore();
  305. if (user.token) {
  306. // 获取用户信息
  307. user.get();
  308. // 获取菜单权限
  309. await menu.get();
  310. }
  311. return {
  312. async hasToken(cb: () => Promise<any> | void) {
  313. if (user.token) {
  314. if (cb) await cb();
  315. }
  316. },
  317. };
  318. },
  319. };
  320. };
  321. ```
  322. 其他模块中接收 `hasToken` 方法:
  323. ```ts
  324. import { ModuleConfig } from "/@/cool";
  325. import { useDict } from "./index";
  326. export default (): ModuleConfig => {
  327. return {
  328. onLoad({ hasToken }) {
  329. const { dict } = useDict();
  330. hasToken(() => {
  331. dict.refresh();
  332. });
  333. },
  334. };
  335. };
  336. ```
  337. ## index.ts
  338. 该模块需要对外开放的变量及方法,方便于别人直接使用:
  339. ```ts
  340. // modules/test/index.ts
  341. import { useStore } from "./store";
  342. export function useTest() {
  343. return {
  344. // 导出 pinia
  345. ...useStore(),
  346. // 自定义方法
  347. test() {},
  348. // 自定义变量
  349. data: {
  350. description: "数据描述",
  351. },
  352. };
  353. }
  354. ```
  355. 导出命名规则 `useBase` `useDemo` `useDict` use + 模块名
  356. 使用:
  357. ```ts
  358. import { useTest } from "/$/test";
  359. const { data, test } = useTest();
  360. ```