vue大部分规范需参照HTML、CSS、JavaScript规范,在此不再强调。
- 
 组件名应该始终是多个单词的
 根组件 
 
 App
 
 以及
 
 <transition>
 
 、
 
 <component>
 
 之类的 Vue 内置组件除外。
 
 这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
 
 – Example –
 
 -js // 不推荐 Vue.component('todo', { // ... }) export default { name: 'Todo', // ... } // 推荐 Vue.component('todo-item', { // ... }) export default { name: 'TodoItem', // ... }
- 
 组件的
 
 data
 
 必须是一个函数
 当在组件中使用 data property 的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 
 
 – Example –
 
 -js // 不推荐 Vue.component('some-comp', { data: { foo: 'bar' } }) export default { data: { foo: 'bar' } } // 推荐 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
 
 定义应该尽量详细
 至少需要指定其类型(type)。 
 
 – Example –
 
 -js // 不推荐 // 这样做只有开发原型系统时可以接受 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
 
 。
 
 – Example –
 
 -html <!-- 不推荐 --> <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-for=“user in users” v-if=“user.isActive”)。在这种情形下,请将 users 替换为一个计算属性 (比如 activeUsers),让其返回过滤后的列表。
- 为了避免渲染本应该被隐藏的列表 (比如 v-for=“user in users” v-if=“shouldShowUsers”)。这种情形下,请将 v-if 移动至容器元素上 (比如 ul、ol)。
 
 
 – Example –
 
 -html <!-- 不推荐 --> <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 的策略)
 
 
 – Example –
 
 -html <!-- 不推荐 --> <template> <button class="btn btn-close">X</button> </template> <style> .btn-close { background-color: red; } </style> <!-- 推荐 --> <!-- 使用 `scoped` attribute --> <template> <button class="button button-close">X</button> </template> <style scoped> .button { border: none; border-radius: 2px; } .button-close { background-color: red; } </style> <!-- 使用 CSS Modules --> <template> <button :class="[$style.button, $style.buttonClose]">X</button> </template> <style module> .button { border: none; border-radius: 2px; } .buttonClose { background-color: red; } </style> <!-- 使用 BEM 约定 --> <template> <button class="c-Button c-Button--close">X</button> </template> <style> .c-Button { border: none; border-radius: 2px; } .c-Button--close { background-color: red; } </style>
- 
 私有
 
 property
 
 名
 使用模块作用域保持不允许外部访问的函数的私有性。如果无法做到这一点,就始终为插件、混入等不考虑作为对外公共 API 的自定义私有 
 
 property
 
 使用
 
 $_
 
 前缀。并附带一个命名空间以回避和其它作者的冲突 (比如
 
 $_yourPluginName_
 
 )。
 
 – Example –
 
 -js // 不推荐 var myGreatMixin = { // ... methods: { update: function () { // ... } } } var myGreatMixin = { // ... methods: { _update: function () { // ... } } } var myGreatMixin = { // ... methods: { $update: function () { // ... } } } var myGreatMixin = { // ... methods: { $_update: function () { // ... } } } // 推荐 var myGreatMixin = { // ... methods: { $_myGreatMixin_update: function () { // ... } } } // 甚至更好! var myGreatMixin = { // ... methods: { publicMethod() { // ... myPrivateFunction() } } } function myPrivateFunction() { // ... } export default myGreatMixin
- 
 组件文件
 只要有能够拼接文件的构建系统,就把每个组件单独分成文件。 
 
 – Example –
 
 -js // 不推荐 Vue.component('TodoList', { // ... }) Vue.component('TodoItem', { // ... })- // 推荐 components/ |- TodoList.js |- TodoItem.js components/ |- TodoList.vue |- TodoItem.vue
- 
 单文件组件文件的大小写
 单文件组件的文件名应该: - 始终是单词大写开头 (PascalCase);
- 
        
 始终是横线连接 (kebab-case)
 
 。
 
 
 – Example –
 
 - // 不推荐 components/ |- mycomponent.vue components/ |- myComponent.vue // 推荐 components/ |- MyComponent.vue components/ |- my-component.vue
- 
 基础组件名
 应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 
 
 Base
 
 、
 
 App
 
 或
 
 V
 
 。
 
 这些组件为你的应用奠定了一致的基础样式和行为。它们可能只包括:- HTML 元素;
- 其它基础组件;
- 第三方 UI 组件库.
 好处: - 基础组件会全部列在一起,这样更容易识别;
- 可以避免你在包裹简单组件时随意选择前缀 (比如 MyButton、VueButton);
- 因为这些组件会被频繁使用,所以你可能想把它们放到全局而不是在各处分别导入它们。
 
 
 – Example –
 
 - // 不推荐 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 前缀命名,以示其唯一性。 
 
 这不意味着组件只可用于一个单页面,而是每个页面只使用一次。
 
 – Example –
 
 - // 不推荐 components/ |- Heading.vue |- MySidebar.vue // 推荐 components/ |- TheHeading.vue |- TheSidebar.vue
