# 前端开发规范

这个文档主要提供项目开发规范文档

# 命名规范

# 🔆 前端命名规范

1、项目名称
全部采用小写方式,以横线分隔或以下划线分隔
例:my-project-name
2、目录名称:有复数结构时,要采用复数命名法
例:scripts, styles, images, datas
4、文件名称:js文件名、scss文件名:采用中间连字符(*+"-"+*)
例:account-model.js、account-model.scss
5、vue文件名:中间连字符
例如:account-model/index.vue,account-model/components/page.vue
6、vue页面中的 name 属性:中间连字符 (name必填且唯一)
例如:y-title
7、文件夹名称:中间连字符
例如:my-document
8、data变量:小驼峰。例如:dataName:'',根据不同类型添加初始数据声明:
    1)对于初始值是字符串类型的字段:userName:''
    2)对于初始值是 数组类型 的字段:userList:[]
    3)对于初始值是 对象类型 的字段:userInfo:{} 或时间对象:nowTime:new Date()
    4)对于初始值是 布尔类型 的字段:isUserEdit:false 或 isUserEdit:true
    5)对于初始值是 数字类型 的字段:userNum:0 或没有初始值的时候 userNum:NaN

9、方法命名:小驼峰
例如:myMethod()
10、组件引入:大驼峰
例如:import GCardHeader from '@/components/g-card-header/index.vue'
 components: {
    GCardHeader,
  }
11、样式选择器命名:class和id
    1)、类名命名=>单词+-+单词,如fine-home。连字符 '-'
    2)、Id命名=>单词+’_’+单词,如fine_home。下划线连接
12、图片命名规范
    1)、不要用拼音,尽量使用英文
    2)、统一使用下划线 nav_right_back.png
    3)、注意区分倍图@2x 和@3x 的后缀,例如banner_@2x.png
    4)、图片的名称分为头尾两部分,用下划线隔开,
    a、头部表示此图片的大类性质,例如广告,标志,菜单,按钮等
        banner:放置在页面顶部的广告,装饰图案等长方形的图片
        logo:标志性的图片
        button:在页面上位置不固定,并且带有链接的小图片
        menu:在页面中某一位置连续出现,性质相同的链接栏目的图片
        pic:装饰用的图片
        title:不带链接表示标题的图片
    b、尾部结合应用具体命名,比如:
        banner_sohu.gif, banner_sina.gif
        menu_aboutus.gif,menu_job.gif
        title_news.gif
        logo_police.gif
        pic_people.gif

# 1.组件命名规范

  • 名称不能重复 (强制)
  • 名称要有意义,做到见名知意 (强制)
  • 不能使用拼音命名 (强制)

# 2.data 变量命名规范

data 属性名应该尽量能够做到见名知意,一般来说需要突出两到三个重点:

  • 这个变量是关于什么业务行为的?
  • 这个变量是关于什么组件的?
  • 这个变量是关于组件什么特性的?
  • 加上变量注释

# 3.方法命名规范

事件方法命名格式 handleXxxxx, 其他方法命名格式 fnXxx,或方法功能含义命名

# 4.路由规范

1、路由命名由两部分组成:模块名+具体功能名。命名:连字符'-'链接,例如:

{
    path: "/login-module/login", //登录页,命名:连字符'-'链接
    name: "login",
    meta: {
        needLogin: false,
        title: "登录页"
    },
    component: () => import(/* webpackChunkName: "loginModule" */"@/views/login-module/login/index.vue")
},
{
    path: "/login-module/reset-pwd", //重置密码页,命名:连字符'-'链接
    name: "reset-pwd",
    meta: {
        needLogin: false,
        title: "重置密码页"
    },
    component: () => import(/* webpackChunkName: "loginModule" */"@/views/login-module/reset-pwd/index.vue")
}
//路由嵌套
{
    path: "/role-management",
    name: "role-management",
    component: () => import(/* webpackChunkName: "setting" */ "@/views/setting-module/role-mangement"),
    redirect: "/role-management/set-auth",//该文件夹下默认打开的路由
    meta: {
    title: "角色管理"
    },
    children: [
    {
        path: "/role-management/set-auth",
        name: "set-auth",
        component: () => import(/* webpackChunkName: "setting" */ "@/views/setting-module/role-mangement/components/set-auth.vue"),
        meta: {
        title: "角色权限设置"
        }
    }
    ]
},

2、路由目录

