# 风格指南
# 介绍
在参与H3-UI开发时,请遵守约定的单文件组件风格指南,指南内容节选自 Vue 官方风格指南
# 组件数据
组件的 data
必须是一个函数。
当在组件中使用 data
属性的时候 (除了 new Vue
外的任何地方),它的值必须是返回一个对象的函数。
// bad
export default {
data: {
foo: 'bar'
}
}
// good
export default {
data () {
return {
foo: 'bar'
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 单文件组件文件名称
基于文件名始终小写的规则,单文件组件的文件名应该始终是横线连接 (kebab-case)。
// bad
mycomponent.vue
myComponent.vue
MyComponent.vue
// good
my-component.vue
2
3
4
5
6
7
# 紧密耦合的组件名
和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
// bad
components/
|- TodoList.vue
|- TodoItem.vue
└─ TodoButton.vue
// good
components/
|- todo-list.vue
|- todo-list-item.vue
└─ todo-list-item-button.vue
2
3
4
5
6
7
8
9
10
11
# 自闭合组件
在单文件组件中没有内容的组件应该是自闭合的。
<!-- bad -->
<my-component></my-component>
<!-- good -->
<my-component />
2
3
4
5
# Prop 名大小写
在声明 prop
的时候,其命名应该始终使用 camelCase,而在模板中应该始终使用 kebab-case。
// bad
export default {
props: {
'greeting-text': String
}
};
// good
export default {
props: {
greetingText: String
}
}
2
3
4
5
6
7
8
9
10
11
12
13
<!-- bad -->
<welcome-message greetingText="hi" />
<!-- good -->
<welcome-message greeting-text="hi" />
2
3
4
5
# Props 换行
多个 Props 的元素超过3个属性应该分多行撰写,每个 Props 一行,闭合标签单起一行。
<!-- bad -->
<my-component id="d" foo="a" bar="b" baz="c" />
<!-- good -->
<my-component
id="d"
foo="a"
bar="b"
baz="c"
/>
2
3
4
5
6
7
8
9
10
# 指令缩写
指令缩写,用 :
表示 v-bind:
,用 @
表示 v-on:
<!-- bad -->
<input
v-bind:value="value"
v-on:input="onInput"
>
<!-- good -->
<input
:value="value"
@input="onInput"
>
2
3
4
5
6
7
8
9
10
11
# Props 顺序
标签的 Props 应该有统一的顺序,依次为指令、属性和事件。
<my-component
v-if="if"
v-show="show"
v-model="value"
ref="ref"
:key="key"
:text="text"
@input="onInput"
@change="onChange"
/>
2
3
4
5
6
7
8
9
10
# 组件选项的顺序
组件选项应该有统一的顺序。
export default {
name: '',
mixins: [],
components: {},
props: {},
data() {},
computed: {},
watch: {},
created() {},
mounted() {},
destroyed() {},
methods: {}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 组件选项中的空行
组件选项较多时,建议在属性之间添加空行。
export default {
computed: {
formattedValue() {
// ...
},
styles() {
// ...
}
},
methods: {
onInput() {
// ...
},
onChange() {
// ...
}
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 为 v-for
设置键值
总是用 key
配合 v-for
。
在组件上总是必须用 key
配合 v-for
,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。
# 详解
假设你有一个待办事项列表:
data: function () {
return {
todos: [
{
id: 1,
text: '学习使用 v-for'
},
{
id: 2,
text: '学习使用 key'
}
]
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
然后你把它们按照字母顺序排序。在更新 DOM 的时候,Vue 将会优化渲染把可能的 DOM 变动降到最低。即可能删掉第一个待办事项元素,然后把它重新加回到列表的最末尾。
这里的问题在于,不要删除仍然会留在 DOM 中的元素。比如你想使用 <transition-group>
给列表加过渡动画,或想在被渲染元素是 <input>
时保持聚焦。在这些情况下,为每一个项目添加一个唯一的键值 (比如 :key="todo.id"
) 将会让 Vue 知道如何使行为更容易预测。
根据我们的经验,最好始终添加一个唯一的键值,以便你和你的团队永远不必担心这些极端情况。也在少数对性能有严格要求的情况下,为了避免对象固化,你可以刻意做一些非常规的处理。
<!-- bad -->
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
<!-- good -->
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 避免 v-if
和 v-for
用在一起 必要
永远不要把 v-if
和 v-for
同时用在同一个元素上。
一般我们在两种常见的情况下会倾向于这样做:
为了过滤一个列表中的项目 (比如
v-for="user in users" v-if="user.isActive"
)。在这种情形下,请将users
替换为一个计算属性 (比如activeUsers
),让其返回过滤后的列表。为了避免渲染本应该被隐藏的列表 (比如
v-for="user in users" v-if="shouldShowUsers"
)。这种情形下,请将v-if
移动至容器元素上 (比如ul
,ol
)。
# 详解
当 Vue 处理指令时,v-for
比 v-if
具有更高的优先级,所以这个模板:
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
2
3
4
5
6
7
8
9
相当于进行了以下的运算:
this.users.map(function (user) {
if (user.isActive) {
return user.name
}
})
2
3
4
5
因此即使我们只想渲染出活跃的用户(user.isActive
)的元素,也得在每次重渲染的时候遍历整个列表。
通过将其更换为在如下的一个计算属性上遍历:
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
2
3
4
5
6
7
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
2
3
4
5
6
7
8
我们将会获得如下好处:
- 过滤后的列表只会在
users
数组发生相关变化时才被重新运算,过滤更高效。 - 使用
v-for="user in activeUsers"
之后,我们在渲染的时候只遍历活跃用户(user.isActive
),渲染更高效。 - 解耦渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。
另一种情况下,v-if
的判断条件不是元素内的属性
<!-- bad -->
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<!-- good -->
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通过将 v-if
移动到容器元素,我们不会再对列表中的每个用户检查 shouldShowUsers
。取而代之的是,我们只检查它一次,且不会在 shouldShowUsers
为否的时候运算 v-for
。
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
2
3
4
5
6
7
8
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
2
3
4
5
6
7
8
# 单文件组件顶级标签的顺序
单文件组件应该总是让顶级标签的顺序保持一致,且标签之间留有空行。
<template>
...
</template>
<script>
/* ... */
</script>
<style>
/* ... */
</style>
2
3
4
5
6
7
8
9
10
11