Vue前端开发规范整理(推荐)


Posted in Javascript onApril 23, 2018

基于Vue官方风格指南整理

一、强制

1. 组件名为多个单词

组件名应该始终是多个单词的,根组件 App 除外。

正例:

export default {
 name: 'TodoItem',
 // ...
}
反例:
export default {
 name: 'Todo',
 // ...
}

2. 组件数据

组件的 data 必须是一个函数。

当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。

正例:

// In a .vue file
export default {
 data () {
 return {
 foo: 'bar'
 }
 }
}
// 在一个 Vue 的根实例上直接使用对象是可以的,
// 因为只存在一个这样的实例。
new Vue({
 data: {
 foo: 'bar'
 }
})

反例:

export default {
 data: {
 foo: 'bar'
 }
}

3. Prop定义

Prop 定义应该尽量详细。

在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。

正例:

props: {
 status: String
}
// 更好的做法!
props: {
 status: {
 type: String,
 required: true,
 validator: function (value) {
 return [
 'syncing',
 'synced',
 'version-conflict',
 'error'
 ].indexOf(value) !== -1
 }
 }
}

反例:

// 这样做只有开发原型系统时可以接受
props: ['status']

4. 为v-for设置键值

总是用 key 配合 v-for。

在组件上_总是_必须用 key 配合 v-for,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。

正例:

<ul>
 <li
 v-for="todo in todos"
 :key="todo.id"
 >
 {{ todo.text }}
 </li>
</ul>

反例:

<ul>
 <li v-for="todo in todos">
 {{ todo.text }}
 </li>
</ul>

5.避免 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 v-if="shouldShowUsers">
 <li
 v-for="user in users"
 :key="user.id"
 >
 {{ user.name }}
 </li>
</ul>

反例:

<ul>
 <li
 v-for="user in users"
 v-if="shouldShowUsers"
 :key="user.id"
 >
 {{ user.name }}
 </li>
</ul>

6. 为组件样式设置作用域

对于应用来说,顶级 App 组件和布局组件中的样式可以是全局的,但是其它所有组件都应该是有作用域的。

这条规则只和单文件组件有关。你不一定要使用 scoped 特性。设置作用域也可以通过 CSS Modules,那是一个基于 class 的类似 BEM 的策略,当然你也可以使用其它的库或约定。

不管怎样,对于组件库,我们应该更倾向于选用基于 class 的策略而不是 scoped 特性。 

这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。

正例:

<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>

反例:

