# 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. 【推荐】属性顺序按照以下标准; ```