写在卷首的话:
代码规范比比皆是,但是很少有公司做好代码规范的,忍不住想谈谈代码规范的重要性,希望能有越来越多的同行将自己的代码结构重视起来。这不仅可以减少我们开发过程中的逻辑混乱,还有助于我们对整个项目的把控能力。
我在行业内只能算是一个新人,可能在这方面只能投石问路,抛砖引玉。这篇规范既写给自己也写给所有志同道合之人,若有轻言肆口,悖言乱辞之处,还望海涵。
总则
很喜欢一句话,最糟糕的管理制度就是员工不愿意执行的制度,我觉得一份优秀的代码规范,应当能打上一下的几个标签:清晰,合理,可行性高,既不影响工作效率,又能增加团队协作。
我从不吝于将符号左右要不要加空格,句末是否需要写分号这类细节的东西放在规范里,代码的可读性不应当在这些地方体现。理由是这些规范都是基于一条语句来定义的,对于我来说,我更加倾向站在模块甚至是整个项目的高度,来考虑代码的可维护性。
一、通用组件
-
命名 公司名 / 项目名缩写 + 组件名
通用类名的命名规则也可以参照这条
语法 单标签
引用 标签名、组件名、文件名三者统一
// 不推荐
<template>
<my-pager :pageOption='pageOption'></my-pager>
</template>
<script>
import pager from '../../pageCompont.vue'
export default {
components:{
myPager: pager
}
}
</script>
// 同样不推荐
<template>
<pager :pageOption='pageOption'></pager>
</template>
<script>
import pager from '../../pageCompont.vue'
export default {
components:{
pager
}
}
</script>
// 推荐
<template>
<su-pager :pageOption='pageOption'/>
</template>
<script>
import suPager from '../../suPage.vue'
export default {
components:{
suPager
}
}
</script>
二、通用对象及方法
Vuex 存放经常需要改变的量
localStorage 存放非敏感的简单数据类型或少量复杂数据类型
-
Vue.prototype
存放 如 全国地址库(超大量数据)
存放 通用方法(登录、登出、获取验证码等)
三、响应式对象
data对象中的对象数量越少越好,这样既便于维护,又方便开发,我们通常将同类型的(如同一个接口)所有变量组合成一个对象存放,这个对象的命名及对象内的key值应当与接口一致,如果接口名过长或语义化不强,可以自定义对象名,但对象下的key值必须与参数字段一致
// 不推荐
<template>
<el-form>
<el-form-item label="用户名" prop="name">
<el-input v-model="name"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="phone">
<el-input v-model="phone"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="password"></el-input>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
name: '',
phone: '',
password: '',
}
},
methords: {
register() {
// 此时需要对请求内容进行二次处理
// 一旦字段过多, 代码将会变得很难维护
let data = {
userName: this.name,
telNumber: this.phone,
password: this.password
}
this.axios
.post('/user/register', this.register)
.then(res => {
console.log(res, 'register')
}).catch(err => {
console.log(err)
})
},
}
}
</script>
// 推荐
<template>
<el-form>
<el-form-item label="用户名" prop="userName">
<el-input v-model="register.userName"></el-input>
</el-form-item>
<el-form-item label="手机号" prop="telNumber">
<el-input v-model="register.telNumber"></el-input>
</el-form-item>
<el-form-item label="密码" prop="password">
<el-input v-model="register.password"></el-input>
</el-form-item>
</el-form>
</template>
<script>
export default {
data() {
return {
register: {}
}
},
methords: {
register() {
// 此时可以直接发送对象, 无需进行任何数据处理
this.axios
.post('/user/register', this.register)
.then(res => {
console.log(res, 'register')
}).catch(err => {
console.log(err)
})
},
}
}
</script>
这种根据接口需求确定 v-model值
的写法,在字段多而复杂的情况下具有极为明显的优势!这对于前后端的接口联调十分友好,这种优势尤其能够在分页查询,分类查询这类条件查询的接口中体现。
// 示例
<template>
<div>
<el-form :model="form" inline label-width="80px" ref="form">
<el-form-item label="姓名">
<el-input placeholder="请输入姓名" v-model="queryOption.name"></el-input>
</el-form-item>
<el-form-item label="电话">
<el-input placeholder="请输入用户手机号" v-model="queryOption.tel"></el-input>
</el-form-item>
<el-form-item label="客户等级">
<!-- 此处客户等级一般为选择器,本例为简写 -->
<el-input placeholder="请输入客户等级" v-model="queryOption.VIPLevel"></el-input>
</el-form-item>
</el-form>
<el-table :data="userList">
<el-table-column label="姓名" prop="name"></el-table-column>
<el-table-column label="电话" prop="tel"></el-table-column>
<el-table-column label="地址" prop="address"></el-table-column>
<el-table-column label="客户等级" prop="VIPLevel"></el-table-column>
</el-table>
<el-pagination
:current-page="queryOption.page"
:page-size="queryOption.limit"
:page-sizes="[20, 40, 80, 100]"
:total="queryOption.total"
background
layout="total, sizes, prev, pager, next, jumper"
></el-pagination>
</div>
</template>
<script>
export default {
data() {
return {
queryOption: {},
userList: []
}
},
methods: {
queryUserList() {
this.axios
.get('/queryUserList', this.queryOption)
.then(res => {
console.log(res)
if (res.code == 200) {
this.queryOption.page = res.page
this.queryOption.total = res.total
this.userList = res.records
}
})
.catch(err => {
console.error(err)
})
}
},
watch: {
queryOption: {
deep: true,
handler() {
this.queryUserList()
}
}
},
}
</script>
四、关于代码本身
即便在总则当中,我说过从不吝于站在某一个很细微的角度去苛责代码,事实上这一章依旧不会这样。下面的内容是一些好的代码思维,希望可以对大家有一些帮助。
链式编程分行写
// 不建议
queryUserList() {
this.axios.get('/queryUserList', this.queryOption).then(res => {
if (res.code == 200) {
this.queryOption.page = res.page
this.queryOption.total = res.total
this.userList = res.records
}
}).catch(err => {
console.error(err)
}
)
}
// 建议
queryUserList() {
this.axios
.get('/queryUserList', this.queryOption)
.then(res => {
console.log(res)
if (res.code == 200) {
this.queryOption.page = res.page
this.queryOption.total = res.total
this.userList = res.records
}
})
.catch(err => {
console.error(err)
}
)
}
慎用三元表达式,尤其慎用三元表达式的嵌套
// 实例一
// 不建议
let data = this.radio5 == 1 ? this.diagram.outAmountList : this.radio5 == 2 ? this.diagram.orderTonnageList : this.diagram.orderAmountList
// 勉强还行
let data
if( this.radio5 == 1 ){
data = this.diagram.outAmountList
}
if( this.radio5 == 2 ){
data = this.diagram.orderTonnageList
}
if( this.radio5 == 3 ){
data = this.diagram.orderAmountList
}
// 优秀
let index = this.radio5 - 1,
data = [this.diagram.outAmountList, this.diagram.orderTonnageList , this.diagram.orderAmountList][index]
// 实例二
// 不推荐
let userName = localStorage.userName ? localStorage.userName : 'admin'
// 推荐
let userName = localStorage.userName || 'admin'
多重判断,永远将特殊情况放在最前面
// 不推荐
if (res.code == 200) {
localStorage.setItem('Variable1', JSON.stringify(res.data.Variable1))
localStorage.setItem('Variable2', res.data.Variable2)
localStorage.setItem('Variable3', res.data.Variable3)
localStorage.setItem('Variable4', res.data.Variable4)
localStorage.setItem('Variable5', res.data.Variable5)
console.log('登录成功')
} else {
if (res.code == 511) {
console.log('审核中, 请稍候!')
} else if (res.code == 512) {
console.log('审核成功, 欢迎登录!')
} else if (res.code == 513) {
console.log('审核失败, 请重试!')
} else if (res.code == 514) {
console.log('您的账号已被停用!')
}
}
// 推荐
if (res.code == 511) return console.log('审核中, 请稍候!')
if (res.code == 512) return console.log('审核成功, 欢迎登录!')
if (res.code == 513) return console.log('审核失败, 请重试!')
if (res.code == 514) return console.log('您的账号已被停用!')
localStorage.setItem('Variable1', JSON.stringify(res.data.Variable1))
localStorage.setItem('Variable2', res.data.Variable2)
localStorage.setItem('Variable3', res.data.Variable3)
localStorage.setItem('Variable4', res.data.Variable4)
localStorage.setItem('Variable5', res.data.Variable5)
console.log('登录成功')
复杂或常用的逻辑拆分
-
初始化页面
如多个表单重置、获取初始化数据,类似这样的连贯动作,适合写在多个方法中,然后再通过一个方法调用
// 实例 clearValidate(){ // 重置表单校验 }, resetForm(){ // 重置表单内容 }, getData(){ // 获取新数据 }, init(){ // 页面初始化 clearValidate() resetForm() getData() }
此时
init()
方法既可以在create方法中调用,又可以在提交、删除、修改数据时调用需要注意
init()
方法的粒度 -
求和
Vue.prototype.$sum = function () { let arr = arguments let length = arr.length let sum = 0 for (let i = 0; i < length; i++) { if (isNaN(new Number(arr[i]))) { continue } sum += ((arr[i] || 0) * 1) } return sum.toFixed(2) }
-
更新 Store 的 通用 方法
const store = new Vuex.Store({ state: { spread: false }, mutations: { updataStore(state, option) { for (let k in option) { state[k] = option[k] } } } }) // 调用,第二个参数中传所有你要更新的store对象即可 this.$store.commit( 'updataStore', { userInfo: { companyId: res.data.companyId, companyName: res.data.companyName, userId: res.data.userId, }, permissions: res.data.permissions } )
常用功能组件化
-
获取验证码按钮
涉及到定时器的清除、按钮的
文字
及loading
、disabled
状态的变化
文章持续更新,欢迎指正!