前端代码规范:

497 阅读4分钟

前端代码规范:

1.整体代码规范按照Airbnb规范:在项目中集成Airbnb+eslint+prettier

1.eslint的集成:

yarn add eslint --save-dev

安装之后生成eslintrc.js文件,

./node_modules/.bin/eslint --init
or
npx eslint --init

创建eslint模板,airbnb,初始化文件。

2.prettier的集成

yarn add prettier --save-dev

安装之后手动创建.prettierrc[yml, json,js]文件。

3.安装eslint-prettier插件

yarn add eslint-config-prettier eslint-plugin-prettier --save-dev

4.配置eslintrc文件:

"extends": [
    ....
    "plugin:prettier/recommended"
  ],
  "plugins": [
    ...
    "prettier"
  ],
  "rules": {
    "prettier/prettier": "error"
  }

5.配置prettierrc文件

{
  // 字符串使用单引号
  singleQuote: true,
  // 每行末尾自动添加分号
  semi: true,
  // tab缩进大小,默认为2
  tabWidth: 2,
  // 使用tab缩进,默认false
  useTabs: false,
  // 对象中打印空格 默认true
  // true: { foo: bar }
  // false: {foo: bar}
  bracketSpacing: true,
  // 箭头函数参数括号 默认avoid 可选 avoid| always
  // avoid 能省略括号的时候就省略 例如x => x
  // always 总是有括号
  arrowParens: 'avoid',
  // 换行长度,默认80
  printWidth: 80,
}

eslint是对代码规范性检查,但不保证代码的美观性。代码的美观性是根据prettier插件控制。但两者之间有冲突,通过配置eslint解决。

tailwid css的集成:http://tailwind.wyz.xyz/docs/installation

2.一些属于自己的总结与思考:

不要以中文拼音首字母命名、不要以中文拼音首字母命名、不要以中文拼音首字母命名

2.1 css 中class的命名:

以小驼峰命名:

由于很多我们使用的组件库或者样式库(tailwindi css)都是以中划线命名,为了区分所以使用驼峰命名。

推荐使用tailwind css

2.2 常用js命名:

2.2.1 变量,函数起名符合驼峰外不能太随意,尽可能的见名知意,另外遵守一些规范

1.变量命名:简明知意

避免全局变量,严格避免类型乱用「声明时字符串使用过程时便成数组,对象等」出现潜伏的bug

2. 函数名命名:动词+功能描述

eg:

// bad
getSbxx() {}
getXlxx() {}
getByqxx() {}
​
// good === 获取信息类:
// 获取设备信息
getEquipInfo() {}
// 获取线路数量
getLineNum() {}
// 获取变压器信息
getTransformerInfo() {}
​
// 其他
set            ----- 设置
is/has         ----- 判断:是否/包含
build/create   ----- 构建/创建

2.3 项目中的一些良好风格:

1.组件中的事件命名:原有组件中所自带的事件处理都是以handleXXX命名,应该所有的都按照handleXXX命名,自定义事件可按照函数命名规范即可

// 处理XXX改变
handleChange() {}

2.组件自带事件处理改变值的无需在监听器中监听处理

<el-form-item class="radio_class" @chang="handleRadioChange">
	<el-radio v-model="radio" size="medium" label="配电变压器">配电变压器</el-radio>
		<el-radio v-model="radio" size="medium" label="配电线路">配电线路</el-radio>
</el-form-item>

data() {
return {
 radio: ''
}
},
watch() {
//==== bad 增加性能负担
radio(newVal, oldVal) {
 // Todo...
 this.radio = newVal
}
},

methods: {
//==== good
handleRadioChange(val) {
 // Todo...
 this.radio = val
}
}

3.必须封装统一请求axios,按照项目模块封装接口地址。【在项目的某一个页面中不要出现地址,硬编码问题】,使用时导入,统一在一个配置文件中维护。

// bad:
axios.get("/zuul/pwjkgw/power/getPowerPage", params).then((res) => {
if (res.status === 200 && res.data.list.length > 0) {
 this.tableColumn = itemData;
 this.gridData = res.data.list;
 this.topCardPage.total = res.data.total;
} else {
 this.gridData = [];
 this.topCardPage.total = 0;
}
});
// bad:
// 日常巡检分析站线类型
getZxlx() {
let url = "/zuul/pwjkgw/common/getChartData";
this.$get(url, { type: "rcxcfx@zxlx" }).then((res) => {
 if (res.status == 200 && res.data) {
   this.zxlx = res.data;
 }
});
},

good: 分文件封装请求,分装请求地址,在具体的模块下调用,在具体的页面不要出现请求地址:

http.js

// axios 全局封装:http.js
import axios from "axios";
import { Message } from "element-ui";
import $router from "@/router";
import Qs from "qs";

axios.defaults.timeout = 10000000000; //请求超时20秒
axios.defaults.baseURL = ""; //请求base url
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded"; 
//设置post请求是的header信息
// axios.defaults.headers.post['Content-Type'] = 'application/json'; 
//设置post请求是的header信息
axios.defaults.withCredentials = true;
axios.defaults.headers.Authorization = "Basic ZjFhdXRvYXV0aDpmMWF1dG9hdXRoc2VjcmV0";
//请求拦截器
axios.interceptors.request.use(
data => {
 //在发送请求之前做些什么
 return data;
},
error => {
 //对请求错误做些什么
 alert(error);
}
);

