如何编写可维护、健壮的前端代码?——前端编码规范制定

前言

我认为代码不只是为了实现某个需求,更是给别的人看的。团队制定一个好的编码规范,能让大家更清晰的去理解代码。只有高质量的代码,才能有优化的可行性。更利于项目的版本迭代和拓展。前段时间为公司制定了编码规范,在这里分享一下

如果感觉文章对你有帮助的话,留个赞再走吧~

js(vue)写法推荐

  1. 变量和普通使用camelCase小驼峰式命名(tableData,isVisible),构造函数使用大驼峰式命名

  2. vue文件命名

对于展示类的、无逻辑的或无状态的基础组件可以单独放在一个文件夹中管理,和父组件紧密耦合的子组件应该以父组件名作为前缀命名。编辑器通常会按字母顺序组织文件,而自动补全让长命名的代价非常之低,尽量使组件命名完整。

components/
    base
        BaseButton.vue
        BaseTable.vue
        BaseIcon.vue
    todoList
        TodoList.vue
        TodoListItem.vue
        TodoListItemButton.vue
    searchSidebar
        SearchSidebar.vue
        SearchSidebarNavigation.vue
  1. 函数式编程,通过语义就知道代码大概要干些什么。
// 获取年龄大于20学生的姓名
const students = [{
        age: 21,
        sex: 2,
        name: '李小花'
    },
    {
        age: 18,
        sex: 1,
        name: '李二蛋'
    },
    {
        age: 22,
        sex: 1,
        name: '王强强'
    },
]
// 推荐
let studentNames_1 = students.filter(student => student.age > 20).map(student => student.name)
// 不推荐
let studentNames_2 = []
for (let i = 0; i < students.length; i++) {
    if (students[i].age > 20) {
        newStudents.push(students[i].name)
    }
}
  1. 最小函数准则,即一个函数只做一件事情。复用性强,拓展性高。而好的函数命名可以使让读者清晰的知道函数的边界

  2. 面向对象的思想。例如在对一张表的增删改查,而那个表就是一个对象。以及合理的运用解构赋值,阅读性强且效率更高(不推荐:row.name,row.price…)

let book = {
    isAdd: false,
    isModalShow: false,
    name: "",
    count: 0,
    price: 0,
}
function editBookModalShow(row) {
    const { name, counts: count, salePrice: price} = row
    book = {
        isAdd: false,
        isModalShow: true,
        name,
        count,
        price,
    }
}
editBookModalShow({
    name: '红楼梦',
    counts: 42,
    salePrice: 60
})
  1. var,let和const的选择

var因为变量提升,重复定义等问题不推荐使用。而任何语言定义常量的开销总是比变量小的。所以,在不需要更改值的情况下只推荐使用const

  1. props是子父组件传递数据的通道。数据的准确性可以说是尤为重要
 // 推荐
 props: {
    type: {
      type: String,
      default: "primary",
      validator: value => ["primary", "success","danger"].includes(value)  // 甚至可以这样去限制参数值
    },
    size: {
      type: String,
      default: "large"
    }
  },
 // 不推荐
 props: ["size","type"]

如何设计一个组件这篇文章讲的非常好

  1. 组件通信及状态管理
    • 该怎么通信就怎么通信,千万不要去滥用vuex,甚至可以不用
    • 遵守单向数据流,不要使用 p a r e n t , parent, parentchildren
  子父组件:props $emit
  兄弟组件:eventBus(eventbus在大型项目中监听和触发的位置不确定,
  所以在维护上会造成麻烦)
  祖孙组件:provide / inject,$attrs/$listeners
  多组件共享状态:vuex
  本地持久化:localStorage sessionStorage
  1. v-for的key值

使用item的 id 来作为key值,而不是index。在数组插入中间值时会出现bug

  1. 永远不要把 v-if 和 v-for 同时用在同一个元素上

因为v-for 比 v-if 具有更高的优先级

    <ul>
      <li
        v-for="user in users"
        v-if="user.isActive"
        :key="user.id"
      >
        {
   
   { user.name }}
      </li>
    </ul>
	// 将会经过如下运算:
    this.users.map(function (user) {
      if (user.isActive) {
        return user.name
      }
    })
    // 这样会造成不必要的遍历 我们可以将users通过计算属性filter出avtiveUsers,再提供给v-for渲染
  1. 尽量不要使用watch

watch对性能的开销大,大部分情况computed是你更好的选择

  1. websocket,webwoker,定时器等在不使用的时候记得关闭

  2. 除非迫不得已不要去操作DOM元素

  3. 按需加载(利用 import() 语法进行code splitting)

