一定要看的前端codeReview规范指南

  • 一定要看的前端codeReview规范指南已关闭评论
  • 209 次浏览
  • A+
所属分类:Web前端
摘要

一、前言
针对目录结构、CSS规范、JavaScript规范、Vue规范
可参照官方给出的 风格指南
这里主要总结业务开发中常遇到的代码问题和实践,帮助大家后续各自做好codeReview,一些你遇到的典型问题,也可以在留言区评论,帮助团队共同进步。

一、前言
针对目录结构、CSS规范、JavaScript规范、Vue规范
可参照官方给出的 风格指南
这里主要总结业务开发中常遇到的代码问题和实践,帮助大家后续各自做好codeReview,一些你遇到的典型问题,也可以在留言区评论,帮助团队共同进步。

二、实践规范
2.1 防止重复提交
--表单提交或者编辑新增数据时,按钮必须加loading,防止重复提交
<el-button type="primary" :loading="submitLoading" @click="handleSubmit"> 提交 </el-button>

--针对table的操作列中的操作项,没有二次确认的也要注意加loading
[图片]

 <yun-table         :pagination="pagination"         :border="true"         :columns="columns"         :loading="loading"         :data="tableData"         @update:pagination="handlePageUpdate"       >         <template #action="{ row }">           <yun-rest>             <el-button               :loading="row.loadingSync"               type="action"               @click="handleAction(row, 'sync')"             >               同步             </el-button>           </yun-rest>         </template>       </yun-table>       ...    <script setup>     const { result } = await fetchApi(data);     if (result) {       tableData.value = result.records.map((item) => {         return {           ...item,           loadingSync: false,         };       });       total.value = result.total;     }       </script> 

2.2 滚动到报错位置
--长表单页面或抽屉内容很长,点击提交时,有验证错误时,页面需要做好滚动到报错位置

const handleSubmit = async () => {     let flag = true;     formRef.value.elForm.validate((valid, noValidObj) => {       flag = valid;       if (!valid) {         const errorArr = Object.keys(noValidObj).filter(           (key) => Array.isArray(noValidObj[key]) && noValidObj[key][0]?.field         );         contractFormRef.value.elForm.scrollToField(errorArr[0]); // 滚动到报错位置       }     });     if (!flag) {       ElMessage.warning("表单未填写完成!");       return;     }     // 走后续提交请求     submitLoading.value = true;     ... 

2.3 模板上的多个判断条件,写成方法或者computed

<template>   // bad          <el-button               v-if="                 ['NORMAL', 'UNUSUAL'].includes(row.archiveType) &&                 ['ALREADY_SEND'].includes(row.contractStatus) &&                 ['ENABLED'].includes(row.enabledStatus)               "               type="action"               @click="handleAction(row, 'modify')"             >               变更             </el-button>             <el-button               v-if="                 ['NORMAL', 'UNUSUAL'].includes(row.archiveType) &&                 ['ALREADY_SEND'].includes(row.contractStatus) &&                 ['ENABLED'].includes(row.enabledStatus)               "               type="action"               @click="handleAction(row, 'renewal')"             >               续签             </el-button>             <el-button               v-if="                 ['NORMAL', 'UNUSUAL'].includes(row.archiveType) &&                 ['ALREADY_SEND'].includes(row.contractStatus) &&                 ['ENABLED'].includes(row.enabledStatus)               "               type="action"               @click="handleAction(row, 'rebook')"             >               改签             </el-button> // good            <el-button             v-if="isChangeAvailiable(row)"             type="action"             @click="handleAction(row, 'modify')"           >             变更           </el-button>           <el-button             v-if="isChangeAvailiable(row)"             type="action"             @click="handleAction(row, 'renewal')"           >             续签           </el-button>           <el-button             v-if="isChangeAvailiable(row)"             type="action"             @click="handleAction(row, 'rebook')"           >             改签           </el-button>  </template>  <script setup> // good const isChangeAvailiable = (row) => { return (   ["ALREADY_SEND", "ALREADY_ARCHIVE"].includes(row.contractStatus) &&   ["ENABLED"].includes(row.enabledStatus) ); };  </script> 

2.4 保持数据响应式

<script setup>   import { reactive } from "vue";   let state = reactive({       loading: false,       a: true,     });     function handleChange(){        // bad 无法实现数据响应式        state = {...state,b:'test'}        // bad 无法实现数据响应式        state = reactive({...state,b:'test'})                // correct 数据具有响应式        state.b = 'test';        // correct 数据具有响应式        Object.assign(state,{b:'test'});          }   </script> 

2.5 避免使用 delete
delete 操作符并不会释放内存,而且会使得附加到对象上的 hidden class 失效,让对象变成 slow object。(hidden class 是 V8 为了优化属性访问时间而创建的隐藏类)

2.6 尽量使用 export 而 不是 export default 来导出
export default 有两个问题:1)不利于 tree shaking 2)如果使用了一个导出对象上不存在的属性,要运行时才能发现。

2.7 可选链访问数组元素

 <template>      // bad      <span>{{row[0].contract.name}}<span>      <span>{{Array.isArray(row) && row[0].contract.name}}<span>           // good     <span>{{row?.[0]?.contract?.name}}<span>  </template> 

2.8 参数硬编码

// bad 硬编码1001 const isActive = this.$route.query.id === '1001'  // good  写到配置信息中。这样,id和状态的对应关系一目了然,便于管理和维护。 const idConfig = {   1001: STATUS.ACTIVE } const isActive = idConfig[this.$route.query.id] === STATUS.ACTIVE 

2.9 定时器是否及时清理

mounted () {   this.timer = setInterval(() => {     doSomething();   }, 300) } destroyed () {   if (this.timer) {     clearInterval(this.timer)   } } 

2.10 监听事件是否有解绑
在window/body 上的事件需要解绑:

mounted() {   window.addEventListener(‘resize’, this.func)   window.addEventListener(‘scroll’, this.func) } beforeDestroy () {   window.removeEventListener('resize', this.func);   window.removeEventListener('scroll', this.func); } 

三、总结

不积跬步,无以至千里。肯定还有很多遗漏的点,欢迎补充哟。