├─src                       # 源代码
│  ├─router                 # 存放路由文件
│  │  ├─common
│  │  │  └─index.js         # 公共模块路由
│  │  ├─login
│  │  │  └─index.js         # 登录模块路由
│  │  └─after-each.js       # 路由拦截器:afterEach
│  │  └─before-each.js      # 路由拦截器:beforeEach
│  │  └─index.js            # 自动注册路由

# 🔆 图片使用规范

# Web 端

# 1、PNG/JPG/SVG 格式
img-rule
# 方案一:如上图所示:
  • 实际代码设置图片宽(width)高(height)以 1 倍图的宽高进行展示;即上图案例中源文件下载宽高:180x180px;页面代码设置宽高:90x90px,提高图片展示清晰度。
  • png 格式的 1 倍和 2 倍的展示效果对比如下:
img-rule-test
# 方案二:

推荐使用 svg 格式,展示清晰度最高,文件小。svg 与 png 格式的 1 倍和 2 倍的展示效果对比如下:

img-rule-svg@2x

web 端 svg 图片下载方式如下图:

img-rule-svg-download

# 移动端

注意:移动端下载的图片以 750px 设计稿为标准,代码设置的图片宽高就是下载下来的 2 倍图的宽高

# 方案一:

移动端推荐使用 svg 格式,展示清晰度最高,文件小。svg 与 750px 标准下的 png 格式 2 倍图的展示效果对比如下:

img-rule-svg

移动端端 svg 图片下载方式如下图:

img-rule-mb-svg

# SVG 图片展示-使用方法

常用方式:

<img :src="require('@/assets/test.svg')" />

svg-icon 使用 svg-sprite-loader:

<svg-icon icon-class="test" />

# 🔆 接口使用规范

1、调用页面 test.vue,如下:

<script>
// 1、引入数据接口
import {commonApi} from "@/api";
export default {
  name: "",
  methods:{
    /**
     * @description:获取表格数据
     * @param {type}
     * @return:
     * @author: chenyt
    */
      getTableData() {
        this.loading = true;
        //2、Api方法,传入接口参数
        commonApi.getListReset(this.pageData.listQuery).then(response => {
          this.tableDatas = response.data.items;
          this.pageData.total = response.data.total;
          // Just to simulate the time of the request
          setTimeout(() => {
            this.loading = false;
          }, 1.5 * 1000);
        });
      }
  }
}
</script>

2、接口 Api 方法定义

//定义接口文件
import request from "@/utils/request";
const basePath = "/table";
// get
/**
 * @description:获取重置数据列表
 * @param {type}
 * @return:
 * @author: chenyt
 */
export function getListReset(params) {
  return request({
    url: `${basePath}/list2`,
    method: "get",
    params: params,
  });
}
//post
/**
 * @description:获取二维码
 * @param {type}
 * @return:
 * @author: chenyt
 */
export const getQRCode = function(params) {
  return request({
    url: `${basePath}/getQRCode`,
    method: "post",
    data: params, // 如果请求方式不是post需要将data改为params
  });
};

3、汇总在 index.js 中,提供按模块输出接口函数,模块命名:“*+Api”,对应 modules 下的模块名称,如下所示:

//接口暴露文件index.js
import * as loginApi from "./modules/login-api";
import * as commonApi from "./modules/common-api";
export { loginApi, commonApi };

4、目录结构

├─src                       # 源代码
│  ├─api                    # 存放api接口文件
│  │  ├─modules             # 根据业务需求划分模块放置接口文件
│  │  │  └─common-api.js    # 公共接口
│  │  │  └─login-api.js     # 登录模块接口,’-api‘结尾,对应views下的页面模块命名
│  │  ├─axios.js            # axios请求文件,配置统一请求设置和返回拦截
│  │  └─index.js            # 向外暴露接口模块

# 🔆 assets资源文件

1、存放图片资源文件,imgs 文件夹下

2、存放数据字典,data 文件夹下

3、根据 views 下的模块划分 imgs 文件夹内部的二级文件夹名称,与页面一一对应。

4、文件目录结构

├─src                       # 源代码
│  ├─assets                 # 存放页面静态资源文件
│  │  ├─imgs                # 存放图片文件夹
│  │  │  ├─common           # 公共图片文件夹
│  │  │  │  └─loading.gif   # 加载gif
│  │  │  ├─login            # 登录模块图片文件夹,根据大模块划分,存储模块下所有图片
│  │  │  └─logo.png         # logo图片
│  │  ├─data                # 数据文件
│  │  │  └─common-dict.js   # 公用数据字典文件

