前端web代码设计规范

709 阅读9分钟

公司Web代码设计规范

版本说明

版本号撰写人审批人提交日期版本说明
V1.0cbb*2022.2.16初版,面向公司前端Coder
V1.1cbb*2022.2.17增加禁用说明,加入便捷开发推荐、代码提交规范

注意

本篇代码设计规范针对公司目前前端框架设立,不涉及前端框架搭建部分,vue部分针对2.x版本,对3.x版本不适用。

一、命名规范

1.文件目录

  • HTML文件夹 pages || views
  • JS文件夹 js
  • CSS文件夹 style
  • 路由文件夹 router
  • API文件夹 api
  • 三方库 plugins
  • 公用方法 utils
  • 说明文档 lib
  • 自定义组件 components
  • 静态文件 assets
    • 图片及SVG文件夹 img
    • 字体图标文件夹 icon
    • 三方字体文件夹 fonts

2.文件命名

确保文件命名总是以字母开头而不是数字,且字母一律小写,以下划线连接且不带其他标点符号,如:

<!-- HTML -->
jr.html
jr_list.html
jr_detail.html

<!-- SASS -->
jr.scss
jr_list.scss
jr_detail.scss

3.代码命名

  • ClassName命名规范 ClassName的命名应该尽量精短、明确、见名知意,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “_” 连接

    基于姓氏命名法(继承 + 外来),祖先模块不能出现下划线,除了是全站公用模块,如 mod_ 系列的命名:

<!--组件内模块-->
<div class="modulename">
	<div class="modulename_info">
		<div class="modulename_son"></div>
		<div class="modulename_son"></div>
		...
	</div>
</div>
	
<!-- 这个是全站公用模块,祖先模块允许直接出现下划线 -->
<div class="mod_info">
	<div class="mod_info_son"></div>
	<div class="mod_info_son"></div>
	...		
</div>

当子孙模块超过4级或以上的时候,可以考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块

<div class="modulename">
	<div class="modulename_cover"></div>
	<div class="modulename_info">
    	<div class="modulename_info_user">
    		<div class="modulename_info_user_img">
    			<img src="" alt="">
    			<!-- 这个时候 miui 为 modulename_info_user_img 首字母缩写-->
    			<div class="miui_tit"></div>
    			<div class="miui_txt"></div>
    			...
    		</div>
    	</div>
    	<div class="modulename_info_list"></div>
	</div>
</div>
  • JavaScript内命名规范

    1.变量名 命名方式: 全 英文小写 或 小驼峰式 命名方法

    2.函数命名 命名方式: 全 英文小写 或 小驼峰式 ( 构造函数使用大驼峰命名法 )

    ​ 命名规则:前缀为动词 如:get、fetch、refresh、delet等

    3.常量名 命名方法:全部大写

       命名规范:使用大写字母和下划线来组合命名,下划线用以分割单词

    /*变量名*/
    let arrList = [];
    let objData = {};
    /*函数命名*/
    function fetchFormData(){...}
    const getTableData = ()=>{...}
    /*构造函数命名*/
    class WelcomPerson{
    	constructor(name){
    		this.name = name
    	}
    	say(){
    		return 'welcome!' + this.name + ',你好'
    	}
    }
    /*常量名*/
    const BASE_URL = 'http://192.168.0.186:8002';
    const TITLE = 'JROK-首页'
    

二、代码规范

团队约定

统一团队的编码规范,有助于代码的维护。

1. HTML

  • 除非有特定的功能、组件要求等,禁止随意使用id来定义元素样式,尽量使用class类名。

  • 标签语法无错误,需要符合语义化。

  • 所有具有开始标签和结束标签的元素都要写上起止标签,某些允许省略开始标签或和束标签的元素亦都要写上。

    <!--推荐-->
    <img src='' /> <br/> <input />
    <!--禁止-->
    <img src=''> <br> <input>
    
  • HTML标签名、类名、标签属性和大部分属性值统一用小写 ;

    <!--推荐-->
    <div> <h1></h1> </div>
    <!--禁止-->
    <DIV> <H1></H1> </DIV>
    
  • 文本可以和字符引用混合出现,尽量使用html转义符。HTML转义字符对照表

    <!--推荐-->
    <a href="#">more&gt;&gt;</a>
    <!--不推荐-->
    <a href="#">more>></a>
    
  • 段落元素与标题元素只能嵌套内联元素。

    <!--推荐-->
    <h1> <span></span> </h1>
    <!--禁止-->
    <span> <h1></h1> </span>
    
  • 段落换行尽量使用块状标签包裹换行,不推荐使用br、hr等标签换行

    <!--推荐-->
    <p>第一行</p> <p>第二行</p>
    <!--不推荐-->
    <p>第一行<br/>第二行</p>
    
  • 页面中svg等图源样式的引入使用img标签包裹引入

    <!--推荐-->
    <img src='asstes/svg/title.svg'/>
    <!--禁止-->
    

