步调开发时定名规范(目录名、文件名、函数名、变量名、数据库字段等)的最 ...

打印 上一主题 下一主题

主题 830|帖子 830|积分 2490

经过实践应用,用合适的方案来给目录、文件等定名将让步调开发变得顺畅。
  前言

阅读本文前先相识以下两篇:


  • 《步调开发时字母大小写的定名规范(目录名、文件名、函数名、变量名、数据库字段等,小驼峰/大驼峰/短横线/下划线)》
  • 《步调开发时单数复数及前缀的定名规范(目录名、文件名、函数名、变量名、数据库字段等)》
根据这两篇的分析及开发经验订立以下定名方案:

上菜

先把最终的样子拿出来看,后面的具体表明根据这份清单来。
  1. router/
  2. ├── index.ts
  3. csdn/
  4. ├── components/
  5. ├── config/
  6. │   ├── index.ts
  7. │   ├── menu.json
  8. │   └── system.json
  9. ├── services/
  10. │   ├── index.ts
  11. │   ├── httpClient.ts
  12. │   ├── serviceAuth.ts
  13. ├── stores/
  14. │   ├── index.ts
  15. │   ├── pinia.ts
  16. │   ├── storeAuth.ts
  17. │   ├── storeMenu.ts
  18. │   └── storeTab.ts
  19. ├── types/
  20. │   ├── index.d.ts
  21. │   ├── typeAuth.d.ts
  22. │   ├── typeMenu.d.ts
  23. │   └── typeService.d.ts
  24. ├── utils/
  25. │   ├── index.ts
  26. │   ├── utilTab.ts
  27. │   └── crypto/
  28. │       ├── index.ts
  29. │       ├── utilBase64.ts
  30. │       ├── utilRsa.ts
  31. │       └── utilSecure.ts
  32. └── views/
  33.     ├── _system/
  34.     │   ├── auth/
  35.     │   │   ├── ForgotPassword.vue
  36.     │   │   ├── Login.vue
  37.     │   │   └── Register.vue
  38.     │   ├── workspace/
  39.     │   │   ├── Layout.vue
  40.     │   │   ├── LeftMenu.vue
  41.     │   │   ├── MainContent.vue
  42.     │   │   ├── MenuItem.vue
  43.     │   │   └── TabContainer.vue
  44.     │   │   └── TopNav.vue
  45.     │   └── About.vue
  46.     └── home
  47.         ├── Dashboard.vue
  48.         └── Notice.vue
复制代码
规范



  • 一层目录除了config,其它都是复数。

    • 原因是config在使用时将被拼接成一个整体使用,如果每个config单独调用,那么思量重立名字。

  • 非vue的文件名开头以该目录单数定名。

    • 比如utils/utilTab、stores/storeTab
      原来并不在文件名开头写目录单数,但是开发时遇到这个环境

      三个名字如出一辙,分别属于路由、控制器和模子,这里目录名还能看到不一样,可如果目录名也一样呢?

      改成带有目录名前缀后,三个不同的menu同时出现在编辑器标签页里也能清晰分辨作用。

   当使用了目录单数名前缀后,目录的复数名是不是也就顺理成章了?
utils/utilMenu.ts、utils/utilTab,如许的 目录/文件 看着顺眼不?
  

  • 一般环境内容都包含在定名空间中,且空间名称与文件名相同。

    • 比如utilMenu.ts中的定名空间就是utilMenu,如许的利益是在其它文件中引用该文件后直接就调用该定名空间了。
      看下面这个例子,不消说什么,单单看到utilMenu.action(),立即就知道在哪个目录下,起什么作用。

  1. import { utilMenu } from "../utils/utilMenu";
  2. const csdn = utilMenu.handler;
复制代码
现实开发时由于在index.ts中已经引入了该组件,所以这么写就更惬意了:
  1. import { utilMenu } from "../utils";
  2. const csdn = utilMenu.handler;
