代码规范是一个非常重要的事情 ,很多企业都有自己的代码规范体系 ,
而在不同阶段体系 HTML 、CSS、JS 也有代码规范 !
那么到了后期框架和库阶段规范你知道吗 ?
今天为大家分享一组热门框架 VUE 的代码风格规范指南
一、命名规范
市面上常用的命名规范 :
- camelCase ( 小驼峰式命名法 -- 首字母小写 )
- PascalCase ( 大驼峰式命名法 -- 首字母大写 )
- kebab-case ( 短横线连接式 )
- Snake ( 下划线连接式 )
1.1、项目文件命名
1.1.1 项目名
全部采用小写方式,以 短横线 分隔 ,
例 : my-project-name web-gsp-pc
1.1.2 目录名
参照项目命名规则,有复数结构时,要采用复数命名法,
例 :docs、assets、components、directives、mixins、utils、views
my-project-name/
|- BuildScript // 流水线部署文件目录
|- docs // 项目的细化文档目录(可选)
|- nginx // 部署在容器上前端项目 nginx 代理文件目录
|- node_modules // 下载的依赖包
|- public // 静态页面目录
|- index.html // 项目入口
|- src // 源码目录
|- api // http 请求目录
|- assets // 静态资源目录,这里的资源会被wabpack构建
|- icon // icon 存放目录
|- img // 图片存放目录
|- js // 公共 js 文件目录
|- scss // 公共样式 scss 存放目录
|- frame.scss // 入口文件
|- global.scss // 公共样式
|- reset.scss // 重置样式
|- components // 组件
|- directives // 指令
|- mixins // 混入
|- plugins // 插件
|- router // 路由
|- routes // 详细的路由拆分目录(可选)
|- index.js
|- store // 全局状态管理
|- utils // 工具存放目录
|- request.js // 公共请求工具
|- views // 页面存放目录
|- App.vue // 根组件
|- main.js // 入口文件
|- tests // 测试用例
|- .browserslistrc// 浏览器兼容配置文件
|- .editorconfig // 编辑器配置文件
|- .eslintignore // eslint 忽略规则
|- .eslintrc.js // eslint 规则
|- .gitignore // git 忽略规则
|- babel.config.js // babel 规则
|- Dockerfile // Docker 部署文件
|- jest.config.js
|- package-lock.json
|- package.json // 依赖
|- README.md // 项目 README
|- vue.config.js // webpack 配置
1.1.3、图像文件名
全部采用 **小写 **方式,优先选择 单个单词 命名,
多个单词命名以 下划线 _ 分隔
banner_sina.gif
menu_aboutus.gif
menutitle_news.gif
logo_police.gif
logo_national.gif
pic_people.jpg
pic_TV.jpg
1.1.4、HTML 文件名
全部采用 **小写 **方式,优先选择 单个单词 命名,
多个单词命名以 下划线 _ 分隔
|- error_report.html
|- success_report.html
1.1.5、CSS 文件名
全部采用 **小写 **方式,优先选择 单个单词 命名,
多个单词命名以 短横线 - 分隔
|- normalize.less
|- base.less
|- date-picker.scss
|- input-number.scss
1.1.6、JavaScript 文件名
全部采用 **小写 **方式,优先选择 单个单词 命名,
多个单词命名以 短横线 - 分隔
|- index.js
|- plugin.js
|- util.js
|- date-util.js
|- account-model.js
|- collapse-transition.js
上述规则可以 快速记忆 为
“ 静态文件 下划线 _ ,编译文件 **短横线 - ** ”
1.2、Vue 组件命名
推荐观看文章 :
Vue项目组件注册命名规范_雨季mo浅忆的博客-CSDN博客
1.2.1、单文件组件命名
文件扩展名为 **.vue ** 的 single-file components ( 单文件组件 ),
单文件组件名应该始终是 ** 单词大写开头 **( PascalCase )
components/
MyComponent.vue
1.2.2、单例组件名
只拥有单个活跃实例的组件应该以 The 前缀命名,以示其 唯一性
这不意味着 组件 只可用于 一个单页面 ,而是 *每个页面 只使用一次。这些组件永远不接受任何 prop ,因为它们是为你的应用 定制 的 。如果你发现有必要添加 prop ,那就表明这实际上是 一个 可复用 的 组件 ,只是 目前 *在 每个页面 里只 使用一次 。
比如,头部 和 侧边栏 组件 几乎在每个页面都会使用 ,不接受 prop,该 组件 是 专门 为 该应用 所 定制 的 。
components/
|- TheHeading.vue
|- TheSidebar.vue
1.2.3、基础组件名
**基础组件 **:不包含业务 ,独立 、具体功能 的 基础组件 ,比如 **日期选择器 、模态框 **等 。 这类组件作为项目的 基础控件 ,会被 大量 使用 ,因此 组件 的 API 进行过 高强度 的 抽象 ,可以通过 不同配置 实现 不同 的 功能 。
应用 特定样式 和 约定 的 基础组件 ( 也就是 展示类 的 、无逻辑 的 或 无状态 、不掺杂 业务逻辑的 组件 ) 应该 全部 以一个 特定 的 前缀 开头 —— Base 。
基础组件 在 一个页面 内可 使用多次,在 不同页面 内也可 复用,是 高可复用 组件 。
components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
1.2.4、业务组件
**业务组件 :它不像 基础组件 只包含 某个 功能 ,而是在 业务中 被 多个页面 复用 的( 具有可复用性 ),它与 基础组件 的 区别是 ,业务组件 只在 当前项目 中会用到 ,不具有 通用性 ,而且会 包含 一些 业务 ,比如 数据请求 ;而 基础组件 不含 业务 ,在 任何项目中 都可以 使用 ,功能单一 **,比如 :一个 具有数据校验 功能 的 输入框 。
**掺杂了复杂业务的组件( 拥有自身 ****
data
、
prop
**** 的 相关处理 )即 业务组件 **
应该以 **
Custom
** 前缀 命名 。业务组件 在一个页面内,
比如:某个页面内有一个 卡片列表 ,而 样式 和 逻辑 跟 业务 紧密相关的卡片就是 业务组件。
components/
|- CustomCard.vue
1.2.5、紧密耦合的组件名
和 父组件 紧密耦合的 子组件 应该以 父组件名 作为 前缀 命名 。
因为编辑器通常会按 字母 顺序 组织文件 ,所以这样做可以把 相关联 的文件 排在一起。
components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
1.2.6、组件名中单词顺序
组件名 应该以 高级别的 ( 通常是一般化描述的 ) 单词 开头 ,以 描述性 的 修饰词 结尾 。
因为编辑器通常会按 字母顺序 组织文件,所以现在组件之间的 重要关系 一目了然 。
如下组件主要是用于 搜索 和 设置 功能 。
components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
还有另一种 多级目录 的方式,把所有的 搜索组件 放到 “ search ” 目录 ,
把所有的 设置组件 放到 “ settings ” 目录 。
我们只推荐在非常 大型 ( 如有 100 + 个 组件 ) 的 应用下才考虑这么做 ,
因为在多级目录间找来找去 ,要比在单个 components 目录下滚动查找要花费更多的精力 。
1.2.7、完整单词的组件名
组件名 应该倾向于 完整单词 而不是 缩写 。
编辑器中的自动补全已经让 书写 长命名 的代价非常之低了,
而其带来的 明确性 却是非常宝贵的。不常用的 缩写 尤其应该 避免 。
components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
1.3、代码参数命名
1.3.1、name
组件名应该始终是 多个单词 ,应该始终是 PascalCase 的,
根组件 App 以及 <transition>、<component> 之类的 Vue 内置组件除外,
这样做可以避免跟现有的以及未来的 HTML 元素相冲突,
因为所有的 HTML 元素名称都是单个单词的。
export default {
name: 'ToDoList',
// ...
}
1.3.2、prop
在声明 prop 的时候,其命名应该始终使用 camelCase,
而在模板和 JSX 中应该始终使用 kebab-case。
我们单纯的遵循每个语言的约定,在 JavaScript 中更自然的是 camelCase 。
而在 HTML 中则是 kebab-case。
1.3.3、router
Vue Router Path 命名采用 kebab-case 格式。
用 Snake( 如:
/user_info
)或
camelCase( 如:
/userInfo
) 的
单词会被当成 一个 单词 ,搜索引擎 无法 区分 语义 。
// bad
{
path: '/user_info', // user_info 当成一个单词
name: 'UserInfo',
component: UserInfo,
meta: {
title: ' - 用户',
desc: ''
}
},
// good
{
path: '/user-info', // 能解析成 user info
name: 'UserInfo',
component: UserInfo,
meta: {
title: ' - 用户',
desc: ''
}
},
1.3.4、模板中组件
对于绝大多数项目来说,在 单文件组件 和 字符串模板 中 组件名 应该总是 PascalCase 的 ,
但是在 DOM 模板中总是 kebab-case 的。
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在 DOM 模板中 -->
<my-component></my-component>
1.3.5、自闭合组件
在 单文件组件 、字符串模板 和 JSX 中 没有内容 的 组件 应该是 自闭合 的
—— 但在 DOM 模板里永远不要这样做 。
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在所有地方 -->
<my-component></my-component>
1.3.6、变量
- 命名方法:camelCase
- 命名规范:类型 + 对象描述或属性的方式
// bad
var getTitle = "LoginTable"
// good
let tableTitle = "LoginTable"
let mySchool = "我的学校"
1.3.7、常量
- 命名方法:全部 大写 下划线 _ 分割
- 命名规范:使用 大写字母 和 下划线 _ 来组合命名,下划线 用以 分割单词
const MAX_COUNT = 10
const URL = 'http://test.host.com'
1.3.8、方法
- 命名方法:camelCase
- 命名规范:统一使用 动词 或者 **动词 + 名词 **形式
// 1、普通情况下,使用动词 + 名词形式
// bad
go、nextPage、show、open、login
// good
jumpPage、openCarInfoDialog
// 2、请求数据方法,以 data 结尾
// bad
takeData、confirmData、getList、postForm
// good
getListData、postFormData
// 3、单个动词的情况
init、refresh
1.3.9、自定义事件
自定义事件 应始终使用 kebab-case 的 事件名 。
不同于组件和 prop ,事件名 不存在 任何 自动化 的 大小写 转换 。
而是触发的 事件名 需要 完全匹配 监听这个 事件 所用的 名称 。
不同于 组件 和 prop ,事件名 不会被用作一个 JavaScript 变量名 或 property 名 ,所以 就没有 理由 使用 camelCase 或 PascalCase 了 。
并且
v-on
事件监听器 在 DOM 模板中会被 自动转换 为全 小写 ( 因为 HTML 是 大小写 不敏感 的 ) , 所以
v-on: myEvent
将会变成
v-on: myevent
—— 导致
myEvent
不可能被监听到。
- 原生事件参考列表
由原生事件可以发现其使用方式如下:
<div
@blur="toggleHeaderFocus"
@focus="toggleHeaderFocus"
@click="toggleMenu"
@keydown.esc="handleKeydown"
@keydown.enter="handleKeydown"
@keydown.up.prevent="handleKeydown"
@keydown.down.prevent="handleKeydown"
@keydown.tab="handleKeydown"
@keydown.delete="handleKeydown"
@mouseenter="hasMouseHoverHead = true"
@mouseleave="hasMouseHoverHead = false">
</div>
而为了区分 *原生事件 *和 自定义事件 ,在 Vue 中的使用 ,
建议除了 多单词 事件名 使用 kebab-case 的情况下 ,命名还需遵守为 **
on
- 动词** 的形式 ,
如下 :
<!-- 父组件 -->
<div
@on-search="handleSearch"
@on-clear="handleClear"
@on-clickoutside="handleClickOutside">
</div>
// 子组件
export default {
methods: {
handleTriggerItem () {
this.$emit('on-clear')
}
}
}
1.3.10、事件方法
- 命名方法:camelCase
- 命名规范:handle + 名称(可选)**+ 动词**
<template>
<div
@click.native.stop="handleItemClick()"
@mouseenter.native.stop="handleItemHover()">
</div>
</template>
<script>
export default {
methods: {
handleItemClick () {
//...
},
handleItemHover () {
//...
}
}
}
</script>
二、代码规范
2.1、Vue
2.1.1、代码结构
<template>
<div id="my-component">
<DemoComponent />
</div>
</template>
<script>
import DemoComponent from '../components/DemoComponent'
export default {
name: 'MyComponent',
components: {
DemoComponent
},
mixins: [],
props: {},
data () {
return {}
},
computed: {},
watch: {}
created () {},
mounted () {},
destroyed () {},
methods: {},
}
</script>
<style lang="scss" scoped>
#my-component {
}
</style>
**2.1.2 data **
**组件的 ****
data
**** 必须是一个函数。**
// In a .vue file
export default {
data () {
return {
foo: 'bar'
}
}
}
2.1.3、prop
Prop 定义应该尽量详细。
export default {
props: {
status: {
type: String, // 规定接收的数据类型
required: true, // 规定数据为必传项
default: '', // 规定数据的默认值(有required时,此项可忽略)
validator: function (value) { // 自定义验证函数
return [
'syncing',
'synced',
'version-conflict',
'error'
].indexOf(value) !== -1
}
}
}
}
2.1.4、computed
应该把 复杂计算属性 分割为 尽可能多 的 更简单 的 属性 。
小的、专注的计算属性减少了信息使用时的假设性限制,所以需求变更时也用不着那么多重构了。
// bad
computed: {
price: function () {
var basePrice = this.manufactureCost / (1 - this.profitMargin)
return (
basePrice -
basePrice * (this.discountPercent || 0)
)
}
}
// good
computed: {
basePrice: function () {
return this.manufactureCost / (1 - this.profitMargin)
},
discount: function () {
return this.basePrice * (this.discountPercent || 0)
},
finalPrice: function () {
return this.basePrice - this.discount
}
}
**2.1.5、为
v-for
设置键值**
**在组件上必须用 ****
key
**** 搭配
v-for
**,以便维护 内部组件 及其 子树 的 状态 。
甚至在元素上维护可预测的行为 ,
比如 动画中的 对象固化 (object constancy)。
<ul>
<li
v-for="todo in todos"
:key="todo.id">
{{ todo.text }}
</li>
</ul>
**2.1.6、
v-if
和
v-for
互斥**
**永远不要把 ****
v-if
**** 和 ****
v-for
**** 同时用在同一个元素上。**
<!-- bad:控制台报错 -->
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id">
{{ user.name }}
</li>
</ul>
一般我们在两种常见的情况下会倾向于这样做:
为了过滤一个列表中的项目
( 比如
v-for="user in users" v-if="user.isActive"
) 。
在这种情形下,请将
users
替换为一个计算属性 ( 比如
activeUsers
) ,
让其 返回 过滤后 的 列表 。
computed: {
activeUsers: function () {
return this.users.filter((user) => {
return user.isActive
})
}
}
<ul>
<li
v-for="user in activeUsers"
:key="user.id">
{{ user.name }}
</li>
</ul>
- 为了避免渲染本应该 被隐藏 的 列表
- ( 比如
v-for="user in users" v-if="shouldShowUsers"
)。 - 这种情形下,请将
v-if
移动至容器元素上 ( 比如ul
,ol
) 。
<!-- bad -->
<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id">
{{ user.name }}
</li>
</ul>
<!-- good -->
<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id">
{{ user.name }}
</li>
</ul>
2.1.7、多个 attribute 的元素
多个 attribute 的元素应该分多行撰写,每个 attribute 一行。
<!-- bad -->
<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
<!-- good -->
<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo">
<MyComponent
foo="a"
bar="b"
baz="c"/>
2.1.8、模板中简单的表达式
组件模板 应该只包含 简单的表达式,复杂的表达式 则应该重构为 计算属性 或 方法。
复杂表达式会让你的模板变得不那么声明式。
我们应该尽量描述应该出现的 **是什么 **,而非 **如何 **计算那个值。
而且 计算属性 和 方法 使得代码可以 重用 。
// bad
{{
fullName.split(' ').map((word) => {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
更好地做法 :
2.1.9、带引号的 attribute 值
非空 HTML 特性值应该始终带双引号。
<!-- bad -->
<input type=text>
<AppSidebar :style={width:sidebarWidth+'px'}>
<!-- good -->
<input type="text">
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
2.1.10、指令缩写
- 用
:
表示v-bind:
- 用
@
表示v-on:
- 用
#
表示v-slot:
<input
:value="newTodoText"
:placeholder="newTodoInstructions">
<input
@input="onInput"
@focus="onFocus">
<template #header>
<h1>Here might be a page title</h1>
</template>
<template #footer>
<p>Here's some contact info</p>
</template>
2.2、HTML
2.2.1、文件模板
HTML5 文件模板:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>HTML5标准模版</title>
</head>
<body>
</body>
</html>
移动端:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no"
/>
<meta name="format-detection" content="telephone=no" />
<title>移动端HTML模版</title>
<!-- S DNS预解析 -->
<link rel="dns-prefetch" href="" />
<!-- E DNS预解析 -->
<!-- S 线上样式页面片,开发请直接取消注释引用 -->
<!-- #include virtual="" -->
<!-- E 线上样式页面片 -->
<!-- S 本地调试,根据开发模式选择调试方式,请开发删除 -->
<link rel="stylesheet" href="css/index.css" />
<!-- /本地调试方式 -->
<link rel="stylesheet" href="http://srcPath/index.css" />
<!-- /开发机调试方式 -->
<!-- E 本地调试 -->
</head>
<body>
</body>
</html>
PC 端:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="keywords" content="your keywords" />
<meta name="description" content="your description" />
<meta name="author" content="author,email address" />
<meta name="robots" content="index,follow" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />
<meta name="renderer" content="ie-stand" />
<title>PC端HTML模版</title>
<!-- S DNS预解析 -->
<link rel="dns-prefetch" href="" />
<!-- E DNS预解析 -->
<!-- S 线上样式页面片,开发请直接取消注释引用 -->
<!-- #include virtual="" -->
<!-- E 线上样式页面片 -->
<!-- S 本地调试,根据开发模式选择调试方式,请开发删除 -->
<link rel="stylesheet" href="css/index.css" />
<!-- /本地调试方式 -->
<link rel="stylesheet" href="http://srcPath/index.css" />
<!-- /开发机调试方式 -->
<!-- E 本地调试 -->
</head>
<body>
</body>
</html>
**2.2.2、元素及标签闭合 **
2.2.3、代码嵌套
2.3、CSS
2.3.1、样式文件
2.3.2、代码格式化
2.3.3、代码大小写
2.3.4、代码易读性
2.3.5、属性值引导
2.3.6、属性书写建议
2.3.7、CSS 浏览器私有前缀
2.4、JavaScript
2.4.1、单行代码块
2.4.2、大括号风格
2.4.3、代码中的风格
三、注释规范
3.1、HTML 文件注释
3.1.1、单行注释
3.1.2、模块注释
3.1.3、嵌套模块注释
3.2、CSS 文件注释
3.2.1、单行注释
3.2.2、模块注释
3.2.3、文件注释
3.3、JavaScript 文件注释
3.3.1、单行注释
3.3.2、多行注释
3.3.3、注释空格
3.3.4、特殊标记
3.3.5、文档类注释
3.3.6、注释工具
四、其它
- 缩进换行请使用两个空格。
- 大型团队多人协作项目推荐 JavaScript 代码末尾加分号。
- 小型个人创新练手项目可尝试使用 JavaScript 代码末尾不加分号的风格,更加清爽简练。
未完待续。。。
版权归原作者 雨季mo浅忆 所有, 如有侵权,请联系我们删除。