<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` 特性 -->
<style scoped>
.button {
 border: none;
 border-radius: 2px;
}
.button-close {
 background-color: red;
}
</style>

二、强烈推荐(增强可读性)

1. 组件文件

只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。

正例:

components/
|- TodoList.vue
|- TodoItem.vue

反例:

V
ue.component('TodoList', {
 // ...
})
Vue.component('TodoItem', {
 // ...
})

2. 单文件组件文件的大小写

单文件组件的文件名应该要么始终是单词大写开头 (PascalCase)

正例:

components/
|- MyComponent.vue

反例:

components/
|- myComponent.vue
|- mycomponent.vue

3. 基础组件名

应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。

正例:

components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue

反例:

components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue

4. 单例组件名

只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。

这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。

正例:

components/
|- TheHeading.vue
|- TheSidebar.vue

反例:

components/
|- Heading.vue
|- MySidebar.vue

5. 紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件名作为前缀命名。

如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。

正例:

components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue

反例:

components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue

6. 组件名中的单词顺序

组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。

正例:

components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue

反例:

components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue

7. 模板中的组件名大小写

总是 PascalCase 的

正例:

<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>

反例:

<!-- 在单文件组件和字符串模板中 -->
<mycomponent/>
<!-- 在单文件组件和字符串模板中 -->
<myComponent/>

8. 完整单词的组件名

组件名应该倾向于完整单词而不是缩写。

正例:

components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue

反例:

components/
|- SdSettings.vue
|- UProfOpts.vue

9. 多个特性的元素

多个特性的元素应该分多行撰写,每个特性一行。

正例:

<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"/>

10. 模板中简单的表达式

组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。

正例:

<!-- 在模板中 -->
{{ normalizedFullName }}
// 复杂表达式已经移入一个计算属性
computed: {
 normalizedFullName: function () {
 return this.fullName.split(' ').map(function (word) {
 return word[0].toUpperCase() + word.slice(1)
 }).join(' ')
 }
}

反例:

{{
 fullName.split(' ').map(function (word) {
 return word[0].toUpperCase() + word.slice(1)
 }).join(' ')
}}

11. 简单的计算属性

正例:

computed: {
 basePrice: function () {
 return this.manufactureCost / (1 - this.profitMargin)
 },
 discount: function () {
 return this.basePrice * (this.discountPercent || 0)
 },
 finalPrice: function () {
 return this.basePrice - this.discount
 }
}

反例:

computed: {
 price: function () {
 var basePrice = this.manufactureCost / (1 - this.profitMargin)
 return (
 basePrice -
 basePrice * (this.discountPercent || 0)
 )
 }
}

12. 带引号的特性值

非空 HTML 特性值应该始终带引号 (单引号或双引号,选你 JS 里不用的那个)。
在 HTML 中不带空格的特性值是可以没有引号的,但这样做常常导致带空格的特征值被回避,导致其可读性变差。

正例:

<AppSidebar :style="{ width: sidebarWidth + 'px' }">

反例:

<AppSidebar :style={width:sidebarWidth+'px'}>

13. 指令缩写

都用指令缩写 (用 : 表示 v-bind: 和用 @ 表示 v-on:)

正例:

<input
 @input="onInput"
 @focus="onFocus"
>

反例:

<input
 v-bind:value="newTodoText"
 :placeholder="newTodoInstructions"
>

三、推荐

1. 单文件组件的顶级元素的顺序

单文件组件应该总是让<script>、<template> 和 <style> 标签的顺序保持一致。且 <style> 要放在最后,因为另外两个标签至少要有一个。

正例:

<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>

四、谨慎使用 (有潜在危险的模式)

1. 没有在 v-if/v-if-else/v-else 中使用 key

如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个 <div> 元素)。

正例:

<div
 v-if="error"
 key="search-status"
>
 错误:{{ error }}
</div>
<div
 v-else
 key="search-results"
>
 {{ results }}
</div>
反例:
<div v-if="error">
 错误:{{ error }}
</div>
<div v-else>
 {{ results }}
</div>

2. scoped 中的元素选择器

元素选择器应该避免在 scoped 中出现。

在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。

正例:

<template>
 <button class="btn btn-close">X</button>
</template>

<style scoped>
.btn-close {
 background-color: red;
}
</style>

反例:

<template>
 <button>X</button>
</template>

<style scoped>
button {
 background-color: red;
}
</style>

3. 隐性的父子组件通信

应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop。

正例:

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
 }
 },
 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>
 `
})

4. 非 Flux 的全局状态管理

应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。

正例:

// 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>

反例:

// 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
 })
 }
 }
})

附录

1. 推荐使用vs code进行前端编码,规定Tab大小为2个空格

vs code配置

{
 "editor.tabSize": 2,
 "workbench.startupEditor": "newUntitledFile",
 "workbench.iconTheme": "vscode-icons",
 // 以下为stylus配置
 "stylusSupremacy.insertColons": false, // 是否插入冒号
 "stylusSupremacy.insertSemicolons": false, // 是否插入分好
 "stylusSupremacy.insertBraces": false, // 是否插入大括号
 "stylusSupremacy.insertNewLineAroundImports": false, // import之后是否换行
 "stylusSupremacy.insertNewLineAroundBlocks": false, // 两个选择器中是否换行
 "vetur.format.defaultFormatter.html": "js-beautify-html",
 "eslint.autoFixOnSave": true,
 "eslint.validate": [
 "javascript",
 {
 "language": "html",
 "autoFix": true
 },
 {
 "language": "vue",
 "autoFix": true
 },
 "javascriptreact",
 "html",
 "vue"
 ],
 "eslint.options": { "plugins": ["html"] },
 "prettier.singleQuote": true,
 "prettier.semi": false,
 "javascript.format.insertSpaceBeforeFunctionParenthesis": false,
 "vetur.format.js.InsertSpaceBeforeFunctionParenthesis": false,
 "vetur.format.defaultFormatter.js": "prettier",
 // "prettier.eslintIntegration": true
}

