前言
由于公司中存在Vue2项目还在维护和迭代,在升级之前避免造成太大的技术负债,需要有一套规则来约束编码习惯。
一、模块化开发
始终基于模块的方式来构建你的 app,每一个子模块只做一件事情。
Vue的设计初衷就是帮助开发者更好的开发界面模块,请用好你手中的每一个组件。一个模块是应用程序中独立的一个部分。
如何做?
组件遵循 单一职责原则,每一个组件都是一个独立的、可复用的和可测试的。
在基于组件独立运行的情况下,尽量保证每一个组件的代码行数不超过300行。
二、组件表达式简单化
Vue.js 的表达式是 100% 的 Javascript 表达式。这导致某些同学滥用表达式而带来复杂性、可读性等问题。
因此,你需要尽可能保证表达式的简单化。
为什么?
- 复杂的行内表达式难以阅读。
- 行内表达式是不能够通用的,这可能会导致重复编码的问题。
- IDE 基本上不能识别行内表达式语法,所以使用行内表达式 IDE 不能提供自动补全和语法校验功能。
如何做?
复杂并难以阅读的行内表达式,那么可以使用 method 或是 computed 属性来替代其功能。
<!-- 不推荐 -->
<template>
<div v-if="isOpenServiceMan && isOpenBespeakStaff && hasResList">111</div>
</template>
<!-- 推荐 -->
<template>
<div v-if="hasStaffView">111</div>
</template>
<script>
export default {
computed() {
hasStaffView() {
return (
this.isOpenServiceMan && this.isOpenBespeakStaff && this.hasResList;
);
},
}
}
</script>
三、props 原子化
组件props支持传递复杂的JavaScript对象,但是尽可能使用原始数据类型(字符串、数字、布尔值)和函数。避免传递复杂对象。
为什么?
- 使得组件 API 清晰直观。
- 其它开发者更好的理解每一个 prop 的含义、作用。
- 传递过于复杂的对象使得我们不能够清楚的知道哪些属性或方法被自定义组件使用,这使得代码难以重构和维护。
如何做?
组件的每一个属性单独使用一个 props,并且使用函数或是原始类型的值。
<!-- 不推荐 -->
<child-component :info="userInfo"></child-component>
<!-- 推荐 -->
<child-component
:name="name"
:age="age"
:sex="sex"
@say="handleSay"
@run="handleRun"
>
</child-component>
四、验证组件的 props
在 Vue.js 中,组件的 props 即 API,一个稳定并可预测的 API 会使得你的组件更容易被其他开发者使用。
组件 props 通过自定义标签的属性来传递。属性的值可以是 Vue.js 字符串(:attr="value" 或 v-bind:attr="value")或是不传。你需要保证组件的 props 能应对不同的情况。
为什么?
验证组件 props 可以保证你的组件永远是可用的(防御性编程)。即使其他开发者并未按照你预想的方法使用时也不会出错,它会聪明的警告你应该如何修正。
如何做?
- 提供默认值。
- 使用 type 属性校验类型。
- 使用 props 之前先检查该 prop 是否存在。
- 更好的做法是在使用之前通过validator校验。
<template>
<input type="range" v-model="value" :max="max" :min="min">
</template>
<script type="text/javascript">
export default {
props: {
max: {
type: Number,
default() { return 10; },
},
min: {
type: Number,
default() { return 0; },
},
value: {
type: Number,
default() { return 0; },
validator: function (value) {
// The value must match one of these strings
return [0, 1, 2].indexOf(value) !== -1
}
},
},
};
</script>
五、避免 this.$parent
Vue.js 支持组件嵌套,并且子组件可访问父组件的上下文。访问组件之外的上下文违反了基于模块开发的第一原则。因此你应该尽量避免使用 this.$parent。
为什么?
- 组件必须相互保持独立,Vue 组件也是。如果组件需要访问其父层的上下文就违反了该原则。
- 如果一个组件需要访问其父组件的上下文,那么该组件将不能在其它上下文中复用。
如何做?
- 通过 props 将值传递给子组件。
- 通过 props 传递回调函数给子组件来达到调用父组件方法的目的。
- 通过在子组件触发事件来通知父组件。
六、减少使用mixins
Mixins 封装可重用的代码,避免了重复。很方便在各个组件中抽离相同的逻辑。
但在复杂系统中,Mixins会造成属性、方法查找苦难的情况,在多人协同项目中,你永远不知道别人会把mixins放到哪个js中。
为什么?
mixins几种合并策略,使得初级开发者把握不好将会滥用。
- 替换型:props、methods、inject、computed
- 合并型:data
- 队列型:lifeCycle和watch
- 叠加型:component、directives、filters
mixins 会产生更多的隐式逻辑,这将会带来调试困难、迁移困难、命名冲突等问题。
怎么做?
尽可能使用utils去维护多个组件功能逻辑,更有利于单元测试。
七、组件结构化
结构化的vue组件能够使得团队开发习惯、结构组织极可能统一。
为什么?
- 导出一个清晰、组织有序的组件,使得代码易于阅读和理解。同时也便于标准化。
- 合理组织,使得组件易于阅读。
- 使用 name 属性。借助于 vue devtools 可以让你更方便的测试。
如何做?
组织结构化。
<template lang="html">
<div class="container">
<!-- ... -->
</div>
</template>
<script type="text/javascript">
export default {
// 不要忘记 name 属性
name: 'Component-Name',
// 使用组件 mixins 共享通用功能
mixins: [],
// 组成新的组件
extends: {},
// 组件属性、变量
props: {
bar: {}, // 按字母顺序
foo: {},
fooBar: {},
},
// 变量
data() {},
computed: {},
// 使用其它组件
components: {},
// 方法
watch: {},
methods: {},
// 生命周期函数
beforeCreate() {},
created() {},
mounted() {},
};
</script>
<style scoped>
.container { /* ... */ }
</style>
八、总结
以上,是业务迭代过程中梳理总结出来比较常见的规范问题,同时也是最容易变成屎山代码的地方,在团队成员存在明显梯度的情况下,需要有一套规则来约束编码习惯,在Code Review的时候根据文档规范来执行,能够在一定程度上减少技术负债。