提示
vue大部分规范需参照HTML、CSS、JavaScript规范
# 组件名应该始终是多个单词的
根组件 App 以及 transition、component 之类的 Vue 内置组件除外。 这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
// 不推荐
Vue.component('todo', {
// ...
})
export default {
name: 'Todo',
// ...
}
// 推荐
Vue.component('todo-item', {
// ...
})
export default {
name: 'TodoItem',
// ...
}
# 组件的 data 必须是一个函数
当在组件中使用 data property 的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。
// 不推荐
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)。
// 不推荐
// 这样做只有开发原型系统时可以接受
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。
<!-- 不推荐 -->
<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)。
<!-- 不推荐 -->
<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 的策略)
<!-- 不推荐 -->
<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>
# 组件文件
只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
// 不推荐
Vue.component('TodoList', {
// ...
})
Vue.component('TodoItem', {
// ...
})
// 推荐
components/
|- TodoList.js
|- TodoItem.js
components/
|- TodoList.vue
|- TodoItem.vue
# 单文件组件文件的大小写
单文件组件的文件名应该:
- 始终是单词大写开头 (PascalCase);
- 始终是横线连接 (kebab-case)。
// 不推荐
components/
|- mycomponent.vue
components/
|- myComponent.vue
// 推荐
components/
|- MyComponent.vue
components/
|- my-component.vue
# 基础组件名
应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。 这些组件为你的应用奠定了一致的基础样式和行为。它们可能只包括:
- HTML 元素;
- 其它基础组件;
- 第三方 UI 组件库.
好处:
- 基础组件会全部列在一起,这样更容易识别;
- 可以避免你在包裹简单组件时随意选择前缀 (比如 MyButton、VueButton);
- 因为这些组件会被频繁使用,所以你可能想把它们放到全局而不是在各处分别导入它们。
// 不推荐
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 前缀命名,以示其唯一性。
- 这不意味着组件只可用于一个单页面,而是每个页面只使用一次。
// 不推荐
components/
|- Heading.vue
|- MySidebar.vue
// 推荐
components/
|- TheHeading.vue
|- TheSidebar.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
components/
|- search/
|- ButtonClear.vue
|- ButtonRun.vue
|- InputQuery.vue
|- InputExcludeGlob.vue
|-setting/
|- CheckboxTerms.vue
|- CheckboxLaunchOnStartup.vue
# 自闭合组件
在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。
<!-- 不推荐 -->
<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent></MyComponent>
<!-- 在 DOM 模板中 -->
<my-component/>
<!-- 推荐 -->
<!-- 在单文件组件、字符串模板和 JSX 中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>
# 自模板中的组件名大小写
- 对于绝大多数项目来说,在单文件组件和字符串模板中组件名应该总是 PascalCase 的——但是在 DOM 模板中总是 kebab-case 的。
- 在所有地方使用 kebab-case
<!-- 不推荐 -->
<!-- 在单文件组件和字符串模板中 -->
<mycomponent/>
<!-- 在单文件组件和字符串模板中 -->
<myComponent/>
<!-- 在 DOM 模板中 -->
<MyComponent></MyComponent>
<!-- 推荐 -->
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>
<!-- 在所有地方 -->
<my-component/>
# JS/JSX 中的组件名大小写
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 名大小写
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case。
// 不推荐
props: {
'greeting-text': String
}
<welcome-message greetingText="hi"/>
// 推荐
props: {
greetingText: String
}
<welcome-message greeting-text="hi"/>
# 多个 attribute 的元素
多个 attribute 的元素应该一行撰写,超出 80 字符按照attribute元素进行换行。
<!-- 不推荐 -->
<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"/>
# 模板中简单的表达式
- 组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
- 前要空一格
<!-- 不推荐 -->
<div>
{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
</div>
<!-- 推荐 -->
<div>{{ normalizedFullName }}</div>
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
# 简单的计算属性
应该把复杂计算属性分割为尽可能多的更简单的 property。
// 不推荐
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 值应该始终带双引号 。
<!-- 推荐 -->
<input type="text">
<app-sidebar :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>
<!-- 推荐 -->
<input :value="newTodoText" :placeholder="newTodoInstructions">
<input @input="onInput" @focus="onFocus">
<template #header>
<h1>Here might be a page title</h1>
</template>
# 组件/实例的选项的统一顺序
- 1.副作用 (触发组件外的影响);(el)
- 2.全局感知 (要求组件以外的知识);(name/parent)
- 3.组件类型 (更改组件的类型);(functional)
- 4.模板修改器 (改变模板的编译方式);(delimiters/comments)
- 5.模板依赖 (模板内使用的资源);(components/directives/filters)
- 6.组合 (向选项里合并 property);(extends/mixins)
- 7.接口 (组件的接口);(inheritAttrs/model/props/propsData)
- 8.本地状态 (本地的响应式 property);(data/computed)
- 9.事件 (通过响应式事件触发的回调);(watch/生命周期钩子)
- .生命周期钩子顺序:beforeCreate / created / beforeMount / mounted / beforeUpdate / updated / activate d /deactivated / beforeDestroy / destroyed
- 10.非响应式的 property (不依赖响应系统的实例 property);(methods)
- 11.渲染 (组件输出的声明式描述)。(template/render/renderError)
最常用组件/实例顺序:
- 1.全局感知 (要求组件以外的知识);(name/parent)
- 2.模板修改器 (改变模板的编译方式);(delimiters/comments)
- 3.模板依赖 (模板内使用的资源);(components/directives/filters)
- 4.接口 (组件的接口);(inheritAttrs/model/props/propsData)
- 5.本地状态 (本地的响应式 property);(data/computed)
- 6.事件 (通过响应式事件触发的回调);(watch/生命周期钩子)
- 生命周期钩子顺序:beforeCreate / created / beforeMount / mounted / beforeUpdate / updated / activate d /deactivated / beforeDestroy / destroyed
- 7.非响应式的 property (不依赖响应系统的实例 property)。(methods)
# 元素 attribute 的顺序
- 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.唯一的 attribute (需要唯一值的 attribute);(ref/key)
- 7.双向绑定 (把绑定和事件结合起来);(v-model)
- 8.事件 (组件事件监听器);(v-on)
- 9.内容 (覆写元素的内容);(v-html/v-text)
- 10.其它 attribute (所有普通的绑定或未绑定的 attribute)。
# 组件/实例选项中的空行
一组 property之间,空行隔开
// 推荐
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 () {
// ...
}
}
# 单文件组件的顶级元素的顺序
<!-- 推荐 -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
# 避免在scoped 中使用元素选择器
<!-- 不推荐 -->
<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 规范
# 页面跳转数据传递使用路由参数
let id = '123'
this.$router.push({ name: 'userCenter', query: { id: id } })
# router 中的命名规范
- path、childrenPoints 命名规范采用kebab-case命名规范;
- path必须以 / 开头,children里的path也要以 / 开头;
- name 命名规范采用KebabCase命名规范且和component组件名保持一致。
# 组件内方法变量命名规范
- 查询列表方法默认命名:getList,如果同一组件内存在多个查询列表方法命名:get+业务名称+List
- 查询列表方法(分页)默认命名:pageList,如果同一组件内存在多个查询列表方法命名:page+业务名称+List
- 新增、修改、删除等操作以handle为前缀,例如handleAdd、handleUpdate、handleDelete等
- 初始化方法应该命名为:init
- 保存表单方法应命名为:submitForm
- 显隐状态命名应以:业务+Visible
- 待补充...
# 注释规范
- 每个独立的VUE文件开头都要进行注释,表明该文件的描述信息、作者、创建时间等
<!--
* @FileDescription: 该文件的描述信息
* @Author: 作者信息
* @Date: 文件创建时间
* @LastEditors: 最后更新作者
* @LastEditTime: 最后更新时间
-->
- VUE文件中method中的方法注释
/**
* @description: 方法描述
* @param {参数类型} 参数名称
* @param {参数类型} 参数名称
* @return 没有返回信息写 void / 有返回信息 {返回类型} 描述信息
*/
# 全局组件
- 当组件在多个场景下使用,组件放到components目录下并注册为全局组件
# 格式化
- 如果开发工具使用的是vscode,请在设置中进行如下配置
{
"editor.fontSize": 18,
"workbench.colorTheme": "Visual Studio Dark",
"update.mode": "manual",
"eslint.codeAction.showDocumentation": {
"enable": true
},
"eslint.execArgv": null,
"search.followSymlinks": false,
"editor.tabSize": 2, //配置eslint
"eslint.validate": [
"javascript", // 用eslint的规则检测js文件
"javascriptreact",
"vue",
"html"
], // 启用保存时自动修复eslint,默认只支持.js文件
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.codeActionsOnSave.rules": null
}
← javascript java →