- 
 紧密耦合的组件名
 和父组件紧密耦合的子组件应该以父组件名作为前缀命名。 
 
 不推荐 在其父组件命名的目录中嵌套子组件。
 
 – Example –
 
 - // 不推荐 components/ |- TodoList.vue |- TodoItem.vue |- TodoButton.vue components/ |- SearchSidebar.vue |- NavigationForSearchSidebar.vue // 推荐 components/ |- TodoList.vue |- TodoListItem.vue |- TodoListItemButton.vue components/ |- SearchSidebar.vue |- SearchSidebarNavigation.vue
- 
 组件名中的单词顺序
 组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。 
 
 如果是一组组件,建议以 高级别的 (通常是一般化描述的) 单词 为名创建一个文件夹,统一放置相关组件文件。
 
 – Example –
 
 - // 不推荐 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 components/ |- search/ |- ButtonClear.vue |- ButtonRun.vue |- InputQuery.vue |- InputExcludeGlob.vue |-setting/ |- CheckboxTerms.vue |- CheckboxLaunchOnStartup.vue
- 
 自闭合组件
 在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。 
 
 – Example –
 
 -html <!-- 不推荐 --> <!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent></MyComponent> <!-- 在 DOM 模板中 --> <my-component/> <!-- 推荐 --> <!-- 在单文件组件、字符串模板和 JSX 中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component>
- 
 自模板中的组件名大小写
 对于绝大多数项目来说,在单文件组件和字符串模板中组件名应该总是 PascalCase 的——但是在 DOM 模板中总是 kebab-case 的。 
 
 
 在所有地方使用 kebab-case
 
 
 – Example –
 
 -html <!-- 不推荐 --> <!-- 在单文件组件和字符串模板中 --> <mycomponent/> <!-- 在单文件组件和字符串模板中 --> <myComponent/> <!-- 在 DOM 模板中 --> <MyComponent></MyComponent> <!-- 推荐 --> <!-- 在单文件组件和字符串模板中 --> <MyComponent/> <!-- 在 DOM 模板中 --> <my-component></my-component> <!-- 在所有地方 --> <my-component/>
- 
 JS/JSX 中的组件名大小写
 
 JS/JSX
 
 中的组件名应该始终是 PascalCase 的,尽管在较为简单的应用中只使用
 
 Vue.component
 
 进行全局组件注册时,可以使用 kebab-case 字符串。
 
 – Example –
 
 -js // 不推荐 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', // ... }
- 
 完整单词的组件名
 组件名应该倾向于完整单词而不是缩写。 
 
 – Example –
 
 - // 不推荐 components/ |- SdSettings.vue |- UProfOpts.vue // 推荐 components/ |- StudentDashboardSettings.vue |- UserProfileOptions.vue
- 
 
 Prop
 
 名大小写
 在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case。 
 
 – Example –
 
 
 
 不推荐:-js props: { 'greeting-text': String }-html <welcome-message greetingText="hi"/>推荐: -js props: { greetingText: String }-html <welcome-message greeting-text="hi"/>
- 
 多个
 
 attribute
 
 的元素
 多个 
 
 attribute
 
 的元素应该一行撰写,超出 80 字符按照
 
 attribute
 
 元素进行换行。
 
 – Example –
 
 -html <!-- 不推荐 --> <img src="https://vuejs.org/images/logo.png" alt="Vue Logo" > <my-component foo="a" bar="b" baz="c" /> <!-- 推荐 --> <img src="https://vuejs.org/images/logo.png" alt="Vue Logo"> <my-component foo="a" bar="b" baz="c"/>
