相比其他的框架来说,Vue中更容易产出不合格代码;因为Vue中的options就是一个大对象,导致js本身的很多检测都失效了,比如一个函数没有用到的话会“变灰”,template中代码提示比较少,较多的mixins等等;遇到不合格代码,大多数人第一反应就是这谁写的代码这么差,其实大多数公司大多数人至少曾经都写过一些不合格代码,有不合格代码很正常,问题在于怎么快速梳理出业务逻辑,防止在迭代新需求时引发bug,在富有余力的情况下可以进行局部重构,渐进式优化屎山代码;
那么,接下来可以看看前端项目不合格的地方,大概有以下几种:
src/
├── App.vue
├── api
├── components
├── constants
├── main.js
├── pages
├── router
├── services
├── utils
│ └── hash.js
└── views
看一下上面的目录,views和pages是类似的含义,都是指的路由对应的页面,而api和services也是类似的都是存放后端接口的封装,同时存在这几种文件夹说明项目初期没有规范,每个人按照自己的规范去开发,导致有的人页面写在views里面,有的写在pages里面,建议这几个相似含义的目录只保留一个;
它的危害在于让后续接手的人要频繁切换文件夹去看不同页面的逻辑,并且不知道后续自己应该在哪个文件夹开发自己的页面,导致恶性循环。
Vue将template、script、style组合在一个.vue文件中,这天然就会使得每一个.vue文件的行数会非常多,难以维护,Vue2中一个最明显的屎山就是几千行、甚至上万行的代码,用专业的术语来讲就是不符合单一职责原则,一个组件应该只干一件事情,一个函数应该只处理一个逻辑,剩下的逻辑交给其他函数或者组件来做;时刻牢记“SOLID”原则是远离屎山的第一心法;
<div
class="files"
:class="{ disabled: !isAllowRead && hasNotPassed && aaa && (bbb || ccc) }"
@click="toDetail()"
>
<a/>
<b v-if="!isAllowRead && hasNotPassed && aaa && (bbb || ccc)"/>
</div>
看这一段代码,为了判断一个禁用状态,使用了大量的运算符,导致逻辑不清晰,并且遇到相似的逻辑在下面b组件上不得不ctrl cv,妥妥地变成了cv工程师,这里正确的做法是应该放到计算属性里面去进行判断,并且根据后面所使用到的逻辑进行计算属性的拆分:
<div
class="files"
:class="{ disabled: isFileDisabled }"
@click="toDetail()"
>
<a/>
<b v-if="isFileDisabled"/>
div>
<script>
export default {
// 此处省略...
computed: {
isFileDisabled(){
return !isAllowRead && hasNotPassed && aaa && (bbb || ccc)
}
}
}
script>
当然isFileDisabled这个计算属性也可以拆分成多个,这个主要看后续的复用情况。
<div>
<span v-for="item in textConfigs" :key="item.valueKey">{{
response[item.valueKey]
}}span>
div>
data() {
return {
textConfigs: [
{ label: "性别", valueKey: "name" },
{ label: "年龄", valueKey: "age" },
{ label: "性别", valueKey: "gender" },
{ label: "身高", valueKey: "height" },
{ label: "体重", valueKey: "weight" },
{ label: "爱好", valueKey: "habit" }
]
};
},
if(!values.username){
this.$message.error("用户名不能为空")
} else if(!values.password){
this.$message.error("密码不能为空")
} else if(!values.phoneNumber){
this.$message.error("手机号不能为空")
} else {
this.submit();
}
可能有人会说,上面的代码语义明确,写得还不够好吗?但是如果需要增加更多的校验条件时,开发者不得不侵入到具体方法去修改代码,使用策略模式优化之后能够让校验条件与具体判断逻辑解耦,当需要增加校验条件时直接修改数组即可:
const validators = [
{ message: "用户名不能为空", required: true, key: "username" },
{ message: "密码不能为空", required: true, key: "password" },
{ message: "手机号不能为空", required: true, key: "phoneNumber" }
];
export default {
methods: {
validator(values) {
const result = validators.some(el => {
if (el.required && !values[el.key]) {
this.$message.error(el.message);
return true;
}
});
return result;
},
submit(values) {
if (this.validator(values)) {
return;
}
// ... 调用接口
}
}
};
// a.mixin.js
export default {
data() {
return {
username: "",
password: "",
age: 18
};
},
created() {
this.fetchUserInfo();
},
methods: {
fetchUserInfo() {}
}
};
// b.mixin.js
export default {
data(){
return {
height:'',
weight:''
}
},
created(){
this.fetchBodyFat();
},
methods:{
fetchBodyFat(){
}
}
}
// c.vue
const DEGREEMAP = {
doctor:'博士'
}
export default {
mixins:[a,b],
data(){
return {
degree:DEGREEMAP.doctor
}
},
created(){
this.log()
},
methods:{
log(){
if(this.age < 30 && this.height>180 && this.degree===DEGREEMAP.doctor){
alert("真牛!")
}
}
}
}
这里a、b提供了一些数据,最后统一在c.vue中使用,这样的话容易造成变量覆盖以及来路不明等问题,如果必须使用vue2的话这种情况是避免不了的,只能尽量减少组件对mixins中data的耦合度。