在不使用懒加载,不分离业务代码时。webpack会把所有的代码打包成一个文件。如果在进入页面时,这个文件过大,会极大的影响首屏加载速度。所以说,在生产环境中的code splitting是十分重要的,在对应的页面只加载需要的代码。分离业务代码和第三方库则需要进行webpack配置,而使用import语法在编码时可以注意

// router.js
{
    path: '/404',
    component: () => import("@/views/404.vue"),
}
// 注册组件
components: {
    TodoList: () => import("@/components/todoList/TodoList.vue")
    TodoListItem: () => import("@/components/todoList/TodoListItem.vue"),
  }
  1. template中合理使用{ {}}表达式

尽量在template只使用简单的表达式。我们只用关心模板中{ {}}需要展示的东西,而数据是如何计算出来的可以写在computed和methods里。在使用el-table时这样去处理一些状态值的字段是不是更舒服呢

```
// 推荐写法
  orderStatus: {
      0: "待发货",
      1: "已发货",
      2: "货物中转"           // 也可以将这些状态统一放在一个文件,方便管理
    }

  <el-table-column prop="status" label="订单状态">
    <template slot-scope="{row}">{
   
   {orderStatus[row.status]}}</template>
  </el-table-column>

// 糟糕的写法
   <el-table-column prop="status" label="订单状态">
    <template slot-scope="{row}">
   	 {
   
   {row.status==='0'?'已发货':row.status==='1'?'待发货':''}}
    </template>
  </el-table-column>
```
  1. 使用严格等进行两数比较,避免在判断的过程中,由 JavaScript 的强制类型转换所造成的困扰
==:运算符称作相等,用来检测两个操作数是否相等,这里的相等定义的非常宽松,可以允许进行类型转换。
===:用来检测两个操作数是否严格相等

但在组件内使用入参进行判断时,也可以使用==,比如一个type属性。type==1则不管你使传string或number类型都可以,对使用组件的人比较友好,element-ui等都使这样做的。所以使用相等和严格等都是可取的,存在即有理

  1. 尽量把函数的入参说明详细
/**
 * @param props.dateTable 模板数组
 * @param props.handleItemClick item点击事件
 * @param props.self 父组件作用域
 */
const RenderDateTemplate = (props) => {
    const { dateTable, handleItemClick, self } = props;
    return (
        <Fragment>
        	 {
                dateTable.map((item, index) => {}
            }
        </Frangment>
        )
}

样式写法推荐

  1. 为每个.vue文件加上scoped,避免污染全局
<style lang="scss" scoped>
</style>
  1. 遵守BEM规范(即block-name__element-name–modifier-name)

但要注意block 嵌套的层次要尽量少(一个层次能搞完的就不要嵌套).
各大组件库(Element AntDesign)的BEM实践,提供了很大的参考性,模仿既学习,它们的做法肯定是比较规范的

m-button__label, m-button__label--danger, m-button__label--success
  1. 在使用css预处理器,如scss。嵌套功能和父选择器标识符 & 解决BEM冗长问题
.m-button{
      margin: 0px;
      &__label{
        font-size: 14px;
      }
      &--success{
        background-color: #029627;
      }
}
  1. scss中变量 $ 使用

一些整个应用的会常用的颜色 大小 宽高 图片路径等,可以放在一个scss文件中定义。可以做到更改一处,从而进行全局更改,从而实现“换肤”的功能。

$color-primary: #3ecacb;
$color-success: #4fc48d;
$color-main: #f3d93f;
  1. scss中巧用@mixin和@extend可复用一大段规则

@extend继承属性

    .common-mod {
      height: 250px;  
      width: 50%;  
      background-color: #fff;  
      text-align: center;
    }
    &-mod { 
      @extend .common-mod;  
      float: right;
    }
    &-mod2 { 
      @extend .common-mod;
    }

@mixin——可传递参数的继承

    @mixin paneactive($image, $level, $vertical) { 
      background: url($image) no-repeat $level $vertical;  
      height: 100px;  
      width: 30px; 
      position: relative;  
      top: 50%;
    }
    &--left-active {  
      @include paneactive($btn-flip, 0, 0);
    }
    &--right-active { 
      @include paneactive($btn-flip, 0, -105px);
    }

参考文章

clean-code-javascript
SCSS — 缩减50%的样式代码
风格指南-vue.js

猜你喜欢

转载自blog.csdn.net/weixin_42565137/article/details/104038427
今日推荐