- 
 模板中简单的表达式
 组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。 
 
 
 {
 
 {
 
 
 后要空一格,
 
 }}
 
 前要空一格
 
 – Example –
 
 -html <!-- 不推荐 --> <div> {{ fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') }} </div> <!-- 推荐 --> <div>{{ normalizedFullName }}</div>-js // 复杂表达式已经移入一个计算属性 computed: { normalizedFullName: function () { return this.fullName.split(' ').map(function (word) { return word[0].toUpperCase() + word.slice(1) }).join(' ') } }
- 
 简单的计算属性
 应该把复杂计算属性分割为尽可能多的更简单的 property。 
 
 – Example –
 
 -js // 不推荐 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 } }
- 
 带引号的
 
 attribute
 
 值
 非空 HTML attribute 值应该始终带双引号 。 
 
 – Example –
 
 -html <!-- 不推荐 --> <input type=text> <app-sidebar :style={width:sidebarWidth+'px'}> <!-- 推荐 --> <input type="text"> <app-sidebar :style="{ width: sidebarWidth + 'px'}">
- 
 指令缩写
 指令缩写 (用 : 表示 v-bind:、用 @ 表示 v-on: 和用 # 表示 v-slot:) 
 
 – Example –
 
 -html <!-- 不推荐 --> <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> <!-- 推荐 --> <input :value="newTodoText" :placeholder="newTodoInstructions"> <input @input="onInput" @focus="onFocus"> <template #header> <h1>Here might be a page title</h1> </template>
- 
 组件/实例的选项的统一顺序
 - 副作用 (触发组件外的影响);(el)
- 全局感知 (要求组件以外的知识);(name/parent)
- 组件类型 (更改组件的类型);(functional)
- 模板修改器 (改变模板的编译方式);(delimiters/comments)
- 模板依赖 (模板内使用的资源);(components/directives/filters)
- 组合 (向选项里合并 property);(extends/mixins)
- 接口 (组件的接口);(inheritAttrs/model/props/propsData)
- 本地状态 (本地的响应式 property);(data/computed)
- 
       事件 (通过响应式事件触发的回调);(watch/生命周期钩子)
- 生命周期钩子顺序:beforeCreate / created / beforeMount / mounted / beforeUpdate / updated / activate d /deactivated / beforeDestroy / destroyed
 
- 非响应式的 property (不依赖响应系统的实例 property);(methods)
- 渲染 (组件输出的声明式描述)。(template/render/renderError)
 - 
       最常用组件/实例顺序
- 全局感知 (要求组件以外的知识);(name/parent)
- 模板修改器 (改变模板的编译方式);(delimiters/comments)
- 模板依赖 (模板内使用的资源);(components/directives/filters)
- 接口 (组件的接口);(inheritAttrs/model/props/propsData)
- 本地状态 (本地的响应式 property);(data/computed)
- 
         事件 (通过响应式事件触发的回调);(watch/生命周期钩子)
- 生命周期钩子顺序:beforeCreate / created / beforeMount / mounted / beforeUpdate / updated / activate d /deactivated / beforeDestroy / destroyed
 
- 非响应式的 property (不依赖响应系统的实例 property)。(methods)
 
 
- 
 元素
 
 attribute
 
 的顺序
 - 定义 (提供组件的选项);(is)
- 列表渲染 (创建多个变化的相同元素);(v-for)
- 条件渲染 (元素是否渲染/显示);(v-if/v-else-if/v-else/v-show/v-cloak)
- 渲染方式 (改变元素的渲染方式);(v-pre/v-once)
- 全局感知 (需要超越组件的知识);(id)
- 
       唯一的
 
 attribute
 
 (需要唯一值的
 
 attribute
 
 );(ref/key)
- 双向绑定 (把绑定和事件结合起来);(v-model)
- 事件 (组件事件监听器);(v-on)
- 内容 (覆写元素的内容);(v-html/v-text)
- 
       其它
 
 attribute
 
 (所有普通的绑定或未绑定的
 
 attribute
 
 )。
 
- 
 组件/实例选项中的空行
 一组 
 
 property
 
 之间,空行隔开
 
 – Example –
 
 -js // 推荐 props: { value: { type: String, required: true }, focused: { type: Boolean, default: false }, label: String, icon: String }, data() { return { advertInfo:[], advertConfig:{}, other1:'', other2:'', } }, computed: { formattedValue: function () { // ... }, inputClasses: function () { // ... } }
- 
 单文件组件的顶级元素的顺序
 
 
 – Example –
 
 -html <!-- 推荐 --> <template>...</template> <script>/* ... */</script> <style>/* ... */</style>
- 
 避免在
 
 scoped
 
 中使用元素选择器
 
 
 – Example –
 
 -html <!-- 不推荐 --> <template> <button>X</button> </template> <style scoped> button { background-color: red; } </style> <!-- 推荐 --> <template> <button class="btn btn-close">X</button> </template> <style scoped> .btn-close { background-color: red; } </style>
- 
 隐性的父子组件通信
 应该优先通过 
 
 prop
 
 和事件进行父子组件之间的通信,而不是
 
 this.$parent
 
 或变更
 
 prop
 
 。
- 
 非 Flux 的全局状态管理
 应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。 
- 
 Vue Router 规范
 - 
页面跳转数据传递使用路由参数。 
 
 – Example –
 
 -js let id = '123'; this.$router.push({ name: 'userCenter', query: { id: id } });
- 
router 中的命名规范。 - path、childrenPoints 命名规范采用kebab-case命名规范;
- 
         path必须以
 
 /
 
 开头,
 
 children
 
 里的path也要以
 
 /
 
 开头;
- name 命名规范采用KebabCase命名规范且和component组件名保持一致。
 
 
- 
 