vs code 插件

  • Auto Close Tag
  • Path Intellisense
  • Prettier
  • Vetur
  • vscode-icons

总结

以上所述是小编给大家介绍的Vue前端开发规范整理,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
浅谈setTimeout 与 setInterval
Jun 23 Javascript
使用CDN和AJAX加速WordPress中jQuery的加载
Dec 05 Javascript
Bootstrap自定义文件上传下载样式
May 26 Javascript
AngularJS中的拦截器实例详解
Apr 07 Javascript
详解Node.js项目APM监控之New Relic
May 12 Javascript
AngularJS中下拉框的高级用法示例
Oct 11 Javascript
十分钟带你快速了解React16新特性
Nov 10 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
Oct 16 jQuery
vue项目初始化到登录login页面的示例
Oct 31 Javascript
微信小程序实现图片压缩
Dec 03 Javascript
JS实现时间校验的代码
May 25 Javascript
vue3.0 上手体验
Sep 21 Javascript
Vue 中mixin 的用法详解
Apr 23 #Javascript
详解Vue2.0配置mint-ui踩过的那些坑
Apr 23 #Javascript
vue2.0 移动端实现下拉刷新和上拉加载更多的示例
Apr 23 #Javascript
详解vue 计算属性与方法跟侦听器区别(面试考点)
Apr 23 #Javascript
JavaScript变量声明var,let.const及区别浅析
Apr 23 #Javascript
Node.js应用设置安全的沙箱环境
Apr 23 #Javascript
vue-devtools的安装步骤
Apr 23 #Javascript
You might like
织梦模板标记简介
2007/03/11 PHP
新手菜鸟必读:session与cookie的区别
2013/08/22 PHP
根据ip调用新浪api获取城市名并转成拼音
2014/03/07 PHP
destoon供应信息title调用出公司名称的方法
2014/08/22 PHP
CodeIgniter辅助之第三方类库third_party用法分析
2016/01/20 PHP
javascript中[]和{}对象使用介绍
2013/03/20 Javascript
有关于eclipse配置spket需要注意的一些地方
2013/04/07 Javascript
jquery单击事件和双击事件冲突解决方案
2016/03/02 Javascript
JS采用绝对定位实现回到顶部效果完整实例
2016/06/20 Javascript
javascript表单控件实例讲解
2016/09/13 Javascript
Bootstrap表单控件使用方法详解
2017/01/11 Javascript
JS实现瀑布流布局
2017/10/21 Javascript
JS实现读取xml内容并输出到div中的方法示例
2018/04/19 Javascript
Vue配合iView实现省市二级联动的示例代码
2018/07/27 Javascript
Vue多组件仓库开发与发布详解
2019/02/28 Javascript
Vue快速实现通用表单验证的示例代码
2020/01/09 Javascript
Vue实现input宽度随文字长度自适应操作
2020/07/29 Javascript
WebStorm无法正确识别Vue3组合式API的解决方案
2021/02/18 Vue.js
python修改注册表终止360进程实例
2014/10/13 Python
在windows系统中实现python3安装lxml
2016/03/23 Python
安装python时MySQLdb报错的问题描述及解决方法
2018/03/20 Python
利用numpy和pandas处理csv文件中的时间方法
2018/04/19 Python
更改Python的pip install 默认安装依赖路径方法详解
2018/10/27 Python
python 标准差计算的实现(std)
2019/07/29 Python
K最近邻算法(KNN)---sklearn+python实现方式
2020/02/24 Python
python 合并多个excel中同名的sheet
2021/01/22 Python
利用canvas实现图片压缩的示例代码
2018/07/17 HTML / CSS
学习党章思想汇报
2014/01/07 职场文书
委托书样本
2014/04/02 职场文书
学校法制宣传月活动总结
2014/07/03 职场文书
安全责任书模板
2014/07/22 职场文书
个人作风建设心得体会
2014/10/22 职场文书
医院领导班子四风问题对照检查材料
2014/10/26 职场文书
2015年为民办实事工作总结
2015/05/26 职场文书
如何书写先进事迹材料?
2019/07/02 职场文书
IDEA2021.2配置docker如何将springboot项目打成镜像一键发布部署
2021/09/25 Java/Android