前端代码规范:
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中添加序号依次编写
\