# 编码规范
Vue编写规范整理,书写漂亮的Vue代码。
# 代码风格
# 缩进
使用4个空格作为一个缩进层级,不允许使用2个空格或tab字符
# 单行最长限制
每行不得超过120个字符
# 模块书写顺序
template->script->style
# template部分
# 根节点
template根节点只允许包含一个直接子节点,以下情况是不允许的:
- 根节点为空
- 根节点是文字
- 根节点有多个元素
- 在根节点使用循环
- 在根节点使用
template和slot - 在根节点使用
v-if,但是没有v-else
// bad
<template></template>
<template>hello</template>
<template><div>one</div><div>two</div></template>
<template><div v-for="x in list"></div></template>
<template><template>hello</template></template>
<template><div v-if="title"></div></template>
// good
<template><div>one</div></template>
# 标签
# 自定义组件的标签名不得使用HTML中默认已定义的标签(reserved HTML elements),要求至少由两个单词组成,并且符合kebab-case
解释:避免和HTML保留字段冲突导致错误。
// bad
<template>
<sub />
</template>
<script>
import OhterComponent from './OtherComponent.vue';
export default {
components: {
sub: OtherComponent
}
}
</script>
// good
<template>
<other-component />
</template>
<script>
import OtherComponent from './OtherComponent.vue';
export default {
components: {
OtherComponent
}
}
</script>
// bad
<component />
<mycomponent />
<myComponent />
<MyComponent />
// good
<my-component />
# HTML Void Element不需要闭合,其他类型标签都需要闭合
// bad
<input></input>
<br></br>
// good
<input>
<br>
# 非根节点的template标签里必须有一个以上的子节点
// bad
<ul>
<template>
<li></li>
</template>
</ul>
// good
<ul>
<li></li>
</ul>
// good
<ul>
<template>
<li></li>
<li></li>
</template>
</ul>
# template标签上不能带有key属性
// bad
<template>
<div>
<template key="x"></template>
<template v-bind:key="y"></template>
<template :key="z"></template>
</div>
</template>
// good
<template>
<div>
<div key="x"></div>
<template></template>
</div>
</template>
# 如果自定义标签中没有内容,需要以自闭合标签形式出现
// bad
<c-title :url="url" :label-type="type"></c-title>
// good
<c-title :url="url" :label-type="type" />
# 标签右括号>的位置
- 元素只有一行时,右括号与元素保持在同一行
- 多行元素(元素最后一个属性与左括号
<不在同一行)时,右括号>需要另起一行,缩进与左括号<保持对齐
// bad
<div id="foo" class="bar"
></div>
// good
<div id="foo" class="bar"></div>
// bad
<div
id="foo"
class="bar">
</div>
// good
<div
id="foo"
class="bar"
>
some message
</div>
// bad
<c-title
:text="text"
:url="url"
:label-type="type"/>
// good
<c-title
:text="text"
:url="url"
:label-type="type"
/>
# 自闭合标签的/>前不用添加空格
// bad
<c-title :url="url" :label-type="type" />
// good
<div></div>
<c-title :url="url" :label-type="type" />
# 属性
# 属性值必须用双引号包围
// bad
<div class='c-color'></div>
// good
<div class="c-color"></div>
# 模板中的属性命名需要符合kebab-case
// bad
<my-component greetingText="hi" />
// good
<my-component greeting-text="hi" />
# class/style属性值不能设置空字符串
// bad
<div class=""></div>
<div style=""></div>
// good
<div></div>
# 布尔类型的属性值为true时,建议不添加属性值
// bad
<c-title text="带箭头标题" :arror="true" />
// good
<input type="text" disabled>
<c-title text="带箭头标题" arrow />
<c-title text="带箭头标题" :arrow="false" />
# 当组件的属性多于2个时,必须分成多行,每行只写一个属性;只有属性个数小于或等于2个时,可以写在一行内
// bad
<c-title :text="text" :url="url" :label-type="type" />
// good
<c-title :text="text" :url="url" />
<c-title
:text="text"
:url="url"
:label-type="type"
/>
# 当元素有多个属性时,应该按照统一的顺序书写,优先级顺序如下:
定义(提供组件的选项)
- is
列表渲染(创建多个变化的相同元素)
- v-for
条件渲染(元素是否渲染/显示)
- v-if
- v-else-if
- v-else
- v-show
- v-cloak
渲染方式(改变元素的渲染方式)
- v-pre/v-once
全局感知(需要超越组件的知识)
- id
唯一的特性(需要唯一值的特性)
- ref
- key
- slot
双向绑定(把绑定和事件结合起来)
- v-model
未绑定的属性
其他绑定(所有普通的绑定)
- v-bind
事件(组件事件监听器)
- v-on
内容(复写元素的内容)
- v-html
- v-text
# 不能有重复的属性,class和style除外
解释: 这里重复的属性包括以下两种情况:
- 属性名完全一样:如有多个
foo或者多个:foo - 有一个普通属性和一个
v-bind动态绑定的属性,动态绑定的属性名和普通属性名重复
// bad
<c-title foo="abc" :foo="def" />
<c-title foo="def" foo="abc" />
<c-title class="def" class="abc" />
<c-title style="def" style="abc" />
// good
<c-title :foo="def" />
<c-title foo="abc" />
<c-title
class="c-color"
:class="{'c-selected': selected}"
/>
<c-title
style="color: #000;"
:style="{width: '100px'}"
/>
# slot命名采用kebab-case
<slot name="header-left"></slot>
<div slot="header-left"></div>
# ref命名采用PascalCase
<div ref="userInfo"></div>
# 指令
# 在使用v-for的元素上添加key,以便维护内部组件及其子树的状态
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
# 不要把v-if和v-for同时用在同一个元素上
解释:
当Vue处理指令时,v-for比v-if具有更高的优先级。所以如果想要使用v-if判断v-for元素列表是否显示,将两个指令同时应用在同一个元素的方法就是错误的。引入这个规则是为了避免引起困惑。
// bad
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
// good
<template>
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
</template>
<script>
export default {
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive;
});
}
}
}
</script>
# 以下指令统一使用缩写
- 使用
:表示v-bind: - 使用
@表示v-on:
# 插值(Mustache)
# 插值左右添加一个空格
// bad
<div>{{ text }}</div>
<div>{{text}}</div>
// good
<div>{{ text }}</div>
# 空格
# 不能有多余空格
// bad
<div class="foo"
:style="bar" > </div>
// good
<div class="foo" :style="bar"></div>
# 变量
# 不能有多余的变量
// bad
<ol><!-- "i" is defined but never used. -->
<li v-for="i in 5">item</li>
</ol>
// good
<ol>
<li v-for="i in 5">{{ i }}</li>
</ol>
# 禁止在插值中使用this
// bad
<a :href="this.url">
{{ this.text }}
</a>
// good
<a :href="url">
{{ text }}
</a>
# javascript部分
# props
# 指定props类型
// bad
<script>
export default {
props: ['status']
};
</script>
// good
<script>
export default {
props: {
status: String
}
};
</script>
# 如果props没有指定为required或者required为false,则需要指定默认值
// bad
<script>
export default {
props: {
a: {
type: Number,
required: true
},
b: {
type: [Number, String],
default: 0
},
c: {
type: Number,
default: 0,
required: false
}
}
};
</script>
# props提供的默认值必须满足校验条件
// bad
<script>
export default {
props: {
propA: {
type: String,
default: {}
},
propB: {
type: String,
default: []
},
propC: {
type: Object,
default: []
},
propD: {
type: Array,
default: []
},
propE: {
type: Object,
default: {
message: 'hello'
}
}
}
};
</script>
// good
<script>
export default {
props: {
propA: Number,
propB: [String, Number],
propC: {
type: Number,
default: 100
},
propD: {
type: Object,
default() {
return {
message: 'hello'
};
}
}
}
};
</script>
# 在props中声明的属性,其属性名应该始终符合camelCase
// bad
<script>
export default {
props: {
'greeting-text': String
}
};
</script>
// good
<script>
export default {
props: {
greetingText: String
}
};
</script>
# data
# data必须是一个函数
// bad
<script>
export default {
data: {
b: 1
}
}
</script>
// good
<script>
export default {
data() {
return {
b: 1
};
}
}
</script>
# data中禁止使用computed中的变量
// bad
<script>
export default {
props: {
a: {
type: String,
default: 0
}
},
data() {
return {
d: this.f
};
},
computed: {
f() {
return this.a * 10;
}
}
};
</script>
# props,data,computed,methods中不能有重复的key
// bad
<script>
export default {
props: {
foo: String
},
data() {
return {
foo: null
};
},
computed: {
foo() {
return 'foo';
}
}
}
</script>
// good
<script>
export default {
props: {
foo: String
},
data() {
return {
bar: null
};
},
computed: {
baz() {
return foo + bar;
}
}
}
</script>
# 变量
# 不能使用Vue中的保留字段命名变量
解释:
Vue使用_前缀来定义其自身的私有属性,所以使用相同的前缀(比如_update)有覆写实例属性的风险。即便你检查确认Vue当前版本根本没有用到这个属性名,也不能保证将来的版本没有冲突。
对于$前缀来说,其在Vue生态系统中的目的是暴露给用户的一个特殊的实例属性,所以把它用于私有属性并不合适。
不过,我们推荐把这两个前缀结合为$_,作为一个用户定义的私有属性的约定,以确保不会和Vue自身相冲突。
// bad
<script>
export default {
props: {
$el: String
},
data() {
return {
_foo: null
};
},
computed: {
$on() {
return 2;
}
},
methods: {
$nextTick() {
}
}
}
</script>
# 其他
# 组件中使用$emit事件时携带的参数,个数不应该超过2个。建议将数据以Object形式传递,将事件参数event放在最后
// bad
onClick(event) {
this.$emit('click', this.value1, this.value2, event);
}
// good
onClick(event) {
this.$emit(
'click',
{
value1: this.value1,
value2: this.value2
},
event
);
}
// good
onClick(event) {
this.$emit('click', event);
}
# style部分
# 为组件样式设置作用域
<style scoped>
.buuton {
border: none;
border-radius: 2px;
}
</style>