复制代码


  • 方法、变量等定名规范参考之前的分析。

    • 这里多讲一点,每个定名空间里的类名可以不太在意,但是其对应的实例如果要定名导出一般用use前缀,例如下面的代码:

  1. // ./stores/storeMenu.ts
  2. import { ref } from 'vue';
  3. import { defineStore } from 'pinia';
  4. // 命名空间与文件名相同
  5. namespace storeMenu {
  6.   // 标识随意,本实例名规范参考之后的说明,主要是builder或factory的区别
  7.   export const builder = defineStore('csdnMenuStore', () => {
  8.     const isCollapsed = ref(false);
  9.     const toggleCollapse = () => {
  10.       isCollapsed.value = !isCollapsed.value;
  11.     };
  12.     return {
  13.       isCollapsed,
  14.       toggleCollapse
  15.     };
  16.   });
  17. }
  18. // 默认导出有且只有一个
  19. export default storeMenu.builder;
  20. // 命名导出中必须有命名空间
  21. export { storeMenu };
  22. // 命名导出中必须有一个实例,且该实例名用use做前缀,目录单数做后缀
  23. export const useMenuStore = storeMenu.builder;
  24. // ../utils/crypto/utilSecure.ts
  25. import SecureLS from 'secure-ls';
  26. // 命名空间与文件名相同
  27. namespace utilSecure {
  28.   // 类名随意
  29.   class SecureStorage {
  30.     private ls: SecureLS;
  31.     constructor() {
  32.       this.ls = new SecureLS({
  33.         isCompression: false,
  34.         encryptionSecret: 'csdn'
  35.       });
  36.     }
  37.     // 方法名随意
  38.     setItem(key: string, value: string): void {
  39.       this.ls.set(key, value);
  40.     }
  41.     // 方法名随意
  42.     getItem(key: string): string | null {
  43.       return this.ls.get(key);
  44.     }
  45.   }
  46.   // 本实例名规范参考之后的说明,主要是builder或factory的区别
  47.   export const builder = new SecureStorage();
  48. }
  49. // 默认导出有且只有一个
  50. export default utilSecure.builder;
  51. // 命名导出中必须有命名空间
  52. export { utilSecure };
  53. // 命名导出中必须有一个实例,且该实例名用use做前缀,目录单数做后缀
  54. export const useSecureUtil = utilSecure.builder;
复制代码
  这么规范的利益你们在开发的时间自己体会。
  

  • 实例名
    上面的代码案例中已经涉及到builder,看一下便明白本段在说啥。
    除了接口类文件,一般定名空间中都有一个实例,无论这个实例是由类new来的又或者天生就是,只要这个实例是对外暴露的,那么也要有个标准名称,比如说可以根据返回值是实例还是函数定义来区分,订立原则如下:
  1. // 返回实例,用builder
  2. const su = storeUser.builder();
  3. const { getId, toggleId } = su;
  4. su.getId();
  5. storeUser.builder().getId();
  6. // 返回函数定义用factory
  7. const su = storeUser.factory();
  8. const { getId, toggleId } = su();
  9. su().getId();
  10. storeUser.builder()().getId();
复制代码
参考:
《factory、creator、handler、builder、provider、generator、instance、constructor之间在返回实例或返回函数定义上有什么区别》


  • 总引入文件

    • 每个目录下基本都有一个index.ts,将该目录下的全部文件引入其中,如许在写代码时只需要引入到该目录即可,不需要关心下面的目录文件。
    • 推荐写法一的引入方法,扩展性更强。我个人喜好写法一的文件调用,原因是:这么写的话,当你在任何地方看到他,都立即能知道他从哪里来。
    • 如果用的函数、属性少,就用下面案例一中写法一、二的使用方法,多就用写法三、四,用到哪里调哪里。
    • 有了总引入文件后,哪怕套再多层,也能直击要害。