直接将svg的代码粘贴到html中




#### 2. CSS

- 代码大小写:样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。

```css
/* 推荐 */
.jrc{
display:block;
}
/* 禁止 */
.JrC{
DISPLAY:BLOCK;
}
  • 选择器:尽量少用通用选择器 *

    /* 推荐 */
    .jrc {}
    .jrc li {}
    .jrc li p{}
    /* 不推荐 */
    *{}
    #jrc {}
    .jrc div{}
    
  • 禁止使用层级过深的选择器,最多3级。

    /*错误示范:*/
    .without-animation .book-body .body-inner .book-header .dropdown .dropdown-menu .buttons{}
    
  • z-index层级不推荐超过三位数,层级太高容易串层,后期维护繁杂。

  • 尽量使用flex布局,减少float布局的使用。原因:浮动布局容易脱离文本域。

3. JS

  • 在使用axios请求方式中,尽量使用promise异步请求方式,且请求按页面模块封装在api文件内,在调用文件中以引入方式调用。

    //api-index.js
    import axios from "@/utils/axios" //引入封装后axios
    /******* 
     * @description: template
     * @param {*} data
     * @return {*} promison Data
     */
    export const templateApi = (data) => {
      return request({
        url: "/api/url",
        method: "post",
        data
      })
    }
    ----------------------------------------------------------------
    //index.vue 
    //不推荐 
    //此写法不方便进行全局接口拦截 耦合度高 且链式调用容易形成“面条代码”
    const getData () => {
        this.$axios.post('/api/url',data).then((res)=>{...}).catch((err)=>{...})
    }
    //推荐
    //分类书写 降低耦合度 后期方便维护
    import { templateApi } from '@/api/index'
    //采用async异步调用并配合try catch捕捉error
    const getData = async () =>{
       const data = {}
       try{
           const res = await templateApi(data)
           console.log(res)
           ...
       }catch(err){
           console.error(error)
       }
    }
    //或者 
    //异步调用与链式调用相结合 节约代码量
    const getData = async () =>{
       const data = {}
       const res = await templateApi(data).catch(err=>{...})
       console.log(res)
       ...
    }
    
  • 请尽量使用es6+规范书写;

    • 对象简写

      /*对象简写*/
      const job = 'JavaCoder'
      let item = {}
      //不推荐
      item = {
          job:job
      }
      
      //推荐
      item = {
          job
      }
      
    • 函数表达式、箭头函数

      /*函数表达式 
      使用具名函数表达式而非函数声明  原因:提高可维护性*/
      /*箭头函数  
      当你必须使用函数表达式(传递匿名函数)时,使用箭头函数标记 
      原因:它将创建在 this 上下文中执行的函数版本,通常是您想要的,并且语法更简洁*/
      //不推荐
      function filterTime(){...}
      [1,2,3].forEach(function(){...})
      
      //推荐
      const filterTime = ()=> {...}
      [1,2,3].forEach(()=>{...})
      
    • 展开运算符

      /*展开运算符 ... */
      const obj = {a:1,b:2}
      const arr = [1,2]
      //合并新对象、数组
      //不推荐
      const newObj = Object.assign(obj,{c:3})
      const newArr = arr.connect([3])
      
      //推荐
      const newObj = {...obj,c:3}
      const newArr = [...arr,3]
      
    • 解构赋值、模板字符串

      /*解构赋值  模板字符串*/
      // 不推荐
      const getFullName = (user) => {
        const firstName = user.firstName
        const lastName = user.lastName
        return firstName + lastName
      }
      
      // 推荐
      const getFullName = (user) => {
        const { firstName, lastName } = user //声明解构
        return `${firstName} ${lastName}` //模板字符串
      }
      
      // 五星好评
      const getFullName = ({ firstName, lastName }) => { //传值结构
        return `${firstName} ${lastName}`
      }
      
    • es6模块的输出与输入

      /*es6模块的输出与输入*/
      // 不推荐
      const util = require('./util')
      module.exports = util
      
      // 推荐
      import Util from './util'
      export default Util
      
      // 五星好评
      import { Util } from './util'
      export { Util } 
      
  • 请记得 constlet 都是块级作用域,var 是函数级作用域,对所有引用都使用 constlet,不要使用 var

    原因:var有污染页面全局变量的风险;

    /*const、let*/
    // 不推荐
    var name = 'JROK'
    var age = 18
    
    // 推荐
    const name = 'JROK' //常量
    let age = 18 //变量
    
    /*将所有的 const 和 let 分组*/
    // 不推荐
    let a
    const b
    let c
    const d
    let e
    
    // 推荐
    const b
    const d
    let a
    let c
    let e
    
  • 不允许出现未被使用的变量;

  • 尽量不要出现“魔术字符串”

    //不推荐
    if(objName === 'JAVA'){...}
    //推荐
    const coder = 'JAVA';
    if(objName === coder){...}
    
  • 不要修改内置对象,如 ObjectArray;原因:避免造成其他页面调用相同方法后调用失败

  • 使用 ===!== 而非 ==!=,避免类型的隐式转换;

    //不推荐
    0 == '0' //true
    //推荐
    0 === '0' //false
    

4. VUE

  • 少用watch监听值的变化,多使用双向绑定或者组件方法@change或者@input,原因:降低运行效率,且耦合度高,不利于后期维护
  • 因vue单页面SPA框架特性,页面中创建的定时器如:setTimeout,setInterval、事件监听如:addEventListener、onload需在页面销毁前即:beforeDestroy()中进行销毁,如若不然则会在下个页面继续执行,造成报错阻塞或污染,影响下一页面代码逻辑执行。

  • 组件的 data 必须是一个函数,原因:避免变量污染
    //不推荐 
    export default {
      data: {
        foo: 'bar'
      }
    }
    //推荐
    export default {
      data () {
        return {
          foo: 'bar'
        }
      }
    }
    
  • Prop 定义应该尽量详细
    //不推荐
    props: ['status']
    //推荐
    props: {
      status: {//值名称
        type: String,//传递值类型
        required: true,//传递值是否必须
      }
    }
    
  • v-for 设置键值 key 总是用 key 配合 v-for ,原因:精准diff算法需要,通过key值来提升渲染的效率。
    Vue2.0 v-for 中 :key 到底有什么用? - 知乎 (zhihu.com)
    <!--禁止-->
    <ul>
      <li v-for="todo in todos">
        {{ todo.text }}
      </li>
    </ul>
    <!--推荐-->
    <ul>
      <li
        v-for="todo in todos"
        :key="todo.id"
      >
        {{ todo.text }}
      </li>
    </ul>
    
  • 避免 v-ifv-for 用在一起 **永远不要把 v-ifv-for 同时用在同一个元素上。**原因:带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
    <!--不推荐-->
    <ul>
      <li
        v-for="user in users"
        v-if="shouldShowUsers"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>
    <!--推荐-->
    <ul v-if="shouldShowUsers">
      <li
        v-for="user in users"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>
    
  • 为组件样式设置作用域,原因:防止样式变量污染,设置作用域scoped后当前样式只作用于当前页面。
    <!--不推荐-->
    <style>
    .btn-close {
      background-color: red;
    }
    </style>
    
    <!--推荐-->
    <!-- 使用 `scoped` attribute -->
    <style scoped>
    .button {
      border: none;
      border-radius: 2px;
    }
    </style>
    
  • 指令缩写,原因:提高代码简洁度
    <!--不推荐-->
    <input
      v-on:input="onInput"
      v-bind:value="newTodoText"
    >
    <!--推荐-->
    <input
      v-model='newTodoText'
    >
    
  • 书写顺序
    • 单文件顺序
      <!-- ComponentA.vue -->
      <script>/* ... */</script>
      <template>...</template>
      <style>/* ... */</style>
      
    • 标签内attribute顺序
      1. 定义 (提供组件的选项)

        • is
      2. 列表渲染 (创建多个变化的相同元素)

        • v-for
      3. 条件渲染 (元素是否渲染/显示)

        • v-if
        • v-else-if
        • v-else
        • v-show
        • v-cloak
      4. 渲染方式 (改变元素的渲染方式)

        • v-pre
        • v-once
      5. 全局感知 (需要超越组件的知识)

        • id
      6. 唯一的 attribute (需要唯一值的 attribute)

        • ref
        • key
      7. 双向绑定 (把绑定和事件结合起来)

        • v-model
      8. 其它 attribute (所有普通的绑定或未绑定的 attribute)

      9. 事件 (组件事件监听器)

        • v-on
      10. 内容 (覆写元素的内容)

        • v-html

        • v-text

    • 组件/实例的选项应该有统一的顺序。

      这是我们推荐的组件选项默认顺序。它们被划分为几大类,所以你也能知道从插件里添加的新 property 应该放到哪里。

      1. 副作用 (触发组件外的影响)
        • el
      2. 全局感知 (要求组件以外的知识)
        • name
        • parent
      3. 组件类型 (更改组件的类型)
        • functional
      4. 模板修改器 (改变模板的编译方式)
        • delimiters
        • comments
      5. 模板依赖 (模板内使用的资源)
        • components
        • directives
        • filters
      6. 组合 (向选项里合并 property)
        • extends
        • mixins
      7. 接口 (组件的接口)
        • inheritAttrs
        • model
        • props/propsData
      8. 本地状态 (本地的响应式 property)
        • data
        • computed
      9. 事件 (通过响应式事件触发的回调)
        • watch
        • 生命周期钩子 (按照它们被调用的顺序)
          • beforeCreate
          • created
          • beforeMount
          • mounted
          • beforeUpdate
          • updated
          • activated
          • deactivated
          • beforeDestroy
          • destroyed
      10. 非响应式的 property (不依赖响应系统的实例 property)
        • methods
      11. 渲染 (组件输出的声明式描述)
        • template/render

        • renderError

三、注释规范

目的和原则

提高可读性和可维护性 如无必要,勿增注释;如有必要,尽量详尽

语法和快捷键

单行注释:// 快捷键: ctrl+/ 多行注释:/**/ 快捷键: ctrl+shift+/

规范

1、注释符与注释内容之间加一个空格 2、注释行与上方代码间加一个空行

HTML顶部文档注释

 <!--
 * @Author: name
 * @Date: 2022-02-11 09:44:53
 * @LastEditTime: 2022-02-17 10:26:39
 * @LastEditors: name
 * @Description: 
 * @FilePath: \views\platform\bill\task\index.html
-->

CSS

/* content */
内容
/* end content */

JS

 /**
   * @description: 获取表格数据
   * @param {Number} type 类型
   * @return {*}
   */
const getTableData(type) =>{...}

四、便捷开发规范

好的软件、工具能更好的实现便捷开发,团队约定

  • 开发工具:

    • Visual Studio Code
  • VS Code插件:

    • ESLint //代码格式规则检查
    • css-auto-prefix //css书写自动添加兼容
    • koroFileHeader //快捷生成注释
    • Prettier //代码格式化
    • Vue 3 Support - All In One //vue快捷提示、代码格式化
    • filesize //引入文件大小展示
    • Auto Close Tag //自动闭合html标签
    • Auto Rename Tag //自动重命名html标签名
    • Color Highlight //color高亮
  • 调试工具:

    • Chorme
    • Edge
    • 微信开发者工具
    • Postman
  • 浏览器插件:

    • Vue.js devtools //vue官方调试工具
    • JSON Viewer //网页Json查看
  • 环境:

    • Node 14.* //向下兼容 不选择最新版本

    • npm

      • 更改至淘宝源

        npm config set registry http://registry.npm.taobao.org/

    • cnpm

      • 安装

        npm install -g cnpm -registry=https://registry.npm.taobao.org

  • 网盘下载:

    WebPlugins

    阿里云盘 提取码: e33q

五、代码提交规范

  1. 提交代码前必须解决所有页面报错

  2. 先拉取,如有冲突解决后,再提交

  3. 禁止代码同步功能

  4. 提交信息commit message 必须填写,格式为 type + content

    <!--修复-->
    fix:修复问题
    
    <!--更新-->
    update:更新代码
    
    <!--添加-->
    add:添加文件
    
    <!--删除-->
    del:删除某个文件