# 书写规范

# 🔆 样式书写规范

1、组件样式请记住加上 scoped 或者命名空间,避免造成全局的样式污染

2、样式选择器应避免使用元素选择器, 推荐类选择器。划分为:header-*container-*footer-*

<style scoped lang="scss"  type="text/scss">
  .header-box { padding: 20px }
</style>

3、尽量给每个页面,添加一个父类。以“page-”开头,如下所示:

<template>
  <div class="page-login"></div>
</template>

其他样式在此父类下编写

<style scoped lang="scss"  type="text/scss">
  .page-login {
    padding: 20px
    .other-class{
       ....
    }
  }
</style>

4、少量样式可以写在组件,大量样式需要引入样式文件。

5、全局的样式变量文件和样式文件,存储在styles文件夹中

6、样式文件夹目录

├─src                       # 源代码
│  ├─styles                 # 存放页面公用样式文件
│  │  ├─iconfonts           # 存放图标
│  │  ├─theme               # 页面主题设置,一般用于重置vant-ui或者element-ui组件样式
│  │  │  └─resetui.less     # 重置样式文件
│  │  └─animate.scss        # 动画
│  │  ├─common.scss         # 公用样式
│  │  ├─normalize.scss      # 浏览器重置样式文件
│  │  └─common-params.scss  # 全局样式变量

# 🔆 业务组件编写规范

根据业务编写的可复用组件,请务必对每个属性、方法添加注释。并且将组件的使用说明编写对应的 readme 文档

# 🔆 组件文件目录规范

├─src                       # 源代码
│  ├─components             # 存放业务组件
│  │  ├─global              # 存放全局注册组件
│  │  │  ├─y-title          # 全局注册组件’y-title‘
│  │  │  │  └─index.vue     # 组件对应文件
│  │  │  │  └─README.md     # 组件使用说明readme
│  │  │  └─y-banner         # 全局注册组件’y-banner‘
│  │  ├─y-title             # 组件’y-title‘
│  │  │  └─index.vue        # 组件对应文件
│  │  │  └─README.md        # 组件使用说明readme
│  │  └─index.js            # 注册全局组件
  • 1、组件文件夹命名 以“y-“开头。例如 y-title
  • 2、全局注册放在 globle 文件夹下,实现自动注册

# 组件 README 文档编写格式参考

## 动画加载

### 如何使用
```js
this.$Loading.show()

this.$Loading.hide()
```js
### API

| name | 描述 | 参数     |
| ---- | ---- | -------- |
| show | 展示 | duration |
| hide | 关闭 ||


### Options

| 参数     | 说明                                           | 类型     | 默认值 |
| -------- | ---------------------------------------------- | -------- | ------ |
| duration | 延迟多少秒自动关闭 当`duration`0时不自动关闭 | `number` | 0      |

# 🔆 views页面文件规范

views下添加业务页面,页面 template 中的标签控制长度,当某个模块例如弹窗模块标签行数很长,导致页面可读性低,应控制页面标签长度,独立此模块放在该文件夹下的 components 中。目录如下

├─src                                 # 源代码
│  ├─views                            # 存放业务页面文件
│  │  ├─login-module                  # 根据业务划分页面存放模块
│  │  │  ├─login                      # 登录页面文件夹
│  │  │  │  └─components              # 登录页面可分模块放置的文件
│  │  │  │  │  └─dialog-module.vue    # 分割出来的弹窗模块组件
│  │  │  │  └─index.vue               # 登录页面文件
│  │  │  └─reset-pwd                  # 重置密码,文件夹命名:用中间连字符“-”
│  │  │     └─index.vue
│  │  ├─other-module                  # 其他模块
│  │  │  ├─other                      # 其他模块页面
│  │  │  │  └─components              # 其他模块页面业务模块文件
│  │  │  │  └─index.vue               # 其他模块页面
│  │  │  └─reset-page                 # 其他模块
│  │  │     └─index.vue               # 其他模块页面
│  │  │     └─style.scss              # 样式文件很长的时候,另存在样式文件中
  • 1、文件夹命名:用中间连字符“-”,以’-module‘结尾,划分模块。
  • 2、页面划分过长的业务模块存放于 components 文件夹中
  • 3、文件内容统一引入存放在 index.vue 中
  • 4、样式文件很长的时候,另存在样式文件中

