写点什么

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

  • 2023-06-29
    福建
  • 本文字数:2909 字

    阅读完需:约 10 分钟

一、前言


针对目录结构、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>// goodconst 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 避免使用 deletedelete


操作符并不会释放内存,而且会使得附加到对象上的 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 硬编码1001const 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);}
复制代码


三、总结


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


文章转载自:辉是暖阳辉

原文链接:https://www.cnblogs.com/mrwh/p/17462559.html

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
一定要看的前端codeReview规范指南_前端_快乐非自愿限量之名_InfoQ写作社区