//响应拦截器
axios.interceptors.response.use(
response => {
 if (response && response.data) {
   if (response.data.code && response.data.code !== "0000") {
     Message({
       type: "error",
       message: response.data.message
     });
   }
   return {
     data: response.data,
     header: response.headers
   };
 }
 return response;
},
error => {
 return Promise.reject(error);
}
);

/**
 * 封装get方法
 * @param url
 * @param data
 * @returns {Promise}
 */
export function get(url, param) {
  return new Promise((resolve, reject) => {
    axios.get(url, { params: param }).then(
        response => {
          resolve(response.data);
        },
        err => {
          reject(err);
          if (err.response.status == 401 || err.response.status == 601) {
            $router.push({ path: "/" });
          }
        }
      ).catch(error => {
        reject(error);
      });
  });
}

/**
 * 封装post方法
 * @param url
 * @param data
 * @returns {Promise}
 */
export function post(url, params) {
  return new Promise((resolve, reject) => {
    axios.post(url, Qs.stringify(params)).then(
        response => {
          resolve(response.data);
        },
        err => {
          reject(err);
        }
      ).catch(error => {
        reject(error);
      });
  });
}

GLOBAL_API.js

import { post as $POST } from "../js/common/http";

// test api prefixURL
// const prefixURL = "/zuul/twh";
// const prefixURL = "/zuul/seafwg";

// production api
const prefixURL = "/";

// 设备规模接口地址:
const pageUrl = "/equipment/getPage";
export const GlobalAPI_EquipGetPage = params => $POST(pageUrl, params);

demo.vue

import { GlobalAPI_EquipGetPage } from 'xxx/GLOBAL_API.js'

// 获取设备信息数据
async getEquipInfoPage() {
  const params = {
    ...
    pageSize: 5,
    pageNum: 1
  }
  try {
    const { data } = await GlobalAPI_EquipGetPage(params);
    // Todo...
  }catch (err){
    console.log('catch-获取设备信息数据', err)
  }
}

4.页面中请求模块的规范

主要展现清晰,可读性强,遵守命名,注释,函数体的可读性,可维护性。

// bad ,,, very bad,,, ========//
// 获得日常巡视分析巡视情况:
getXsqk(cityId, time, type, country) {
  // 默认全省
  var parmar = {
    type: "rcxcfx@xsqk",
    filter: `t.tjsj:${time};t.sbfl:${type};t.ssds:zz.isc_id;zz.sjbmid:008df5db70319f73e0508eoabd9b0002`,
  };
  let ds = `t.tjsj:${time};t.sbfl:${type};t.ywdw:zz.isc_id;zz.sjbmid:${cityId}`;
  // 选择地市[除了全省]
  if (cityId && cityId != "全省") {
    parmar = {
      type: "rcxcfx@xsqk",
      filter: `t.tjsj:${time};t.sbfl:${type};t.ywdw:zz.isc_id;zz.sjbmid:${cityId}`, //地市
    };
  }
  // 选择县级:县级t.whbz不传t.ssds,t.ywdw且参数固定位zz.isc_id
  if (country && this.csjb == 2) {
    parmar = {
      type: "rcxcfx@xsqk",
      filter: `t.tjsj:${time};t.sbfl:${type};t.whbz:zz.isc_id;zz.sjbmid:${country}`,
    };
    if (country == "全区县") {
      parmar = {
        type: "rcxcfx@xsqk",
        filter: `t.tjsj:${time};t.sbfl:${type};t.ywdw:zz.isc_id;zz.sjbmid:${cityId}`, //地市
      };
    }
  }
  var url = "/zuul/pwjkgw/common/getChartData";
  let that = this;
  this.$get(url, parmar).then((res) => {
    if (res.status == 200 && res.data.length > 0 && res.data[0][0]) {
      that.xsqk = res.data[0];
    } else {
      that.xsqk = [0, 0, 0, 0, 0];
    }
  });
}, 

// good
// 获得日常巡视分析巡视情况:
async getDailyInspectInfo() {
  const params = {
    ...this.buildParams(), // 此类参数是共有的,可以在具体的组件中或者使用Mixin混入做统一封装使用,
    type: 'xxxx'           // 每个接口的私有属性
  }
  try{
    const res = await GlobalAPI_dailyInspect(params)
    // Todo...
  }catch(err) {
    console.log('catch --- 获得日常巡视分析巡视情况', err)
  }
}
// 一个请求接口的函数功能就三部分:
// 1.构造请求的参数【参数太复杂抽离函数,专门构建参数的函数】
// 2.调用api请求
// 3.请求成功后的处理与异常处理

// 建议总体设计不要超过100行,超过100行抽离函数
// 建议使用async, await + try catch处理增强代码可读性,避免回调。
// 建议不要使用不断的传参数而且是特别多的参数,由于data域中的数据都是绑定的,在事件机制的驱动下都是响应式的数据,直接操作即可,参数太多,调用地方多的情况下可读性差

5. vue页面的建议

## 1.页面中的一些默认顺序:(统一习惯较好)
export default {
  mixin: [navMixin],
	name: '',
  components: {},
  data() {
    return {}
  },
  created() {},
  mounted() {},
  ...
  computer: {}, // !?
  watch: {},
  methods: {    // 放在页面的最下面

  }
}
## 2.页面请求中的接口顺序:
// 按照一个页面中的布局顺序在methods中添加序号依次编写

\