# 🔆 代码注释

  • 页面基本信息注释
<!--
 * @Description: 首页
 * @Version: 0.1
 * @Autor: chenyt
 -->
  • 页面方法注释
/**
 * @description:初始化
 * @param {type}
 * @return:
 * @author: chenyt
 */

# 提交规范

# 🔆 代码提交规范

# 1、代码提交必须包含提交类别

用于说明 commit 的类别,只允许使用下面 9 个标识:

  • feat:新功能
  • fix:修复 bug
  • docs:撰写文档
  • style:代码格式(不影响代码运行的变动)
  • refactor:重构(既不是新增功能,也不是修改 bug 的代码变动)
  • test:增加测试
  • build:工程化
  • chore:代码优化或辅助工具的变动

    例如:fix:修改登录自动退出的 bug。

# 2、执行 npm run lint

规范 eslint 规则

# 3、提交合并

保证功能完整性,提交到个人开发分支远程后,合并到 develop 分支

# 🔆 代码分支管理统一

1、分支通常可以对应研发流程中不同的部署环境:

  • tag -> 生产环境(production)
  • master -> 预发/灰度环境(pre-production/staging)
  • develop -> 测试环境(test)
  • feature -> 线下调试/开发环境,例如:feature/cyt

2、使用过无用的分支定期清理掉

# 用户体验

若需求方无特殊要求,则按照以下规则。

# 🔆 前端表格规范 - 严格要求

# 颜色值

  1. UI 没有给出明确色值时,表头背景颜色值: #F0F2F5; 选中或鼠标悬停在某一行时,此行背景颜色值应为: #DEE9F5;

# 表格中数据展示应符合下述要求

  1. 表头数据 居中 展示
  2. 同一列文本数据长短不一致的应 居左 展示,例如单位名称、地址;
  3. 统一列数据长短基本一致的应 居中 展示,例如姓名、性别、日期、审核状态
  4. 金额、数字内容应 居右 展示,对应表头标题应使用 半角括号 注明单位,例如“金额(元)”
  5. 金额应保留两位小数点
rule_table

# 表格交互应符合下述要求

  1. 表格数据较多时可显示拖动滑块; 宜根据操作需求,提供编辑功能;
  2. 表格列宽结合实际内容不能全部统一宽度;
  3. 主动询问了解表格数据量,询问是否需要做分页及其分页策略

# 表格展示

用于查询后的数据展示时,表格的第一列应为序号; 表格中使用多选框和单选框时,设置在序号左侧;

# 表格滚动条

滑动横向滚动条时保留重要字段;如操作区域、表头区域。

# 🔆 前端数据校验规范

# 身份证

  1. 号码长度验证:身份证长度仅存在 15 位或 18 位两种长度;
  2. 号码正确性验证:如身份证号为 18 位,可根据本体码与校验码得关系验证身份证号码输入有误(本体码包括地址码、出生日期码和顺序码,根据本体码,通过采用 ISO 7064:1983,MOD 11-2 校验码系统计算出校验码。);
  3. 根据 18 位与 15 位身份证号码编码规则及校验码算法,将 15 位身份证号码转换为 18 位身份证号码(a.出生日期码:15 位身份证号码中出生日期码为 4 位,其中年份代码仅有 2 位,如 590328,代表 1959 年生。b. 校验码:15 位身份证号码中无校验位。);
  4. 校验码为 X:因校验码为 X,实际上有大小写输入不同,请注意兼容或统一。
  5. 号码真实性:真实姓名和身份证号在公安系统进行匹配真实性。

# 手机号

  1. 第一位必须为数字 1;
  2. 第二位不能为 0/1/2;
  3. 数字长度必须为 11 位,多了少了都不行;
  4. 必须输入阿拉伯数字,其他数字、字母、汉字和符号均不可输入。

# 登录密码

如没特殊要求,为了方便老年人的同时,尽可能保证账户的安全性,密码长度为 6 到 8 位数字或字母或数字和字母组合,字母不区分大小写。不能输入汉字和各种符号。

# 电子邮箱

  1. 电子邮件的邮箱地址格式:用户标识符+@+域名;
  2. @之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.);
  3. @和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着;
  4. 最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于 2 个字节,小于等于 6 个字节。

# 金额

  1. 不能输入中文、特殊符号
  2. 只能输入一个点(.)