案例一
  1. // ./stores/index.ts
  2. export * from './pinia';
  3. export * from './storeAuth';
  4. export * from './storeMenu';
  5. export * from './storeTab';
  6. // 某文件
  7. // 写法一:
  8. import {storeMenu} from '../stores'
  9. const { isCollapsed, toggleCollapse } = storeMenu.action();
  10. // 写法二:
  11. import { useMenuStore } from '../stores';
  12. const { isCollapsed, toggleCollapse } = useMenuStore();
  13. // 写法三:
  14. import { useMenuStore } from '../stores/storeMenu';
  15. const menuStore = useMenuStore();
  16. menuStore.isCollapsed;
  17. menuStore.toggleCollapse();
  18. // 写法四:每个文件都有一个自己的默认导出,所以要用默认内容,导入的时候就必须精确到文件
  19. import csdn from '../stores/storeMenu';
  20. const menuStore = csdn();
  21. menuStore.isCollapsed;
  22. menuStore.toggleCollapse();
  23. // 更多写法...
复制代码
案例二
  1. // ./utils/crypto/index.ts
  2. // 所有命名导出继续导出
  3. export * from './utilSecure';
  4. export * from './utilBase64';
  5. // 选择性的让命名导出继续命名导出
  6. export { utilSecure, useSecureUtil } from './utilSecure';
  7. export { utilBase64, useBase64Util } from './utilBase64';
  8. //因为default默认的会重叠,所以不带默认的家伙们玩了
  9. ...
  10. // 某文件
  11. // 套娃只要引入一层,比如这里实际引用文件为 ../ytils/crypto/utilBase64.ts,但只要引入一层就能使用
  12. // 这里导入命名空间
  13. import { utilBase64 } from '../utils';
  14. utilBase64.handler.encode('csdn');
  15. //而因为在./utils/crypto/index.ts已经引入了命名导出,所以如下也是可以的
  16. // 这里导入实例
  17. import { useBase64Util } from '../utils';
  18. useBase64Util.encode('csdn');
复制代码


  • 其它定名
    比如./stores/pinia.ts、./services/httpClient.ts等由于作用比较特殊且具有全局性,所以不把他们的前缀强制取目录单数名。
具体环境

目录中的目录改用单复数?
在上面的套娃案例中utils/crypto/...,这里的crypto该用复数还是单数呢?分析分析如下:
分析:crypto vs cryptos
当前的项目目录结构中:
  1. csdn/
  2. ├── utils/
  3. │   └── crypto/
  4. │       ├── index.ts
  5. │       ├── utilBase64.ts
  6. │       ├── utilRsa.ts
  7. │       └── utilSecure.ts
复制代码


  • 单数(即 crypto),由于这个目录表示一个加密工具模块,而不是多个独立的工具集。crypto 更倾向于指一个整体的加密工具库。
  • 如果这个目录内专门存放不同类型的加密工具且各自独立,也可以思量用复数(cryptos),但大多数环境下,单数会显得更加自然和简便。
最终决定:crypto


  • 更符合模块定名的习惯,表明这是一个专门处理加密的工具集合。
  • 为什么这个例子单独拿出来讲,由于这是提醒你(我),在遇到单个环境的时间,一定具体环境具体分析具体决定。
总结

总的规范使用本解决方案,特例单独使用。
觉不错请一键三连。
更新

2024.12.02 更新

项目靠近尾声,根据目前的开发经验,修改或确定了如下两条:

  • config改为configs
    原本config全为json格式,直接在index.ts中合并即可。但现实使用中json文件不能标注释,无法在不同环境下提供不同设置,且服从还差点。所以综合思量还是用回传统的方式,用export分别暴露。
  • 非组件对外暴露都依照如下格式
    定名空间+主输出符,并都对应一个简写方式,比如
    设置类configTest.options对应getTestConfig;
    实例类serviceTest.builder对应useTestService;
    定义类storeTest.factory对应makeTestStore。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

吴旭华

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表