# frontend-development-doc **Repository Path**: yuanhehe1208/frontend-development-doc ## Basic Information - **Project Name**: frontend-development-doc - **Description**: 前端开发风格 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2022-04-06 - **Last Updated**: 2022-04-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #前端开发风格指北(js and vue) ## 规则归类 #### 优先级是根据根据约束力强弱来分类,参考了一些编程规约和eslint规则。 - 优先级A:【必要】 这个规则会规避一些错误,请学习接受它。可能会存在一些例外,除非非常精通js才可以去做。 - 优先级B:【推荐】 这个规则可以改善代码的可读性和开发体验,不遵守,代码也能运行,但例外尽可能少,除非有合理的理由。 - 优先级C:【参考】 同时存在多种选项,多种解决方法,建议的一个默认选择。 #### 举例/延伸说明 - "说明" --- 对于规约的适当扩展和解释; - "正例" --- 提倡的编码和实现方式; - "反例" --- 需要提防的雷区,以及真实错误案例; ## 手册愿景 > 高效开发,码出质量; > > 写一次,复制到哪都可以用。。。(write once copy everywhere) ; > > 代码千万行,安全每一行;开发不规范,再看两行泪。 > > 为了协同开发制定,不是为了消灭创造力和优雅性,而是消灭过度的个性。 ## 编程规约 #### 变量/命名 1. 【必要】声明的方式不能使用 var;例外:兼容IE9以下jquery项目 2. 【必要】方法、参数、成员变量、局部变量命名使用 lowerCamelCase 小驼峰方式;类名、构造函数使用UpperCamelCase大驼峰方式;例外:xxxHTML等; 3. 【推荐】全局静态常量命名使用全大写,单词间用下划线分割,语义表达清楚,不嫌长;数组和对象等引用类型声明使用const遵循小驼峰方式; 4. 【必要】语义化命名,望文知义,禁止出现歧视侮辱影射式词语;【推荐】命名中带类型后缀标识; **正例:** ```js let nameStr = '张三'; // 字符串后缀 Str let ageInt = 18; // 整数使用后缀 Int let moneyNum = 100.25; // 其他数字类型使用 Num const shopArr = []; // 数组可以使用 Arr / List const shopObj = {}; // 对象后缀 Obj const stateMap = new Map(); // 映射对象后缀 map /** function 分为几种情况 */ // 事件类句柄命名方式: handle + 功能 + 事件名称 handleGetShopListClick() {}; handleNameChange() {}; handleStateSelect() {}; // 功能类函数 动作 + 功能 changeTimestampToDateStr() {}; getRedFromColorLIst() {}; isObject() {}; // 接口类函数 动词 + 功能 [+ 结构] ;接口的增删改查必须使用这四个(get/create/update/delete) getShopList() {}; createShopData() {}; updateShopDetail() {}; // 其他函数 动词 + 功能 // create/submit/copy/build/edit/bind...... 望词知意; ``` **反例** ```js let a = 18; let Sb = "李四"; let 😊 = 'xiao'; const arr = {}; ``` 5. 【必要】VUE/JSX组件命名应是多个单词组成,避免组件过多引起命名冲突,组件name属性遵循大驼峰; **正例** ```js // TableColumn.vue/TableColumn.js Vue.component("table-column", { }) export default { name: "TableColumn" } ``` 6. 【推荐】关于对象、组件、类的私有方法; **说明** ```js // vue component export default { // 内部私有属性,如:__proto__ methods: { // vue 官方推荐; $_uprate() {}, // 官方极力推荐,这里也推荐 publicFun() { privateFun(); } } } privateFun() {} ``` 7. 【推荐】文件夹/js/css/scss/HTML/image 命名统一小写,以-分隔; 8. 【必要】项目及其路径中不要出现中文;【参考】拼音也别用; 9. 【必要】结构、行为、样式分离分类; 10. 【必要】禁止使用关键字保留字命名; #### 代码规约 1. 【必要】关于{}/[]内容为空时,中间不要加空格或者换行; - 左大括号 { 前不换行; - 右大括号 } 后换行; - 右大括号后有 else 等连续语句代码不换行;表示代码块终止的必须换行; **正例** ```js const personBaseObj = {}; const personObj = { name: '张三' }; const personDetailObj = { name: '张三', age: 18, addr: '大厦10层' }; if(booolean) { // do something... } else { // do something... } ``` 2. 【必要】运算符、=赋值时左右两边都需要加空格; 3. 【推荐】条件判断减少使用if-else的方式; ```js if (condition) { return obj } // 接着写 else 逻辑代码 ``` 说明: 如果必须使用 if() ... else if() ... else ... 请不要超过3层; 正例: 超过3层考虑使用卫语句、策略模式、状态模式等来实现;(详见设计模式) ```js // 卫语句 if(day.today === '六') { return '喜欢' } if(day.today === '日') { return '喜欢' } // if(day.today === '六' || day.today === '日') { return '喜欢' } return '不喜欢'; ``` 反例 ```js if(day.today !== '三'){ if (day.today !== '四') { if(day.today !== '五') { return '不喜欢'; } else { return '喜欢'; } } else { return '不喜欢'; } } else { return '不喜欢'; } ``` 4. 【推荐】使用4空格缩进,如果使用 Tab 请设置下 1Tab = 4空格; 5. 【必要】注释双斜线后必须加一个空格; 6. 【必要】方法参数、数组逗号后必须加一个空格; 7. 【推荐】一个方法(函数)只干一件事,每个方法(函数)不超过80行; 说明:格式化有效代码不超过80行,力求代码主干清晰,易于复用和维护; 8. 【参考】不同逻辑、不同业务、不同语义代码块用个一个空行隔开;较复杂的地方需要注释提醒后面开发者; 9. 【必要】谨慎修改项目级全局变量、样式、方法; 10. 【推荐】使用 === 判断是否相等,减少使用 ==; 11. 【必要】不要在其他表达式中加入赋值语句; **反例** ```js const month = (m = new Date().getMonth()) + 1; ``` 11. 【必要】禁止不必要的取反逻辑; **反例** ```js if(!(1 <= age)) {} ``` 12. 【必要】微任务(异步任务)中,不要使用try...catch...; 13. 【必要】前后端统一返回时间格式 'yyyy-MM-dd HH:mm:ss'; 例外:ios手机端网页可能需要返回timestamp格式; 14. 【必要】模版字符串中不要写过多的、复杂的逻辑; 15. 【参考】前后端接口格式要固定; **说明** ```json { "status/code": 200, "data": "{...仅供参考...}", "message/msg": "成功/失败/token过期......" } ``` 16. 【必要】不要使用eval();带有eval()的插件谨慎使用; 17. 【推荐】ESNEXT新的特性,谨慎使用; 17. 【必要】全局变量、闭包、没有清理的定时器、冗余的DOM不会垃圾回收机制回收,造成内存泄漏,请谨慎使用; ## 控制语句/循环语句 1. 【必要】switch语句内,每个case必须含有 continue/break/return 其中一个;每个switch必须含有default放在最后,即使什么都不做; 2. 【参考】if条件判断常量在前,需要判断的变量在后; **说明** ```js if(1 === a) { /** do something */} ``` 3. 【推荐】微任务(异步任务)一些递减的变量判断,不推荐使用等于; **反例** ```js let time = 100; setInterval(() => { time -- }, 100); if (0 === time) { // do something... } ``` **正例** ```js let time = 100; setInterval(() => { time -- }, 100); if (0 <= time) { // do something... } ``` 4. 【必要】在if/else/for/while语句中必须使用大括号; 说明: 即使只有一行代码,也禁止不实用大括号: if(condition) statements; 5. 【必要】条件清晰情况下赋值可选用 Object/Map/WeakMap; **反例** ```js const status = '1'; if ('1' === status) { gender = '女' } else if ('2' === status) { // ... } ``` **正例** ```js const status = '1'; const genderObj = { '1': '女', '2': '男', } gender = genderObj[status]; ``` 5. 【推荐】不要在判断条件中加入复杂语句,将复杂语句结果赋值给一个语义化布尔变量名,提高可读性; 6. 【必要】根据循环方法特性来选用对应的语法,请勿乱用; **说明** ```js // 用于普通循环,返回值undefined,无法终止或跳出循环;特别注意: callback函数中可能改变原数组 arr.forEach(callback(currentValue [, index [, array]])[, thisArg]) // 返回新数组,不改变之前数组,返回的数组每一项都可以在函数体内修改;可链式调用 const newArr = arr.map(function callback(currentValue[, index[, array]]) { // Return element for new_array }[, thisArg]) // 返回一个新数组, 不改变之前数组,其包含通过所提供函数实现的所有元素;可链式调用 const newArray = arr.filter(callback(element[, index[, array]])[, thisArg]) // 对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值,不会改变数组; reduceRight使用同reduce,为降序执行 const value = arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]) // 一个数组内的所有元素是否都能通过某个指定函数的测试;它返回一个布尔值,不会改变数组,可跳出循环 const allTrue = arr.every(callback(element[, index[, array]])[, thisArg]) // 至少有1个元素通过了被提供的函数测试;它返回一个布尔值,不会改变数组,可跳出循环 const inArr = arr.some(callback(element[, index[, array]])[, thisArg]) // 返回数组中满足提供的函数的第一个元素的值。否则返回 undefined;该方法的效率要低于那些只遍历有值的索引的方法 // 不建议使用 find 方法;替代方法 Array.prototype.indexOf() 或 Array.prototype.includes()。 const found = arr.find(callback[, thisArg]) // 返回数组中满足提供的函数的第一个元素的索引。否则返回 -1; const found = arr.findIndex(callback[, thisArg]) ``` 7. 【推荐】不使用 while(true) {......} ## VUE/JSX风格指南 > 以官方规范的优先级A规则为基础(https://cn.vuejs.org/v2/style-guide)[https://cn.vuejs.org/v2/style-guide], 请仔细阅读该规范; 0. 【必要】项目目录及结构; ``` vue-project / src │ App.vue main.js 入口 ├─ public 公共文件 ├─ request 请求方法,接口列表 ├─ assets 静态资源,icon/image/font/svg等 ├─ components 公共组件 ├─ plugins 本地插件 ├─ router 路由 ├─ store 公共状态 ├─ styles 样式 ├─ utils 封装的方法 ├─ layouts 页面布局组件(header,footer,menu等等) ├─ types 可选 ts相关(.d.ts) ├─ mixins/directives/filters 可选 ├─ constant 可选 静态常量/配置 ├─ tests 可选 单元测试 ├─ hook 可选 封装的composition-api ├─ changelog 可选 改版日志 └─ views 视图 ├─ base │ ├─ components 只用一次的私有组件 ``` 1. 【必要】data 必须是一个函数; 2. 【必要】computed 计算属性要简单点,复杂的分割为尽可能多的更简单的 property; 3. 【必要】组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法; 4. 【必要】确认只用一次的放在模块文件夹的components下; 5. 【必要】页面顶级元素顺序; ```html ``` 6. 【必要】props down, events up; 禁止隐性通信;props 定义必须详细; 7. 【参考】初始化数据接口一般放到created里面请求,如果有依赖dom必须存在的情况,就放到mounted(){this.$nextTick(() => { })}里面; 7. 【推荐】组件中window.addEventListener使用在组件销毁之前移除监听事件; **正例** ```js window.addEventListener('resize', this.$_handleScollChange); this.$once('hook:beforeDestroy', () => { window.removeEventListener('resize', this.$_handleScollChange) }) ``` 9. 【推荐】项目内统一是否使用指令缩写; 10. 【推荐】不推荐使用style module 方式;且必须设置作用域 scoped; 11. 【推荐】vue 组件功能顺序 (常用) ``` 1. 组件基础信息 el name 2. 模板依赖 components directives filters 3. 组合 mixins 4. 数据 props data computed 5. watch/生命周期钩子 watch beforeCreate created beforeMount mounted beforeUpdate updated activated deactivated beforeDestroy destroyed 6. 方法 methods handleXxxClick() {} 事件句柄 getXxxxList() {} 异步接口 filterList() {} 数据处理方法 render() {} 模板渲染方法 ``` 12. 【推荐】v-for和v-if相关指令不能同时使用; 13. ## HTML 1. 【必要】减少标签数量;删除不必要的空标签和冗余标签; 2. 【推荐】class 取名语义化,多个单词用中划线 - 分隔;例外 jsx 的 className; 3. 【必要】减少或不操作DOM; 4. 【推荐】不使用行内样式; 5. 【推荐】一个标签上的类名不能超过 4 个;例外:给js使用的类名; 6. 【推荐】id采用驼峰式命名;避免使用id选择器; 7. 【必要】标签名小写; 8. 【推荐】HTML代码结构和视觉结构保持一致; 9. 【推荐】说明文案注释格式; ```html 开始注释 结束注释(可不写) ``` 10. 【推荐】属性顺序按照以下标准; ```
``` 11. 【必要】保持结构清晰,与样式和逻辑分离; 12. 【推荐】块级元素可包含行内元素或某些块元素,但行内元素不可包含块元素,只能包含行内元素; 13. 【推荐】class 越少越好; 14. 【推荐】根据需求使用相应的标签,不要满篇都是div、span; 例外:兼容性要求较高的; 15. ## CSS/SCSS/LESS/STALUS 1. 【必要】选择器的层级不要超过三层; 2. 【推荐】不要给id写样式; 3. 【必要】组件内禁止给元素写样式; 4. 【必要】组件内禁止写全局样式; 5. 【推荐】不使用浏览器兼容带前缀的样式; 6. 【必要】class 命名 推荐 **BEM** 约定: 块(block)、元素(element)、修饰符(modifier);下划线代表后代,中划线代表状态; **参考** ``` 比如: .el-table__header-wrapper // from element-ui // BEM 思想 el: 框架标识 table: 模块名称 (block) header: 组件名称 (element) wrapper: 功能、用途、位置、修饰 (modifier) ``` 7. 【推荐】不写行内样式 8. 【必要】抽离的样式,提供说明; 9. 【推荐】避免使用 !important; 10. 【必要】属性声明顺序; ```css /** 布局定位类 */ position 及相关(top/left....] display 及相关(align-items.......) /** DOM自身类 */ width/height 及相关(min-width......) padding -> border ->margin (border-radius......) /** 内部文本类 */ text-align/line-height 及相关(text-* ......) font-size 及相关(font-* ......) color/background 及相关(background-* ......) /** 动画类及其它 */ opacity/box-shadow transform/animation 及相关(......) ....其它静态属性 ``` 11. 【推荐】颜色使用hex格式,建议使用小写; 12. 【参考】属性为0时,可以不带单位; 13. 【推荐】减少使用 >、+、~;多个 selector 时,每个选择器声明必须独占一行; **正例** ```css .page_item-num, .page .page_item-jump, .page .page_item-prev{ } ``` **反例** ```css .btn, .ipt, .select{ } ``` 14. 【参考】在可以使用缩写的情况下,尽量使用属性缩写; 15. 【必要】CSS内部分类及顺序,可按分类进行分文件; 此项不与 BEM 约定冲突; - 重置(reset)和默认(base)(tags):消除默认样式,并设置部分标签的初始样式; - 全局(global)(.g-*)(tags):全局属性、样式、字体统一处理; - 布局(layout)(.l-*):页面几大块;Header、Aside、Body...... - 模块(module)(.m-*):封装的 module、components; - 元件(unit)和功能(function)和状态(status): 其它; 16. 【参考】语义化单词参考:不推荐使用简写; **布局** | 语义 | 命名 | 简写 | | ---------- | -------- | -------- | | 文档 | doc | doc | | 头部 | head | hd | | 主体 | body | bd | | 尾部 | foot | ft | | 主栏 | main | mn | | 主栏子容器 | mainc | mnc | | 侧栏 | side | sd | | 侧栏子容器 | sidec | sdc | | 盒容器 | wrap/box | wrap/box | | | | | **模块、元件** | 语义 | 命名 | 简写 | | ------ | ------------ | ----- | | 导航 | nav | nav | | 子导航 | subnav | snav | | 面包屑 | crumb | crm | | 菜单 | menu | menu | | 选项卡 | tab | tab | | 标题区 | head/title | hd/tt | | 内容区 | body/content | bd/ct | | 列表 | list | lst | | 表格 | table | tb | | 表单 | form | fm | | 热点 | hot | hot | | 排行 | top | top | | 登录 | login | log | | 标志 | logo | logo | | 广告 | advertise | ad | | 搜索 | search | sch | | 幻灯 | slide | sld | | 提示 | tips | tips | | 帮助 | help | help | | 新闻 | news | news | | 下载 | download | dld | | 注册 | regist | reg | | 投票 | vote | vote | | 版权 | copyright | cprt | | 结果 | result | rst | | 标题 | title | tt | | 按钮 | button | btn | | 输入 | input | ipt | | | | | **功能、状态、其它** | 语义 | 命名 | 简写 | | -------- | ------------------- | ----- | | 浮动清除 | clearboth | cb | | 向左浮动 | floatleft | fl | | 向右浮动 | floatright | fr | | 内联块级 | inlineblock | ib | | 文本居中 | textaligncenter | tac | | 文本居右 | textalignright | tar | | 文本居左 | textalignleft | tal | | 垂直居中 | verticalalignmiddle | vam | | 溢出隐藏 | overflowhidden | oh | | 完全消失 | displaynone | dn | | 字体大小 | fontsize | fs | | 字体粗细 | fontweight | fw | | | | | | 字体颜色 | fontcolor | fc | | 背景 | background | bg | | 背景颜色 | backgroundcolor | bgc | | 背景图片 | backgroundimage | bgi | | 背景定位 | backgroundposition | bgp | | 边框颜色 | bordercolor | bdc | | | | | | 选中 | selected | sel | | 当前 | current | crt | | 显示 | show | show | | 隐藏 | hide | hide | | 打开 | open | open | | 关闭 | close | close | | 出错 | error | err | | 不可用 | disabled | dis | 17. 【参考】选择器权重: style > id > class > dom标签; ## 前后端规约 1. 【必要】功能类接口禁止使用get请求方式传值;(增删改) 2. 【必要】基本权限分为四级,系统、模块、页面、按钮(功能);例外:更原子化的权限; ``` 系统code:取值范围 1-9;(单个系统时可省略); 模块code:取值范围 01-99;(单系统时:1-99); 页面code:取值范围 01-99; 按钮code:取值范围 01-99; 【示例】 // 模块及以下 { name: 'userMana', code: '1', // 模块 children: [ { name: 'userList', code: '101', // 路由、页面 children: [ { name: 'create', code: '10101', // 子页面、按钮 } ] }, { name: 'create', code: '10101', // 子页面 } ] } ``` 3. ## GIT 1. 【必要】**git merge** 参数,在有多次无效 commit 合并分支请使用 --squash,其他请使用 --no-ff - --no-ff 不使用fast-forward方式合并,保留分支的commit历史 - --squash 把多次分支commit历史压缩为一次 **正例** ```shell git merge --squash feature-1.0.0 git commit -m 'feat(xxx):修复了xxx' git push origin origin/branch ``` 2. 【必要】**git commit** 规范,Commit message 需按照严格格式标准 **正例** ```shell # 一般提交 commit message 只写
git commit -m '<类型 type>[(可选的作用域 scope)]: <描述 subject>' #【正例】 git commit -m 'feat(xxx.vue): xx页面添加功能' ``` ```shell # 重大需求、更新等必须添加body git add xxxx git commit # 只输入 git commit 之后会出现 vim 窗口,标准格式如下 <类型 type>[(可选的作用域 scope)]: <描述 subject> #空一行 [可选的正文] #空一行 [可选的脚注] # 【正例】 feat(xxx.vue): 权限页面 此次改版包含新的权限树,...更新typescript版本到3.4.1,去掉项目部分代码使用的装饰器。 v2.0.1 版本/开发任务: FE21-07-26-A01 #【正例结束】 ``` Header: - type:(类型) 分为一下几类: ``` # 主要type feat: 增加新功能 fix: 修复bug # 次要 docs: 只改动了文档相关的内容 style: 不影响代码含义的改动,例如去掉空格、改变缩进、增删分号 build: 构造工具的或者外部依赖的改动,例如webpack,npm refactor: 代码重构时使用 test: 增加测试 chore: 构建过程或辅助工具的变动 ``` - scope:(可选的作用域)说明影响范围,比如数据层、控制层、视图层等等,是项目而定 - subject:(简洁描述)能让人知道你此次改动的核心点 **查询git log相关命令** ```shell # grep 筛选关键词 git log --pretty=format:"%an %h %cd %s"--date=iso | grep 'feat*' # %H 提交对象(commit)的完整哈希字串 # %h 提交对象的简短哈希字串 # %T 树对象(tree)的完整哈希字串 # %t 树对象的简短哈希字串 # %P 父对象(parent)的完整哈希字串 # %p 父对象的简短哈希字串 # %an 作者(author)的名字 # %ae 作者的电子邮件地址 # %ad 作者修订日期(可以用-date= 选项定制格式) # %ar 作者修订日期,按多久以前的方式显示 # %cn 提交者(committer)的名字 # %ce 提交者的电子邮件地址 # %cd 提交日期 # %cr 提交日期,按多久以前的方式显示 # %s 提交说明 ``` 3. 【推荐】回退版本,备份当前分支后,使用git可视化工具(git GUI / Sourcetree / TortoiseGit),以及有一些编辑器插件;例外:当你非常了解git原理和机制; ​