# 🔆 前端表单优化

# 1. 标签

  1. 表单中 label 一般不宜太长,尽量不换行(适当调整 label-width)。
  2. 必填项需标记“*”,若全为必填则不标记

# 2.输入域

  1. 输入框 带有 clearable 清空属性
<el-input
  placeholder="请输入内容"
  v-model="input"
  clearable>
</el-input>
  1. 单选框、多选框:可以单击它或关联标签来激活/禁用它
<input type="checkbox" id="option1" /> <label for="option1">Option 1</label>

或者

<label for="option1">
  Option 1
  <input type="checkbox" id="option1" />
</label>
  1. 密码输入框 增加显示密码功能-右侧小眼睛图标,便于用户看到输入的错误。

# 3.触发校验

在完成一个字段后进行内联验证,比如当姓名输入框失去焦点后,再进行验证。 不要在输入过程中进行验证,否则用户还未输入完成会一直出现错误。

# 4.错误信息提示

输入域错误提示时,带上校验规则说明,如:

  1. "请输入用户名" 换成 "请输入字母开头,3-20 位的用户名"
  2. "请输入密码" 换成"请输入 6-20 位由字母大小写和数字组成的密码"

# 5.操作按钮

操作按钮通常分为主次按钮,如:提交和取消,保存和取消等。

  1. 按钮默认位置:左侧为次要线框按钮,右侧为主要色块按钮。
  2. 表单有清空/重置按钮等回退按钮。
  3. 查询表单建议重置按钮,清空表单同时触发查询。

# 6.键盘

请使用与预期输入相匹配的键盘,如手机号使用数字键盘

# 🔆 避免重复请求 - 重要

  1. 业务提交时,需要使用带遮罩的 loading,避免用户重复提交
  2. 封装全局请求方法,避免接口重复请求
// 使用示例,第一个参数name不可重复
export function queryUnitGroupByPage(data = {}, config = {}) {
  return yRequest.post("unitSettingQuery", "/gbjd/Unit/queryUnitGroupByPage", data, config)
}

/*
 * @Description: 封装全局请求方法
 * @Autor: syx
 */
import axiosRequest from "./common-axios"
const GLOBAL_REQUEST_OBJ = {}
function request(name, params) {
  return new Promise((resolve, reject) => {
    if (GLOBAL_REQUEST_OBJ[name] && GLOBAL_REQUEST_OBJ[name] === "requesting") {
      return
    }
    GLOBAL_REQUEST_OBJ[name] = "requesting"
    axiosRequest(params).then(result => {
      delete GLOBAL_REQUEST_OBJ[name]
      resolve(result)
    }).catch(err => {
      delete GLOBAL_REQUEST_OBJ[name]
      reject(err)
    })
  })
}

["get", "post"].forEach(type => {
  request[type] = (name, ...params) => {
    return new Promise((resolve, reject) => {
      if (GLOBAL_REQUEST_OBJ[name] && GLOBAL_REQUEST_OBJ[name] === "requesting") {
        return
      }
      GLOBAL_REQUEST_OBJ[name] = "requesting"
      axiosRequest[type].apply(this, params).then(result => {
        delete GLOBAL_REQUEST_OBJ[name]
        resolve(result)
      }).catch(err => {
        delete GLOBAL_REQUEST_OBJ[name]
        reject(err)
      })
    })
  }
})

export default request

# 🔆 其他优化

# 1.手型鼠标

链接或可点击区域,光标移入变成手型鼠标

# 2.点击区域

提供足够大的点击区域,如标题和对应图标都应有绑定事件。移动端谷歌建议最小区域为 48x48px 可作为参照。

# 3.图片显示优化

图片尺寸、比例与显示比例不一致,可使用 object-fit:cover 优化,避免图片拉伸变形

# 4.弹窗

  1. 弹窗宽度:同类型弹窗尽可能宽度保持一致,常见 PC 端弹窗宽度尺寸为:640px、720px、960px;

  2. 弹窗高度:整个弹窗高度不要超过90vh, 可以设置 .el-dialog__body 的最大高度, 最小高度也不小于260px;

.el-dialog__body {
    padding: 16px 24px;
    max-height: 64vh; // 最大高度设置
    min-height: 260px; // 最小高设置
    overflow: auto;
}

对比如下:

dialog_body_height

更新时间: 5/18/2022, 2:27:47 PM