组件名应该始终是多个单词的,根组件App
以及<transition>
、<component>
之类的 Vue 内置组件除外。css
这样作能够避免跟现有的以及将来的 HTML 元素相冲突,由于全部的 HTML 元素名称都是单个单词的。html
反例前端
Vue.component('todo', { // ... }) export default { name: 'Todo', // ... }
好例子vue
Vue.component('todo-item', { // ... }) export default { name: 'TodoItem', // ... }
组件的data
必须是一个函数。git
当在组件中使用data
属性的时候 (除了new Vue
外的任何地方),它的值必须是返回一个对象的函数。github
反例web
Vue.component('some-comp', { data: { foo: 'bar' } })
export default { data: { foo: 'bar' } }
好例子vue-cli
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 定义应该尽可能详细。编辑器
在你提交的代码中,prop 的定义应该尽可能详细,至少须要指定其类型。ide
反例
// 这样作只有开发原型系统时能够接受 props: ['status']
好例子
props: { status: String }
// 更好的作法! props: { status: { type: String, required: true, validator: function (value) { return [ 'syncing', 'synced', 'version-conflict', 'error' ].indexOf(value) !== -1 } } }
v-for
设置键值老是用key
配合v-for
。
在组件上_老是_必须用key
配合v-for
,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,好比动画中的对象固化 (object constancy),也是一种好的作法。
反例子
<ul> <li v-for="todo in todos"> {{ todo.text }} </li> </ul>
好例子
<ul> <li v-for="todo in todos" :key="todo.id" > {{ todo.text }} </li> </ul>
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
)。反例
<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>
好例子
<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>
对于应用来讲,顶级App
组件和布局组件中的样式能够是全局的,可是其它全部组件都应该是有做用域的。
这条规则只和单文件组件有关。你_不必定_要使用scoped
attribute。设置做用域也能够经过CSS Modules,那是一个基于 class 的相似BEM的策略,固然你也可使用其它的库或约定。
无论怎样,对于组件库,咱们应该更倾向于选用基于 class 的策略而不是scoped
attribute。
这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有过高的选择器优先级,并且不太会致使冲突。
反例
<template> <button class="btn btn-close">X</button> </template> <style> .btn-close { background-color: red; } </style>
好例子
<template> <button class="button button-close">X</button> </template> <!-- 使用 `scoped` attribute --> <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>
只要有可以拼接文件的构建系统,就把每一个组件单独分红文件。
当你须要编辑一个组件或查阅一个组件的用法时,能够更快速的找到它。
反例
Vue.component('TodoList', { // ... }) Vue.component('TodoItem', { // ... })
好例子
components/ |- TodoList.js |- TodoItem.js
components/ |- TodoList.vue |- TodoItem.vue
单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线链接 (kebab-case)。
单词大写开头对于代码编辑器的自动补全最为友好,由于这使得咱们在 JS(X) 和模板中引用组件的方式尽量的一致。然而,混用文件命名方式有的时候会致使大小写不敏感的文件系统的问题,这也是横线链接命名一样彻底可取的缘由。
反例
components/ |- mycomponent.vue
components/ |- myComponent.vue
好例子
components/ |- MyComponent.vue
components/ |- my-component.vue
应用特定样式和约定的基础组件 (也就是展现类的、无逻辑的或无状态的组件) 应该所有以一个特定的前缀开头,好比Base
、App
或V
。
反例
components/ |- MyButton.vue |- VueTable.vue |- Icon.vue
好例子
components/ |- BaseButton.vue |- BaseTable.vue |- BaseIcon.vue
components/ |- AppButton.vue |- AppTable.vue |- AppIcon.vue
components/ |- VButton.vue |- VTable.vue |- VIcon.vue
只应该拥有单个活跃实例的组件应该以The
前缀命名,以示其惟一性。
这不意味着组件只可用于一个单页面,而是_每一个页面_只使用一次。这些组件永远不接受任何 prop,由于它们是为你的应用定制的,而不是它们在你的应用中的上下文。若是你发现有必要添加 prop,那就代表这其实是一个可复用的组件,_只是目前_在每一个页面里只使用一次。
反例
components/ |- Heading.vue |- MySidebar.vue
好例子
components/ |- TheHeading.vue |- TheSidebar.vue
和父组件紧密耦合的子组件应该以父组件名做为前缀命名。
若是一个组件只在某个父组件的场景下有意义,这层关系应该体如今其名字上。由于编辑器一般会按字母顺序组织文件,因此这样作能够把相关联的文件排在一块儿。
反例
components/ |- TodoList.vue |- TodoItem.vue |- TodoButton.vue
components/ |- SearchSidebar.vue |- NavigationForSearchSidebar.vue
好例子
components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue
components/ |- SearchSidebar.vue |- SearchSidebarNavigation.vue
组件名应该以高级别的 (一般是通常化描述的) 单词开头,以描述性的修饰词结尾。
反例
components/ |- ClearSearchButton.vue |- ExcludeFromSearchInput.vue |- LaunchOnStartupCheckbox.vue |- RunSearchButton.vue |- SearchInput.vue |- TermsCheckbox.vue
好例子
components/ |- SearchButtonClear.vue |- SearchButtonRun.vue |- SearchInputQuery.vue |- SearchInputExcludeGlob.vue |- SettingsCheckboxTerms.vue |- SettingsCheckboxLaunchOnStartup.vue
在单文件组件、字符串模板和JSX中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样作。
自闭合组件表示它们不只没有内容,并且刻意没有内容。其不一样之处就好像书上的一页白纸对比贴有“本页有意留白”标签的白纸。并且没有了额外的闭合标签,你的代码也更简洁。
不幸的是,HTML 并不支持自闭合的自定义元素——只有官方的“空”元素。因此上述策略仅适用于进入 DOM 以前 Vue 的模板编译器可以触达的地方,而后再产出符合 DOM 规范的 HTML。
反例
<!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent></MyComponent>
<!-- 在 DOM 模板中 --> <my-component/>
好例子
<!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent/>
<!-- 在 DOM 模板中 --> <my-component></my-component>
对于绝大多数项目来讲,在单文件组件和字符串模板中组件名应该老是 PascalCase 的——可是在 DOM 模板中老是 kebab-case 的。
PascalCase 相比 kebab-case 有一些优点:
<MyComponent>
视觉上比<my-component>
更可以和单个单词的 HTML 元素区别开来,由于前者的不一样之处有两个大写字母,后者只有一个横线。不幸的是,因为 HTML 是大小写不敏感的,在 DOM 模板中必须仍使用 kebab-case。
还请注意,若是你已是 kebab-case 的重度用户,那么与 HTML 保持一致的命名约定且在多个项目中保持相同的大小写规则就可能比上述优点更为重要了。在这些状况下,在全部的地方都使用 kebab-case 一样是能够接受的。
反例
<!-- 在单文件组件和字符串模板中 --> <mycomponent/>
<!-- 在单文件组件和字符串模板中 --> <myComponent/>
<!-- 在 DOM 模板中 --> <MyComponent></MyComponent>
好例子
<!-- 在单文件组件和字符串模板中 --> <MyComponent/>
<!-- 在 DOM 模板中 --> <my-component></my-component>
或者
<!-- 在全部地方 --> <my-component></my-component>
JS/JSX中的组件名应该始终是 PascalCase 的,尽管在较为简单的应用中只使用Vue.component
进行全局组件注册时,可使用 kebab-case 字符串。
反例
Vue.component('myComponent', { // ... })
import myComponent from './MyComponent.vue'
export default { name: 'myComponent', // ... }
export default { name: 'my-component', // ... }
好例子
Vue.component('MyComponent', { // ... })
Vue.component('my-component', { // ... })
import MyComponent from './MyComponent.vue'
export default { name: 'MyComponent', // ... }
组件名应该倾向于完整单词而不是缩写。
编辑器中的自动补全已经让书写长命名的代价很是之低了,而其带来的明确性倒是很是宝贵的。不经常使用的缩写尤为应该避免。
反例
components/ |- SdSettings.vue |- UProfOpts.vue
好例子
components/ |- StudentDashboardSettings.vue |- UserProfileOptions.vue
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和JSX中应该始终使用 kebab-case。
咱们单纯的遵循每一个语言的约定。在 JavaScript 中更天然的是 camelCase。而在 HTML 中则是 kebab-case。
反例
props: { 'greeting-text': String }
<WelcomeMessage greetingText="hi"/>
好例子
props: { greetingText: String }
<WelcomeMessage greeting-text\="hi"/>
多个 attribute 的元素应该分多行撰写,每一个 attribute 一行。
在 JavaScript 中,用多行分隔对象的多个属性是很常见的最佳实践,由于这样更易读。模板和JSX值得咱们作相同的考虑。
反例
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
好例子
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo" >
<MyComponent foo="a" bar="b" baz="c" />
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。咱们应该尽可能描述应该出现的_是什么_,而非_如何_计算那个值。并且计算属性和方法使得代码能够重用。
反例
{{ fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }}
好例子
<!-- 在模板中 --> {{ normalizedFullName }}
// 复杂表达式已经移入一个计算属性 computed: { normalizedFullName: function () { return this.fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') } }
应该把复杂计算属性分割为尽量多的更简单的属性。
反例
computed: { price: function () { var basePrice = this.manufactureCost / (1 - this.profitMargin) return ( basePrice - basePrice * (this.discountPercent || 0) ) } }
好例子
computed: { basePrice: function () { return this.manufactureCost / (1 - this.profitMargin) }, discount: function () { return this.basePrice * (this.discountPercent || 0) }, finalPrice: function () { return this.basePrice - this.discount } }
非空 HTML attribute 值应该始终带引号 (单引号或双引号,选你 JS 里不用的那个)。
在 HTML 中不带空格的 attribute 值是能够没有引号的,但这鼓励了你们在特征值里_不写_空格,致使可读性变差。
反例
<input type=text>
<AppSidebar :style={width:sidebarWidth+'px'}>
好例子
<input type="text">
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
指令缩写 (用:
表示v-bind:
、用@
表示v-on:
和用#
表示v-slot:
) 应该要么都用要么都不用。
反例
<input v-bind:value="newTodoText" :placeholder="newTodoInstructions" >
<input v-on:input="onInput" @focus="onFocus" >
<template v-slot:header> <h1>Here might be a page title</h1> </template> <template #footer> <p>Here's some contact info</p> </template>
好例子
<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" >
<template v-slot:header> <h1>Here might be a page title</h1> </template> <template v-slot:footer> <p>Here's some contact info</p> </template>
<template #header> <h1>Here might be a page title</h1> </template> <template #footer> <p>Here's some contact info</p> </template>