# 風格指南
這里是官方的 Vue 特有代碼的風格指南。如果在工程中使用 Vue,為了回避錯誤、小糾結和反模式,該指南是份不錯的參考。不過我們也不確信風格指南的所有內容對于所有的團隊或工程都是理想的。所以根據過去的經驗、周圍的技術棧、個人價值觀做出有意義的偏差是可取的。
對于其絕大部分,我們也總體上避免就 JavaScript 或 HTML 的本身提出建議。我們不介意你是否使用分號或結尾的逗號。我們不介意你在 HTML 特性中使用單引號還是雙引號。不過當我們發現在 Vue 的情景下有幫助的特定模式時,也會存在例外。
> **不久之后,我們還會提供操作層面的技巧。**有的時候你只需要遵守規則,而我們會盡可能向你展示如何使用 ESLint 及其它自動化程序把操作層面弄得更簡單。
最終,我們把所有的規則歸為了四個大類:
## [規則歸類](https://vuejs.bootcss.com/v2/style-guide/#%E8%A7%84%E5%88%99%E5%BD%92%E7%B1%BB "規則歸類")
### [優先級 A:必要的](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-A%EF%BC%9A%E5%BF%85%E8%A6%81%E7%9A%84 "優先級 A:必要的")
這些規則會幫你規避錯誤,所以學習并接受它們帶來的全部代價吧。這里面可能存在例外,但應該非常少,且只有你同時精通 JavaScript 和 Vue 才可以這樣做。
### [優先級 B:強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-B%EF%BC%9A%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "優先級 B:強烈推薦")
這些規則能夠在絕大多數工程中改善可讀性和開發體驗。即使你違反了,代碼還是能照常運行,但例外應該盡可能少且有合理的理由。
### [優先級 C:推薦](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-C%EF%BC%9A%E6%8E%A8%E8%8D%90 "優先級 C:推薦")
當存在多個同樣好的選項,選任意一個都可以確保一致性。在這些規則里,我們描述了每個選項并建議一個默認的選擇。也就是說只要保持一致且理由充分,你可以隨意在你的代碼庫中做出不同的選擇。請務必給出一個好的理由!通過接受社區的標準,你將會:
1. 訓練你的大腦,以便更容易的處理你在社區遇到的代碼;
2. 不做修改就可以直接復制粘貼社區的代碼示例;
3. 能夠經常招聘到和你編碼習慣相同的新人,至少跟 Vue 相關的東西是這樣的。
### [優先級 D:謹慎使用](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-D%EF%BC%9A%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8 "優先級 D:謹慎使用")
有些 Vue 特性的存在是為了照顧極端情況或幫助老代碼的平穩遷移。當被過度使用時,這些特性會讓你的代碼難于維護甚至變成 bug 的來源。這些規則是為了給有潛在風險的特性敲個警鐘,并說明它們什么時候不應該使用以及為什么。
## [優先級 A 的規則:必要的 (規避錯誤)](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-A-%E7%9A%84%E8%A7%84%E5%88%99%EF%BC%9A%E5%BF%85%E8%A6%81%E7%9A%84-%E8%A7%84%E9%81%BF%E9%94%99%E8%AF%AF "優先級 A 的規則:必要的 (規避錯誤)")
### [組件名為多個單詞必要](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6%E5%90%8D%E4%B8%BA%E5%A4%9A%E4%B8%AA%E5%8D%95%E8%AF%8D-%E5%BF%85%E8%A6%81 "組件名為多個單詞 必要")
**組件名應該始終是多個單詞的,根組件`App`除外。**
這樣做可以避免跟現有的以及未來的 HTML 元素[相沖突](http://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name),因為所有的 HTML 元素名稱都是單個單詞的。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B "反例")反例
Vue.component('todo', {
// ...
})
export default {
name: 'Todo',
// ...
}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90 "好例子")好例子
Vue.component('todo-item', {
// ...
})
export default {
name: 'TodoItem',
// ...
}
### [組件數據必要](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6%E6%95%B0%E6%8D%AE-%E5%BF%85%E8%A6%81 "組件數據 必要")
**組件的`data`必須是一個函數。**
當在組件中使用`data`屬性的時候 (除了`new Vue`外的任何地方),它的值必須是返回一個對象的函數。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-1 "反例")反例
Vue.component('some-comp', {
data: {
foo: 'bar'
}
})
export default {
data: {
foo: 'bar'
}
}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-1 "好例子")好例子
Vue.component('some-comp', {
data: function () {
return {
foo: 'bar'
}
}
})
// In a .vue file
export default {
data () {
return {
foo: 'bar'
}
}
}
// 在一個 Vue 的根實例上直接使用對象是可以的,
// 因為只存在一個這樣的實例。
new Vue({
data: {
foo: 'bar'
}
})
### [Prop 定義必要](https://vuejs.bootcss.com/v2/style-guide/#Prop-%E5%AE%9A%E4%B9%89-%E5%BF%85%E8%A6%81 "Prop 定義 必要")
**Prop 定義應該盡量詳細。**
在你提交的代碼中,prop 的定義應該盡量詳細,至少需要指定其類型。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-2 "反例")反例
// 這樣做只有開發原型系統時可以接受
props: ['status']
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-2 "好例子")好例子
props: {
status: String
}
// 更好的做法!
props: {
status: {
type: String,
required: true,
validator: function (value) {
return [
'syncing',
'synced',
'version-conflict',
'error'
].indexOf(value) !== -1
}
}
}
### [為`v-for`設置鍵值必要](https://vuejs.bootcss.com/v2/style-guide/#%E4%B8%BA-v-for-%E8%AE%BE%E7%BD%AE%E9%94%AE%E5%80%BC-%E5%BF%85%E8%A6%81 "為 v-for 設置鍵值 必要")
**總是用`key`配合`v-for`。**
在組件上*總是*必須用`key`配合`v-for`,以便維護內部組件及其子樹的狀態。甚至在元素上維護可預測的行為,比如動畫中的[對象固化 (object constancy)](https://bost.ocks.org/mike/constancy/),也是一種好的做法。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-3 "反例")反例
<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-3 "好例子")好例子
<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
### [避免`v-if`和`v-for`用在一起必要](https://vuejs.bootcss.com/v2/style-guide/#%E9%81%BF%E5%85%8D-v-if-%E5%92%8C-v-for-%E7%94%A8%E5%9C%A8%E4%B8%80%E8%B5%B7-%E5%BF%85%E8%A6%81 "避免 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`)。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-4 "反例")反例
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-4 "好例子")好例子
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
### [為組件樣式設置作用域必要](https://vuejs.bootcss.com/v2/style-guide/#%E4%B8%BA%E7%BB%84%E4%BB%B6%E6%A0%B7%E5%BC%8F%E8%AE%BE%E7%BD%AE%E4%BD%9C%E7%94%A8%E5%9F%9F-%E5%BF%85%E8%A6%81 "為組件樣式設置作用域 必要")
**對于應用來說,頂級`App`組件和布局組件中的樣式可以是全局的,但是其它所有組件都應該是有作用域的。**
這條規則只和[單文件組件](https://vuejs.bootcss.com/v2/guide/single-file-components.html)有關。你*不一定*要使用[`scoped`特性](https://vue-loader.vuejs.org/zh-cn/features/scoped-css.html)。設置作用域也可以通過[CSS Modules](https://vue-loader.vuejs.org/zh-cn/features/css-modules.html),那是一個基于 class 的類似[BEM](http://getbem.com/)的策略,當然你也可以使用其它的庫或約定。
**不管怎樣,對于組件庫,我們應該更傾向于選用基于 class 的策略而不是`scoped`特性。**
這讓覆寫內部樣式更容易:使用了常人可理解的 class 名稱且沒有太高的選擇器優先級,而且不太會導致沖突。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-5 "反例")反例
<template>
<button class="btn btn-close">X</button>
</template>
<style>
.btn-close {
background-color: red;
}
</style>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-5 "好例子")好例子
<template>
<button class="button button-close">X</button>
</template>
<!-- 使用 `scoped` 特性 -->
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>
<template>
<button :class="[$style.button, $style.buttonClose]">X</button>
</template>
<!-- 使用 CSS Modules -->
<style module>
.button {
border: none;
border-radius: 2px;
}
.buttonClose {
background-color: red;
}
</style>
<template>
<button class="c-Button c-Button--close">X</button>
</template>
<!-- 使用 BEM 約定 -->
<style>
.c-Button {
border: none;
border-radius: 2px;
}
.c-Button--close {
background-color: red;
}
</style>
### [私有屬性名必要](https://vuejs.bootcss.com/v2/style-guide/#%E7%A7%81%E6%9C%89%E5%B1%9E%E6%80%A7%E5%90%8D-%E5%BF%85%E8%A6%81 "私有屬性名 必要")
**在插件、混入等擴展中始終為自定義的私有屬性使用`$_`前綴。并附帶一個命名空間以回避和其它作者的沖突 (比如`$_yourPluginName_`)。**
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-6 "反例")反例
var myGreatMixin = {
// ...
methods: {
update: function () {
// ...
}
}
}
var myGreatMixin = {
// ...
methods: {
_update: function () {
// ...
}
}
}
var myGreatMixin = {
// ...
methods: {
$update: function () {
// ...
}
}
}
var myGreatMixin = {
// ...
methods: {
$_update: function () {
// ...
}
}
}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-6 "好例子")好例子
var myGreatMixin = {
// ...
methods: {
$_myGreatMixin_update: function () {
// ...
}
}
}
## [優先級 B 的規則:強烈推薦 (增強可讀性)](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-B-%E7%9A%84%E8%A7%84%E5%88%99%EF%BC%9A%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90-%E5%A2%9E%E5%BC%BA%E5%8F%AF%E8%AF%BB%E6%80%A7 "優先級 B 的規則:強烈推薦 (增強可讀性)")
### [組件文件強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6%E6%96%87%E4%BB%B6-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "組件文件 強烈推薦")
**只要有能夠拼接文件的構建系統,就把每個組件單獨分成文件。**
當你需要編輯一個組件或查閱一個組件的用法時,可以更快速的找到它。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-7 "反例")反例
Vue.component('TodoList', {
// ...
})
Vue.component('TodoItem', {
// ...
})
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-7 "好例子")好例子
components/
|- TodoList.js
|- TodoItem.js
components/
|- TodoList.vue
|- TodoItem.vue
### [單文件組件文件的大小寫強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%8D%95%E6%96%87%E4%BB%B6%E7%BB%84%E4%BB%B6%E6%96%87%E4%BB%B6%E7%9A%84%E5%A4%A7%E5%B0%8F%E5%86%99-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "單文件組件文件的大小寫 強烈推薦")
**[單文件組件](https://vuejs.bootcss.com/v2/guide/single-file-components.html)的文件名應該要么始終是單詞大寫開頭 (PascalCase),要么始終是橫線連接 (kebab-case)。**
單詞大寫開頭對于代碼編輯器的自動補全最為友好,因為這使得我們在 JS(X) 和模板中引用組件的方式盡可能的一致。然而,混用文件命名方式有的時候會導致大小寫不敏感的文件系統的問題,這也是橫線連接命名同樣完全可取的原因。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-8 "反例")反例
components/
|- mycomponent.vue
components/
|- myComponent.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-8 "好例子")好例子
components/
|- MyComponent.vue
components/
|- my-component.vue
### [基礎組件名強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%9F%BA%E7%A1%80%E7%BB%84%E4%BB%B6%E5%90%8D-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "基礎組件名 強烈推薦")
**應用特定樣式和約定的基礎組件 (也就是展示類的、無邏輯的或無狀態的組件) 應該全部以一個特定的前綴開頭,比如`Base`、`App`或`V`。**
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-9 "反例")反例
components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-9 "好例子")好例子
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
components/
|- AppButton.vue
|- AppTable.vue
|- AppIcon.vue
components/
|- VButton.vue
|- VTable.vue
|- VIcon.vue
### [單例組件名強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%8D%95%E4%BE%8B%E7%BB%84%E4%BB%B6%E5%90%8D-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "單例組件名 強烈推薦")
**只應該擁有單個活躍實例的組件應該以`The`前綴命名,以示其唯一性。**
這不意味著組件只可用于一個單頁面,而是*每個頁面*只使用一次。這些組件永遠不接受任何 prop,因為它們是為你的應用定制的,而不是它們在你的應用中的上下文。如果你發現有必要添加 prop,那就表明這實際上是一個可復用的組件,*只是目前*在每個頁面里只使用一次。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-10 "反例")反例
components/
|- Heading.vue
|- MySidebar.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-10 "好例子")好例子
components/
|- TheHeading.vue
|- TheSidebar.vue
### [緊密耦合的組件名強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%B4%A7%E5%AF%86%E8%80%A6%E5%90%88%E7%9A%84%E7%BB%84%E4%BB%B6%E5%90%8D-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "緊密耦合的組件名 強烈推薦")
**和父組件緊密耦合的子組件應該以父組件名作為前綴命名。**
如果一個組件只在某個父組件的場景下有意義,這層關系應該體現在其名字上。因為編輯器通常會按字母順序組織文件,所以這樣做可以把相關聯的文件排在一起。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-11 "反例")反例
components/
|- TodoList.vue
|- TodoItem.vue
|- TodoButton.vue
components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-11 "好例子")好例子
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
### [組件名中的單詞順序強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6%E5%90%8D%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D%E9%A1%BA%E5%BA%8F-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "組件名中的單詞順序 強烈推薦")
**組件名應該以高級別的 (通常是一般化描述的) 單詞開頭,以描述性的修飾詞結尾。**
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-12 "反例")反例
components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-12 "好例子")好例子
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
### [自閉合組件強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E8%87%AA%E9%97%AD%E5%90%88%E7%BB%84%E4%BB%B6-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "自閉合組件 強烈推薦")
**在[單文件組件](https://vuejs.bootcss.com/v2/guide/single-file-components.html)、字符串模板和[JSX](https://vuejs.bootcss.com/v2/guide/render-function.html#JSX)中沒有內容的組件應該是自閉合的——但在 DOM 模板里永遠不要這樣做。**
自閉合組件表示它們不僅沒有內容,而且**刻意**沒有內容。其不同之處就好像書上的一頁白紙對比貼有“本頁有意留白”標簽的白紙。而且沒有了額外的閉合標簽,你的代碼也更簡潔。
不幸的是,HTML 并不支持自閉合的自定義元素——只有[官方的“空”元素](https://www.w3.org/TR/html/syntax.html#void-elements)。所以上述策略僅適用于進入 DOM 之前 Vue 的模板編譯器能夠觸達的地方,然后再產出符合 DOM 規范的 HTML。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-13 "反例")反例
<!-- 在單文件組件、字符串模板和 JSX 中 -->
<MyComponent></MyComponent>
<!-- 在 DOM 模板中 -->
<my-component/>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-13 "好例子")好例子
<!-- 在單文件組件、字符串模板和 JSX 中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>
### [模板中的組件名大小寫強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E6%A8%A1%E6%9D%BF%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E5%90%8D%E5%A4%A7%E5%B0%8F%E5%86%99-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "模板中的組件名大小寫 強烈推薦")
**對于絕大多數項目來說,在[單文件組件](https://vuejs.bootcss.com/v2/guide/single-file-components.html)和字符串模板中組件名應該總是 PascalCase 的——但是在 DOM 模板中總是 kebab-case 的。**
PascalCase 相比 kebab-case 有一些優勢:
* 編輯器可以在模板里自動補全組件名,因為 PascalCase 同樣適用于 JavaScript。
* `<MyComponent>`視覺上比`<my-component>`更能夠和單個單詞的 HTML 元素區別開來,因為前者的不同之處有兩個大寫字母,后者只有一個橫線。
* 如果你在模板中使用任何非 Vue 的自定義元素,比如一個 Web Component,PascalCase 確保了你的 Vue 組件在視覺上仍然是易識別的。
不幸的是,由于 HTML 是大小寫不敏感的,在 DOM 模板中必須仍使用 kebab-case。
還請注意,如果你已經是 kebab-case 的重度用戶,那么與 HTML 保持一致的命名約定且在多個項目中保持相同的大小寫規則就可能比上述優勢更為重要了。在這些情況下,**在所有的地方都使用 kebab-case 同樣是可以接受的。**
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-14 "反例")反例
<!-- 在單文件組件和字符串模板中 -->
<mycomponent/>
<!-- 在單文件組件和字符串模板中 -->
<myComponent/>
<!-- 在 DOM 模板中 -->
<MyComponent></MyComponent>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-14 "好例子")好例子
<!-- 在單文件組件和字符串模板中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>
或者
<!-- 在所有地方 -->
<my-component></my-component>
### [JS/JSX 中的組件名大小寫強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#JS-JSX-%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%E5%90%8D%E5%A4%A7%E5%B0%8F%E5%86%99-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "JS/JSX 中的組件名大小寫 強烈推薦")
**JS/[JSX](https://vuejs.bootcss.com/v2/guide/render-function.html#JSX)中的組件名應該始終是 PascalCase 的,盡管在較為簡單的應用中只使用`Vue.component`進行全局組件注冊時,可以使用 kebab-case 字符串。**
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-15 "反例")反例
Vue.component('myComponent', {
// ...
})
import myComponent from './MyComponent.vue'
export default {
name: 'myComponent',
// ...
}
export default {
name: 'my-component',
// ...
}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-15 "好例子")好例子
Vue.component('MyComponent', {
// ...
})
Vue.component('my-component', {
// ...
})
import MyComponent from './MyComponent.vue'
export default {
name: 'MyComponent',
// ...
}
### [完整單詞的組件名強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%AE%8C%E6%95%B4%E5%8D%95%E8%AF%8D%E7%9A%84%E7%BB%84%E4%BB%B6%E5%90%8D-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "完整單詞的組件名 強烈推薦")
**組件名應該傾向于完整單詞而不是縮寫。**
編輯器中的自動補全已經讓書寫長命名的代價非常之低了,而其帶來的明確性卻是非常寶貴的。不常用的縮寫尤其應該避免。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-16 "反例")反例
components/
|- SdSettings.vue
|- UProfOpts.vue
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-16 "好例子")好例子
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
### [Prop 名大小寫強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#Prop-%E5%90%8D%E5%A4%A7%E5%B0%8F%E5%86%99-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "Prop 名大小寫 強烈推薦")
**在聲明 prop 的時候,其命名應該始終使用 camelCase,而在模板和[JSX](https://vuejs.bootcss.com/v2/guide/render-function.html#JSX)中應該始終使用 kebab-case。**
我們單純的遵循每個語言的約定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中則是 kebab-case。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-17 "反例")反例
props: {
'greeting-text': String
}
<WelcomeMessage greetingText="hi"/>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-17 "好例子")好例子
props: {
greetingText: String
}
<WelcomeMessage greeting-text="hi"/>
### [多個特性的元素強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%A4%9A%E4%B8%AA%E7%89%B9%E6%80%A7%E7%9A%84%E5%85%83%E7%B4%A0-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "多個特性的元素 強烈推薦")
**多個特性的元素應該分多行撰寫,每個特性一行。**
在 JavaScript 中,用多行分隔對象的多個屬性是很常見的最佳實踐,因為這樣更易讀。模板和[JSX](https://vuejs.bootcss.com/v2/guide/render-function.html#JSX)值得我們做相同的考慮。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-18 "反例")反例
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-18 "好例子")好例子
<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo"
>
<MyComponent
foo="a"
bar="b"
baz="c"
/>
### [模板中簡單的表達式強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E6%A8%A1%E6%9D%BF%E4%B8%AD%E7%AE%80%E5%8D%95%E7%9A%84%E8%A1%A8%E8%BE%BE%E5%BC%8F-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "模板中簡單的表達式 強烈推薦")
**組件模板應該只包含簡單的表達式,復雜的表達式則應該重構為計算屬性或方法。**
復雜表達式會讓你的模板變得不那么聲明式。我們應該盡量描述應該出現的*是什么*,而非*如何*計算那個值。而且計算屬性和方法使得代碼可以重用。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-19 "反例")反例
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-19 "好例子")好例子
<!-- 在模板中 -->
{{ normalizedFullName }}
// 復雜表達式已經移入一個計算屬性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
### [簡單的計算屬性強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%AE%80%E5%8D%95%E7%9A%84%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "簡單的計算屬性 強烈推薦")
**應該把復雜計算屬性分割為盡可能多的更簡單的屬性。**
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-20 "反例")反例
computed: {
price: function () {
var basePrice = this.manufactureCost / (1 - this.profitMargin)
return (
basePrice -
basePrice * (this.discountPercent || 0)
)
}
}
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-20 "好例子")好例子
computed: {
basePrice: function () {
return this.manufactureCost / (1 - this.profitMargin)
},
discount: function () {
return this.basePrice * (this.discountPercent || 0)
},
finalPrice: function () {
return this.basePrice - this.discount
}
}
### [帶引號的特性值強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%B8%A6%E5%BC%95%E5%8F%B7%E7%9A%84%E7%89%B9%E6%80%A7%E5%80%BC-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "帶引號的特性值 強烈推薦")
**非空 HTML 特性值應該始終帶引號 (單引號或雙引號,選你 JS 里不用的那個)。**
在 HTML 中不帶空格的特性值是可以沒有引號的,但這鼓勵了大家在特征值里*不寫*空格,導致可讀性變差。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-21 "反例")反例
<input type=text>
<AppSidebar :style={width:sidebarWidth+'px'}>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-21 "好例子")好例子
<input type="text">
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
### [指令縮寫強烈推薦](https://vuejs.bootcss.com/v2/style-guide/#%E6%8C%87%E4%BB%A4%E7%BC%A9%E5%86%99-%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90 "指令縮寫 強烈推薦")
**指令縮寫 (用`:`表示`v-bind:`和用`@`表示`v-on:`) 應該要么都用要么都不用。**
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-22 "反例")反例
<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
<input
v-on:input="onInput"
@focus="onFocus"
>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-22 "好例子")好例子
<input
:value="newTodoText"
:placeholder="newTodoInstructions"
>
<input
v-bind:value="newTodoText"
v-bind:placeholder="newTodoInstructions"
>
<input
@input="onInput"
@focus="onFocus"
>
<input
v-on:input="onInput"
v-on:focus="onFocus"
>
## [優先級 C 的規則:推薦 (將選擇和認知成本最小化)](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-C-%E7%9A%84%E8%A7%84%E5%88%99%EF%BC%9A%E6%8E%A8%E8%8D%90-%E5%B0%86%E9%80%89%E6%8B%A9%E5%92%8C%E8%AE%A4%E7%9F%A5%E6%88%90%E6%9C%AC%E6%9C%80%E5%B0%8F%E5%8C%96 "優先級 C 的規則:推薦 (將選擇和認知成本最小化)")
### [組件/實例的選項的順序推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6-%E5%AE%9E%E4%BE%8B%E7%9A%84%E9%80%89%E9%A1%B9%E7%9A%84%E9%A1%BA%E5%BA%8F-%E6%8E%A8%E8%8D%90 "組件/實例的選項的順序 推薦")
**組件/實例的選項應該有統一的順序。**
這是我們推薦的組件選項默認順序。它們被劃分為幾大類,所以你也能知道從插件里添加的新屬性應該放到哪里。
1. **副作用**(觸發組件外的影響)
* `el`
2. **全局感知**(要求組件以外的知識)
* `name`
* `parent`
3. **組件類型**(更改組件的類型)
* `functional`
4. **模板修改器**(改變模板的編譯方式)
* `delimiters`
* `comments`
5. **模板依賴**(模板內使用的資源)
* `components`
* `directives`
* `filters`
6. **組合**(向選項里合并屬性)
* `extends`
* `mixins`
7. **接口**(組件的接口)
* `inheritAttrs`
* `model`
* `props`/`propsData`
8. **本地狀態**(本地的響應式屬性)
* `data`
* `computed`
9. **事件**(通過響應式事件觸發的回調)
* `watch`
* 生命周期鉤子 (按照它們被調用的順序)
* `beforeCreate`
* `created`
* `beforeMount`
* `mounted`
* `beforeUpdate`
* `updated`
* `activated`
* `deactivated`
* `beforeDestroy`
* `destroyed`
10. **非響應式的屬性**(不依賴響應系統的實例屬性)
* `methods`
11. **渲染**(組件輸出的聲明式描述)
* `template`/`render`
* `renderError`
### [元素特性的順序推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%85%83%E7%B4%A0%E7%89%B9%E6%80%A7%E7%9A%84%E9%A1%BA%E5%BA%8F-%E6%8E%A8%E8%8D%90 "元素特性的順序 推薦")
**元素 (包括組件) 的特性應該有統一的順序。**
這是我們為組件選項推薦的默認順序。它們被劃分為幾大類,所以你也能知道新添加的自定義特性和指令應該放到哪里。
1. **定義**(提供組件的選項)
* `is`
2. **列表渲染**(創建多個變化的相同元素)
* `v-for`
3. **條件渲染**(元素是否渲染/顯示)
* `v-if`
* `v-else-if`
* `v-else`
* `v-show`
* `v-cloak`
4. **渲染方式**(改變元素的渲染方式)
* `v-pre`
* `v-once`
5. **全局感知**(需要超越組件的知識)
* `id`
6. **唯一的特性**(需要唯一值的特性)
* `ref`
* `key`
* `slot`
7. **雙向綁定**(把綁定和事件結合起來)
* `v-model`
8. **其它特性**(所有普通的綁定或未綁定的特性)
9. **事件**(組件事件監聽器)
* `v-on`
10. **內容**(覆寫元素的內容)
* `v-html`
* `v-text`
### [組件/實例選項中的空行推薦](https://vuejs.bootcss.com/v2/style-guide/#%E7%BB%84%E4%BB%B6-%E5%AE%9E%E4%BE%8B%E9%80%89%E9%A1%B9%E4%B8%AD%E7%9A%84%E7%A9%BA%E8%A1%8C-%E6%8E%A8%E8%8D%90 "組件/實例選項中的空行 推薦")
**你可能想在多個屬性之間增加一個空行,特別是在這些選項一屏放不下,需要滾動才能都看到的時候。**
當你的組件開始覺得密集或難以閱讀時,在多個屬性之間添加空行可以讓其變得容易。在一些諸如 Vim 的編輯器里,這樣格式化后的選項還能通過鍵盤被快速導航。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-23 "好例子")好例子
props: {
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
},
computed: {
formattedValue: function () {
// ...
},
inputClasses: function () {
// ...
}
}
// 沒有空行在組件易于閱讀和導航時也沒問題。
props: {
value: {
type: String,
required: true
},
focused: {
type: Boolean,
default: false
},
label: String,
icon: String
},
computed: {
formattedValue: function () {
// ...
},
inputClasses: function () {
// ...
}
}
### [單文件組件的頂級元素的順序推薦](https://vuejs.bootcss.com/v2/style-guide/#%E5%8D%95%E6%96%87%E4%BB%B6%E7%BB%84%E4%BB%B6%E7%9A%84%E9%A1%B6%E7%BA%A7%E5%85%83%E7%B4%A0%E7%9A%84%E9%A1%BA%E5%BA%8F-%E6%8E%A8%E8%8D%90 "單文件組件的頂級元素的順序 推薦")
**[單文件組件](https://vuejs.bootcss.com/v2/guide/single-file-components.html)應該總是讓`<script>`、`<template>`和`<style>`標簽的順序保持一致。且`<style>`要放在最后,因為另外兩個標簽至少要有一個。**
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-23 "反例")反例
<style>/* ... */</style>
<script>/* ... */</script>
<template>...</template>
<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>
<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-24 "好例子")好例子
<!-- ComponentA.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>
<!-- ComponentB.vue -->
<script>/* ... */</script>
<template>...</template>
<style>/* ... */</style>
<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
<!-- ComponentB.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
## [優先級 D 的規則:謹慎使用 (有潛在危險的模式)](https://vuejs.bootcss.com/v2/style-guide/#%E4%BC%98%E5%85%88%E7%BA%A7-D-%E7%9A%84%E8%A7%84%E5%88%99%EF%BC%9A%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8-%E6%9C%89%E6%BD%9C%E5%9C%A8%E5%8D%B1%E9%99%A9%E7%9A%84%E6%A8%A1%E5%BC%8F "優先級 D 的規則:謹慎使用 (有潛在危險的模式)")
### [沒有在`v-if`/`v-else-if`/`v-else`中使用`key`謹慎使用](https://vuejs.bootcss.com/v2/style-guide/#%E6%B2%A1%E6%9C%89%E5%9C%A8-v-if-v-else-if-v-else-%E4%B8%AD%E4%BD%BF%E7%94%A8-key-%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8 "沒有在 v-if/v-else-if/v-else 中使用 key 謹慎使用")
**如果一組`v-if`+`v-else`的元素類型相同,最好使用`key`(比如兩個`<div>`元素)。**
默認情況下,Vue 會盡可能高效的更新 DOM。這意味著其在相同類型的元素之間切換時,會修補已存在的元素,而不是將舊的元素移除然后在同一位置添加一個新元素。如果本不相同的元素被識別為相同,則會出現[意料之外的副作用](https://jsfiddle.net/chrisvfritz/bh8fLeds/)。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-24 "反例")反例
<div v-if="error">
錯誤:{{ error }}
</div>
<div v-else>
{{ results }}
</div>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-25 "好例子")好例子
<div
v-if="error"
key="search-status"
>
錯誤:{{ error }}
</div>
<div
v-else
key="search-results"
>
{{ results }}
</div>
<p v-if="error">
錯誤:{{ error }}
</p>
<div v-else>
{{ results }}
</div>
### [`scoped`中的元素選擇器謹慎使用](https://vuejs.bootcss.com/v2/style-guide/#scoped-%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E9%80%89%E6%8B%A9%E5%99%A8-%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8 "scoped 中的元素選擇器 謹慎使用")
**元素選擇器應該避免在`scoped`中出現。**
在`scoped`樣式中,類選擇器比元素選擇器更好,因為大量使用元素選擇器是很慢的。
#### 詳解
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-25 "反例")反例
<template>
<button>X</button>
</template>
<style scoped>
button {
background-color: red;
}
</style>
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-26 "好例子")好例子
<template>
<button class="btn btn-close">X</button>
</template>
<style scoped>
.btn-close {
background-color: red;
}
</style>
### [隱性的父子組件通信謹慎使用](https://vuejs.bootcss.com/v2/style-guide/#%E9%9A%90%E6%80%A7%E7%9A%84%E7%88%B6%E5%AD%90%E7%BB%84%E4%BB%B6%E9%80%9A%E4%BF%A1-%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8 "隱性的父子組件通信 謹慎使用")
**應該優先通過 prop 和事件進行父子組件之間的通信,而不是`this.$parent`或改變 prop。**
一個理想的 Vue 應用是 prop 向下傳遞,事件向上傳遞的。遵循這一約定會讓你的組件更易于理解。然而,在一些邊界情況下 prop 的變更或`this.$parent`能夠簡化兩個深度耦合的組件。
問題在于,這種做法在很多*簡單*的場景下可能會更方便。但請當心,不要為了一時方便 (少寫代碼) 而犧牲數據流向的簡潔性 (易于理解)。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-26 "反例")反例
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: '<input v-model="todo.text">'
})
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
removeTodo () {
var vm = this
vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
return todo.id !== vm.todo.id
})
}
},
template: `
<span>
{{ todo.text }}
<button @click="removeTodo">
X
</button>
</span>
`
})
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-27 "好例子")好例子
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: `
<input
:value="todo.text"
@input="$emit('input', $event.target.value)"
>
`
})
Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: `
<span>
{{ todo.text }}
<button @click="$emit('delete')">
X
</button>
</span>
`
})
### [非 Flux 的全局狀態管理謹慎使用](https://vuejs.bootcss.com/v2/style-guide/#%E9%9D%9E-Flux-%E7%9A%84%E5%85%A8%E5%B1%80%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86-%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8 "非 Flux 的全局狀態管理 謹慎使用")
**應該優先通過[Vuex](https://github.com/vuejs/vuex)管理全局狀態,而不是通過`this.$root`或一個全局事件總線。**
通過`this.$root`和/或[全局事件總線](https://vuejs.bootcss.com/v2/guide/migration.html#dispatch-%E5%92%8C-broadcast-%E6%9B%BF%E6%8D%A2)管理狀態在很多簡單的情況下都是很方便的,但是并不適用于絕大多數的應用。Vuex 提供的不僅是一個管理狀態的中心區域,還是組織、追蹤和調試狀態變更的好工具。
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%8F%8D%E4%BE%8B-27 "反例")反例
// main.js
new Vue({
data: {
todos: []
},
created: function () {
this.$on('remove-todo', this.removeTodo)
},
methods: {
removeTodo: function (todo) {
var todoIdToRemove = todo.id
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoIdToRemove
})
}
}
})
#### [](https://vuejs.bootcss.com/v2/style-guide/#%E5%A5%BD%E4%BE%8B%E5%AD%90-28 "好例子")好例子
// store/modules/todos.js
export default {
state: {
list: []
},
mutations: {
REMOVE_TODO (state, todoId) {
state.list = state.list.filter(todo => todo.id !== todoId)
}
},
actions: {
removeTodo ({ commit, state }, todo) {
commit('REMOVE_TODO', todo.id)
}
}
}
<!-- TodoItem.vue -->
<template>
<span>
{{ todo.text }}
<button @click="removeTodo(todo)">
X
</button>
</span>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods: mapActions(['removeTodo'])
}
</script>
發現錯誤?想參與編輯?[在 GitHub 上編輯此頁!](https://github.com/vuejs/cn.vuejs.org/blob/master/src/v2/style-guide/index.md)