前端代码编写规范
一个好的程序员肯定是要能书写可维护的代码,而不是一次性的代码,怎么能让团队当中其他人甚至一段时间时候你再看你某个时候写的代码也能看懂呢,这就需要规范你的代码了。
然而通过搜索引擎搜索到的开发文档都不太全,于是我抽空整理了一套相对比较全的代码规范。本文档持续更新,可添加收藏长期使用。
HTML 规范
代码规范
DOCTYPE 声明
一个DOCTYPE必须包含以下部分,并严格按照顺序出现:
- 一个ASCII字符串 “<!DOCTYPE” ,大小写不敏感
- 一个或多个空白字符
- 一个ASCII字符串”html”,大小写不敏感
- 一个可选的历史遗留的DOCTYPE字符串 (DOCTYPE legacy string),或者一个可选的已过时但被允许的DOCTYPE字符串 (obsolete permitted DOCTYPE string) 字符串
- 一个或多个空白字符
- 一个编码为 U+003E 的字符 “>”
HTML文件必须加上 DOCTYPE 声明,并统一使用 HTML5 的文档声明:
1 |
页面语言LANG
推荐使用属性值 cmn-Hans-CN(简体, 中国大陆),但是考虑浏览器和操作系统的兼容性,目前仍然使用 zh-CN 属性值
1 | <html lang="zh-CN"> |
更多地区语言参考:
1 | zh-SG 中文 (简体, 新加坡) 对应 cmn-Hans-SG 普通话 (简体, 新加坡) |
CHARSET
因为 ISO-8859 中字符集大小是有限的,且在多语言环境中不兼容,所以 Unicode 联盟开发了 Unicode 标准。
Unicode 标准覆盖了(几乎)所有的字符、标点符号和符号。
Unicode 使文本的处理、存储和运输,独立于平台和语言。
HTML-5 中默认的字符编码是 UTF-8
一般情况下统一使用 “UTF-8” 编码
1 | <meta charset="UTF-8"> |
由于历史原因,有些业务可能会使用 “GBK” 编码
1 | <meta charset="GBK"> |
请尽量统一写成标准的 “UTF-8”,不要写成 “utf-8” 或 “utf8” 或 “UTF8”。根据 IETF对UTF-8的定义,其编码标准的写法是 “UTF-8”;而 UTF8 或 utf8 的写法只是出现在某些编程系统中,如 .NET framework 的类 System.Text.Encoding 中的一个属性名就叫 UTF8。
元素及标签闭合
HTML元素共有以下5种:
- 空元素:area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr
- 原始文本元素:script、style
- RCDATA元素:textarea、title
- 外来元素:来自MathML命名空间和SVG命名空间的元素。
- 常规元素:其他HTML允许的元素都称为常规元素。
元素标签的闭合应遵循以下原则:
- 原始文本元素、RCDATA元素以及常规元素都有一个开始标签来表示开始,一个结束标签来表示结束。
- 某些元素的开始和结束标签是可以省略的,如果规定标签不能被省略,那么就绝对不能省略它。
- 空元素只有一个开始标签,且不能为空元素设置结束标签。
- 外来元素可以有一个开始标签和配对的结束标签,或者只有一个自闭合的开始标签,且后者情况下该元素不能有结束标签。
为了能让浏览器更好的解析代码以及能让代码具有更好的可读性,有如下约定:
- 所有具有开始标签和结束标签的元素都要写上起止标签,某些允许省略开始标签或和束标签的元素亦都要写上。
- 空元素标签都不加 “/” 字符
推荐:
1 | <div> |
不推荐:
1 | <div> |
书写风格
HTML代码大小写
HTML标签名、类名、标签属性和大部分属性值统一用小写
推荐:
1 | <div class="demo"></div> |
不推荐:
1 | <div class="DEMO"></div> |
HTML文本、CDATA、JavaScript、meta标签某些属性等内容可大小写混合
1 | <!-- 优先使用 IE 最新版本和 Chrome Frame --> |
类型属性
不需要为 CSS、JS 指定类型属性,HTML5 中默认已包含
推荐:
1 | <link rel="stylesheet" href="" > |
不推荐:
1 | <link rel="stylesheet" type="text/css" href="" > |
元素属性
- 元素属性值使用双引号语法
- 元素属性值可以写上的都写上
推荐:
1 | <input type="text"> |
不推荐:
1 | <input type=text> |
特殊字符引用
文本可以和字符引用混合出现。这种方法可以用来转义在文本中不能合法出现的字符。
在 HTML 中不能使用小于号 “<” 和大于号 “>”特殊字符,浏览器会将它们作为标签解析,若要正确显示,在 HTML 源代码中使用字符实体
1 | <!-- 推荐 --> |
代码缩进
统一使用两个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)
1 | <div class="jdc"> |
纯数字输入框
使用 type="tel" 而不是 type="number"
1 | <input type="tel"> |
代码嵌套
元素嵌套规范,每个块状元素独立一行,内联元素可选
推荐:
1 | <div> |
不推荐:
1 | <div> |
段落元素与标题元素只能嵌套内联元素
推荐:
1 | <h1><span></span></h1> |
不推荐:
1 | <h1><div></div></h1> |
注释规范
HTML注释规范写法应该遵循以下标准:
- 必须以4个有序字符开始:编码为 U+003C LESS-THAN SIGN 的小于号, 编码为 U+0021 EXCLAMATION MARK 的感叹号, 编码为 U+002D HYPHEN-MINUS 横线, 编码为 U+002D HYPHEN-MINUS横线 ,即 “<!–”
- 在此之后是注释内容,注释的内容有以下限制:
- 不能以单个 “>” (U+003E) 字符开始
- 不能以由 “-“(U+002D HYPHEN-MINUS)和 ”>” (U+003E) 组合的字符开始,即 “->”
- 不能包含两个连续的 U+002D HYPHEN-MINUS 字符,即 “–”
- 不能以一个 U+002D HYPHEN-MINUS 字符结束,即 “-”
- 必须以3个有序字符结束:U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN,即 “–>”
标准写法:
1 | <!--Comment Text--> |
错误的写法:
1 | <!-->The Wrong Comment Text--> |
单行注释
一般用于简单的描述,如某些状态描述、属性描述等
注释内容前后各一个空格字符,注释位于要注释代码的上面,单独占一行
推荐:
1 | <!-- Comment Text --> |
不推荐:
1 | <div>...</div><!-- Comment Text --> |
模块注释
一般用于描述模块的名称以及模块开始与结束的位置
注释内容前后各一个空格字符,<!-- S Comment Text --> 表示模块开始,<!-- E Comment Text --> 表示模块结束,模块与模块之间相隔一行
推荐写法:
1 | <!-- S Comment Text A --> |
不推荐写法:
1 | <!-- S Comment Text A --> |
嵌套模块注释
当模块注释内再出现模块注释的时候,为了突出主要模块,嵌套模块不再使用
1 | <!-- S Comment Text --> |
而改用
1 | <!-- /Comment Text --> |
注释写在模块结尾标签底部,单独一行。
1 | <!-- S Comment Text A --> |
文件模版
HTML模版指的是团队使用的初始化HTML文件,里面会根据不同平台而采用不一样的设置,一般主要不同的设置就是 mata 标签的设置,以下是 PC 和移动端的 HTML 模版。
HTML5标准模版
1 |
|
移动端
1 |
|
PC端
1 |
|
WebApp Meta 标签设置(iOS)
WebApp目的在于使其界面和行为在某种程度上类似于原生APP应用。例如,WebApp 可以在 iOS 设备上通过缩放去适配设备屏幕。当用户将WebApp程序添加到主屏幕后,会使得它看上去像原生APP一样,以此,你可以进一步为 Safari 定制自己的 WebApp,而使用某些专为 iOS 平台设定的设置就可以做到。
WebApp可以通过设置 meta 标签来改变页面的一些表现,有些 meta 设置在 Safari 应用或原生 App 的内嵌网页中都可以生效,而有些设置侧需要将应用添加到主屏幕的时候才会生效。
Viewport Meta Tag
通用类设置
1 | <meta name="viewport" content="width=device-width, initial-scale=1.0, |
- width – viewport的宽度
- height – viewport的高度
- initial-scale – 初始的缩放比例
- minimum-scale – 允许用户缩放到的最小比例
- maximum-scale – 允许用户缩放到的最大比例
- user-scalable – 是否允许用户缩放
Safari on iOS viewport
- 默认宽度是 980px,范围从 200px 到 10000px
- initial-scale 缩放比例范围值是 从 >0 到 10 之间
- minimum-scale 默认值是 0.25
- maximum-scale 默认值是 5
- user-scalable – 默认值是 yes,设置 no 还可以在文本框输入文本的时候阻止页面滚动
Apple-Specific Meta Tag Keys
apple-mobile-web-app-capable
设置 WebApp 是否进入全屏模式,该设置需要添加到主屏幕才生效
1 | <meta name="apple-mobile-web-app-capable" content="yes"> |
- content设置 yes 进入全屏模式
- 默认会启动 Safari 应用,使用 Safari 应用浏览
- 通过检测 window.navigator.standalone 的 Boolean 值可以判断 web 应用是否处于全屏模式
apple-mobile-web-app-status-bar-style
为 webapp 设置状态栏样式
1 | <meta name="apple-mobile-web-app-status-bar-style" content="black"> |
- 此 meta 设置只在全屏模式生效
- 默认值是 default
- content=”black”,状态栏背景黑色,网页内容在状态栏下面
- content=”black-translucent”,状态栏半透明,背景黑色,网页内容占满全屏
format-detection
自动识别页面中有可能是电话格式的数字
1 | <meta name="format-detection" content="telephone=no"> |
iOS中的 Safari 会默认识别与电话格式相似的数字并生成一个可以拉起电话应用并将该数字作为电话号码拨打的链接。定义 telephone=no 可以屏蔽该功能
图片规范
图片格式
常见的图片格式有 GIF、PNG8、PNG24、JPEG、WEBP,根据图片格式的特性和场景需要选取适合的图片格式。
内容图
内容图多以商品图等照片类图片形式存在,颜色较为丰富,文件体积较大
- 优先考虑 JPEG 格式,条件允许的话优先考虑 WebP 格式
- 尽量不使用PNG格式,PNG8 色位太低,PNG24 压缩率低,文件体积大
背景图
背景图多为图标等颜色比较简单、文件体积不大、起修饰作用的图片
- PNG 与 GIF 格式,优先考虑使用 PNG 格式,PNG格式允许更多的颜色并提供更好的压缩率
- 图像颜色比较简单的,如纯色块线条图标,优先考虑使用 PNG8 格式,避免不使用 JPEG 格式
- 图像颜色丰富而且图片文件不太大的(40KB 以下)或有半透明效果的优先考虑 PNG24 格式
- 图像颜色丰富而且文件比较大的(40KB - 200KB)优先考虑 JPEG 格式
- 条件允许的,优先考虑 WebP 代替 PNG 和 JPEG 格式
图片大小
PC平台单张的图片的大小不应大于 200KB。
移动平台单张的图片的大小不应大于 100KB。
图片质量
- 上线的图片都应该经过压缩处理,压缩后的图片不应该出现肉眼可感知的失真区域
- 60质量的JPEG格式图片与质量大于60的相比,肉眼已看不出明显的区别,因此保存 JPEG 图的时候,质量一般控制在60,若保真度要求高的图片可适量提高到 80,图片大小控制在 200KB 以内
图片引入
测试内容图应该写上表明图片尺寸的占位图,可以用线上占位图生成服务,如:
1 | http://via.placeholder.com/300x300.png |
HTML 中图片引入不需添加 width、height 属性,alt 属性应该写上
1 | <!-- 推荐 --> |
CSS 中图片引入不需要引号
1 | .jdc { |
CSS Sprites 使用建议
- 适合使用频率高更新频率低的小图标
- 尽量不留太多的空白
- 体积较大的图片不合并
- 确保要合并的小图坐标数值和合并后的 Sprites 图尺寸均为偶数
Data URIs(base64编码)使用建议
- 适合更新频率高的小图片,如某些具备自定义功能的标题icon等
- 转换成 Base64 编码的图片应小于 2KB
- 移动端不使用 Base64 编码
- 要兼容 IE6/IE7 的不使用
CSS 规范
代码规范
编码规范
- 样式文件必须写上
@charset规则,并且一定要在样式文件的第一行首个字符位置开始写,编码名用“UTF-8” - 字符
@charset “”; 都用小写字母,不能出现转义符,编码名允许大小混写 - 考虑到在使用
“UTF-8”编码情况下 BOM 对代码的污染和编码显示的问题,在可控范围下,坚决不使用 BOM。
推荐:
1 | @charset "UTF-8"; |
不推荐:
1 | /** |
代码风格
代码格式化
样式书写一般有两种:一种是紧凑格式 (Compact)
1 | .jdc{ display: block;width: 50px;} |
一种是展开格式(Expanded)
1 | .jdc { |
建议统一使用展开格式书写样式
代码大小写
样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。
1 | /* 推荐 */ |
选择器
- 尽量少用通用选择器
* - 不使用 ID 选择器
- 不使用无具体语义定义的标签选择器
1 | /* 推荐 */ |
代码缩进
统一使用两个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)
1 | .jdc { |
分号
每个属性声明末尾都要加分号;
1 | .jdc { |
代码易读性
左括号与类名之间一个空格,冒号与属性值之间一个空格
1 | /* 推荐 */ |
逗号分隔的取值,逗号之后一个空格
:
1 | /* 推荐 */ |
为单个css选择器或新申明开启新行
推荐:
1 | .jdc, |
不推荐:
1 | .jdc,jdc_logo,.jdc_hd { |
颜色值 rgb() rgba() hsl() hsla() rect() 中不需有空格,且取值不要带有不必要的 0
1 | /* 推荐 */ |
属性值十六进制数值能用简写的尽量用简写
1 | /* 推荐 */ |
不要为 0 指明单位
1 | /* 推荐 */ |
属性值引号
css属性值需要用到引号时,统一使用单引号
1 | /* 推荐 */ |
属性书写顺序
建议遵循以下顺序:
- 布局定位属性:display / position / float / clear / visibility / overflow
- 自身属性:width / height / margin / padding / border / background
- 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word
- 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background:linear-gradient …
1 | .jdc { |
CSS3浏览器私有前缀写法
CSS3 浏览器私有前缀在前,标准前缀在后
1 | .jdc { |
注释规范
- 注释以字符
/*开始,以字符*/结束 - 注释不能嵌套
1 | /*Comment Text*/ |
单行注释
注释内容第一个字符和最后一个字符都是一个空格字符,单独占一行,行与行之间相隔一行
推荐:
1 | /* Comment Text */ |
不推荐:
1 | /*Comment Text*/ |
模块注释
注释内容第一个字符和最后一个字符都是一个空格字符,/* 与 模块信息描述占一行,多个横线分隔符-与*/占一行,行与行之间相隔两行
推荐:
1 | /* Module A |
不推荐:
1 | /* Module A ---------------------------------------------------- */ |
文件信息注释
在样式文件编码声明 @charset 语句下面注明页面名称、作者、创建日期等信息
1 | @charset "UTF-8"; |
SASS规范
语法选用
考虑到 SCSS 语法对 CSS 语法友好的兼容性和扩展性,我们在使用 SASS 编写样式的时候,统一使用 SCSS 语法
编码格式
严格遵守上面 “CSS规范” 中的 “编码规范”
SASS注释规范
SCSS 文件内
- 全部遵循 CSS 注释规范
- 不使用
/*! */注释方式 - 注释内不放 SASS 变量
标准的注释规范如下:
1 | @charset "UTF-8"; |
嵌套规范
选择器嵌套
1 | /* CSS */ |
属性嵌套
1 | /* CSS */ |
变量
可复用属性尽量抽离为页面变量,易于统一维护
1 | // CSS |
混合(mixin)
根据功能定义模块,然后在需要使用的地方通过 @include 调用,避免编码时重复输入代码段
1 | // CSS |
占位选择器 %
如果不调用则不会有任何多余的 css 文件,占位选择器以 % 标识定义,通过 @extend 调用
1 | //scss |
extend 继承
1 | // CSS |
for 循环
1 | // CSS |
注意:#{} 是连接符,变量连接使用时需要依赖
each 循环
1 | // CSS |
function 函数
1 | @function pxToRem($px) { |
运算规范
运算符之间空出一个空格
1 | .jdc { |
注意运算单位,单位同时参与运算,所以 10px 不等于 10,乘除运算时需要特别注意
1 | // 正确的运算格式 |
重置样式
移动端
1 | * { -webkit-tap-highlight-color: transparent; outline: 0; margin: 0; padding: 0; vertical-align: baseline; } |
PC端
1 | html, body, div, h1, h2, h3, h4, h5, h6, p, dl, dt, dd, ol, ul, li, fieldset, form, label, input, legend, table, caption, tbody, tfoot, thead, tr, th, td, textarea, article, aside, audio, canvas, figure, footer, header, mark, menu, nav, section, time, video { margin: 0; padding: 0; } |
媒体查询
常用查询语句
判断设备横竖屏
1 | /* 横屏 */ |
判断设备宽高
1 | /* 设备宽度大于 320px 小于 640px */ |
判断设备像素比
1 | /* 设备像素比为 1 */ |
常用设备设置
iPhones
1 | /* ----------- iPhone 4 and 4S ----------- */ |
Galaxy Phones
1 | /* ----------- Galaxy S3 ----------- */ |
HTC Phones
1 | /* ----------- HTC One ----------- */ |
iPads
1 | /* ----------- iPad mini ----------- */ |
移动端常用私有属性
-webkit-scrollbar
-webkit-scrollbar 是 -webkit-私有的伪元素,用于对拥有overflow属性的区域 自定义滚动条的样式。
譬如,为了隐藏滚动条,你可以这么做:
1 | .scroll::-webkit-scrollbar { |
除了对整个滚动条的控制外,Webkit还提供了控制对滚动条各组成部分的表现渲染的伪元素,甚至具体到滚动条的各种状态行为的伪类。
滚动条各块组成表现渲染的伪元素
一般而言,滚动条的主要组成部分包括:
- 滚动按钮 — 滚动按钮的夹角则被称为滚动角(corner)。
- 轨道 — 轨道(track)可以进一步分为轨枕(track pieces) 和滑块(thumb)。
Webkit则根据滚动条各组成部分,提供了不同的伪元素来自定义样式。
1 | ::-webkit-scrollbar { /* 1 */ } |
以下则是各伪元素对应的滚动条各部分:
::-webkit-scrollbar:滚动条整体部分。可设置width、height、background、border等。
::-webkit-scrollbar-button:滚动条两端的按钮。可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果。
::-webkit-scrollbar-track:轨道。可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果。
::-webkit-scrollbar-track-piece:轨枕,也就是除去滚动滑块的部分。
::-webkit-scrollbar-thumb:滚动滑块,也就是滚动条里面可以拖动的那部分。
::-webkit-scrollbar-corner:滚动按钮的夹角则被称为滚动角。
::-webkit-resizer:用于定义右下角拖动块的样式。
需要注意的是:若是水平滚动条,则width属性不起作用,height属性用来控制滚动条相应部分竖直方向高度;若是竖直滚动条,则height属性不起作用,width属性用来控制相应部分的宽度。
滚动条各块组成的伪元素
下面的伪类可以应用到上面的伪元素中。:horizontal:选择水平方向的滚动条。
:vertical:选择垂直方向的滚动条。
:decrement:适用于滚动按钮和轨枕。选择能够使得视窗位置递减状态(例如,垂直滚动条向上滚动,水平滚动条向左滚动。)的滚动按钮或轨枕。
:increment:适用于滚动按钮和轨枕。选择能够使得视窗位置递增状态(例如,垂直滚动条向下滚动,水平滚动条向右滚动。)的滚动按钮或轨枕。
:start:适用于滚动按钮和轨枕。选择位于滚动滑块前边的滚动按钮和轨枕。
:end:适用于滚动按钮和轨枕。选择位于滚动滑块后边的滚动按钮和轨枕。
:double-button:适用于滚动按钮和轨枕。选中紧挨着一对按钮的轨枕以及位于滚动条某一端的一对按钮中的其中一个滚动按钮。
:single-button:适用于滚动按钮和轨枕。选中紧挨着仅一个按钮的轨枕以及位于滚动条某一端的仅它本身一个的滚动按钮。
:no-button:适用于轨枕。选中轨道结束位置没有按钮的轨枕。
:corner-present:适用于选中滚动角不存在的滚动条。
:window-inactive:适用于所有滚动条,选中焦点不在该视窗的滚动区域。
另外,:enabled、:disabled、:hover、和:active等伪类同样在滚动条中适用。
为了更好地理解,以下是几个伪元素组合伪类的应用例子:
1 | ::-webkit-scrollbar-track-piece:start { |
-webkit-touch-callout
-webkit-touch-callout 是一个不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。
当你触摸并按住触摸目标时候,禁止或显示系统默认菜单。在iOS上,当你触摸并按住触摸的目标,比如一个链接,Safari浏览器将显示链接有关的系统默认菜单,这个属性可以让你禁用系统默认菜单。
属性值
none:系统默认菜单被禁用inherit:系统默认菜单不被禁用
兼容性
- iOS 2.0及更高版本的 Safari 浏览器可用
- Android 尚不明确
-webkit-tap-highlight-color
-webkit-tap-highlight-color 是一个不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。
在 iOS Safari 上,当用户点击链接或具有 JavaScript 可点击脚本的元素,系统会为这些被点击元素加上一个默认的透明色值,该属性可以覆盖该透明值。
属性值
<color>:颜色值
兼容性
- iOS 1.1.1及更高版本的Safari浏览器可用
- 大部分安卓手机
-webkit-overflow-scrolling
定义在具 overflow:scroll 属性的元素内是否采用原生样式滚动行为
属性值
auto:默认值,单手滚动,滚动没有惯性效果touch:原生样式滚动,应用此属性值会产生层叠上下文(会影响定位参照物的属性,类似opacity、masks、transforms属性,影响到position的效果,甚至影响到position:fixed的定位参照物,)
兼容性
- iOS 5.0 及更高版本
- 大部分安卓机
-webkit-line-clamp
-webkit-line-clamp 是一个不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。
限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他外来的WebKit属性。
常见结合属性:
display: -webkit-box:必须结合的属性,将对象作为弹性伸缩盒子模型显示。-webkit-box-orient:必须结合的属性,设置或检索伸缩盒对象的子元素的排列方式。text-overflow:可以用来多行文本的情况下,用省略号“…”隐藏超出范围的文本。
属性值
<number>:块元素显示的文本的行数
兼容性
- iOS
- Andriod
-webkit-appearance
-webkit-appearance 是一个不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。
改变按钮和其他控件的外观,使其类似于原生控件。
属性值
none:去除系统默认 appearance 的样式,常用于 iOS 下移除原生样式button:渲染成 button 的风格checkbox:渲染成 input checkbox 样式的复选框按钮radio:渲染成 radio 的风格
兼容性
- iOS 2.0及更高版本的Safari浏览器可用
- Android 尚不明确
-webkit-font-smoothing
字体平滑,该属性定义文本的平滑属性,但要注意以下说明:
非标准属性,不建议用于网页上,这个属性不能保证所有用户都能看到相同效果,这会使网站的字体渲染造成不一致,而此属性的渲染行为日后也有可能会改变
属性值
none:去掉字体平滑效果,使字体带锯齿antialiased:使字体在像素级别更平滑更轻细subpixel-antialiased:在多数非 Retina 显示设备中字体将会更锐利。
注意:以上属性在 Retina 设备上会有明显的效果,在非 Retina 设备上看不出差异
兼容性
- 部分高清设备,如 Retina Mac
-webkit-backface-visibility
backface-visibility 在 W3文档 有定义描述
定义转换元素的背面是否显示
属性值
visible:显示(默认值)hidden:隐藏
兼容性
- iOS 2.0 及更高版本的 Safari 浏览器可用
- 大部分 Android
-webkit-mask
定义多样的蒙板效果属性(缩写属性,类似 margin)
使用语法
1 | <mask-image> [<mask-repeat> || <mask-attachment> || <mask-position> || <mask-origin> || <mask-clip> || <mask-composite>]* |
默认值:
1 | -webkit-mask: none repeat scroll 0% 0% padding border add; |
属性值
<mask-image>:为元素设置蒙板图片,蒙板图片会根据图片的透明区域对元素可视部分进行裁剪<uri>:图片链接作为蒙板图片<gradient>:渐变函数-webkit-gradient作为蒙板图片none:去掉蒙板图片
<mask-repeat>:定义蒙板图片是否平铺或平铺的方式repeat:默认值,水平和垂直方向平铺repeat-x:水平方向平铺repeat-y:垂直方向平铺no-repeat:不平铺
<mask-attachment>:如果-webkit-mask-image属性有设置,attachment决定该图片是否相对视窗固定或随着其容器滚动scroll:默认值,随容器滚动fixed:相地视窗固定
<mask-position>:定义蒙板图片的初始位置,书写格式类似background-position—-<mask-position>[, <mask-position>]*<percentage><length>leftrightcenter
<mask-origin>:定义蒙板图片定位相对起点,与webkit-mask-position属性相关。当-webkit-mask-attachment:fixed的时候,该属性不生效。padding:默认值,蒙板定位相对边距border:蒙板定位相对边框content:蒙板定位相对元素盒子内容
<mask-clip>:如果-webkit-mask-image属性有设置,-webkit-mask-clip将定义蒙板图片的裁剪区域border:默认值,蒙板图片延伸到容器的边框padding:蒙板图片延伸到容器的边距content:蒙板图片裁剪到元素盒子内容范围text:蒙板图片裁剪到元素文本范围
<mask-composite>:定义蒙板图片重合的裁剪显示方式add:默认值,图片重合不裁剪subtract:去掉层级低的图形以及图片重合部分图形,只留层级高非重合部分图形intersect:只留重合部分图形exclude:只去掉重合部分图形
兼容性
- Safari 4.0 及更高版本
- iOS 4.0 及更高版本
- Android 2.1 及更高版本
-webkit-user-select
定义用户是否能选中元素内容
属性值
auto:可选中元素内容none:不能选中任何内容text:可选中元素内的文本
兼容性
- iOS 3.0 及更高版本的 Safari
- 大部分安卓手机
-webkit-user-modify
定义用户是否可编辑元素内容
属性值
read-only:只读read-write:可读可写,粘贴内容会保留富文本格式( Android 机不保留富文本格式 )read-write-plaintext-only:可读可写,粘贴内容所有富文本格式都会丢失
注意:使用这个属性的时候,请不要出现 -webkit-user-select: none,文本无法选中的情况下,在 Safari 该属性不生效,不过在 Chrome 依然生效
兼容性
- iOS 5.0 及更高版本
- Safari 3.0 及更高版本
- 大部分安卓手机
-webkit-text-stroke
定义文本描边,可以设计描边的宽和颜色,一般与文本填充属性 -webkit-text-fill-color 共用。
属性值
<length>:长度单位<color>:颜色值
兼容性
- iOS 2.0 及更高版本
- Safari 3.0 及更高版本
- 安卓尚不明确
-webkit-text-fill-color
定义文本填充,一般与文本描边属性 -webkit-text-stroke 共用。
属性值
<color>:颜色值currentcolor:元素color属性值-webkit-activelink:链接被点击时系统的默认颜色
兼容性
- iOS 2.0 及更高版本
- Safari 3.0 及更高版本
- 安卓尚不明确
-webkit-text-size-adjust
定义 iOS Safari 网页文本大小调整属性
属性值
<percentage>:百分比值,字体显示调整值auto:字体自动调整none:字体不能自动调整
兼容性
- iOS 1.0 及更高版本
- Safari on iOS only
- 安卓尚不明确
-webkit-marquee
定义滚动文本内容属性(缩写属性,类似margin)。
使用语法
1 | -webkit-marquee: direction increment repetition style speed |
属性值
<direction>:滚动方向ahead:从下到上滚动auto:默认滚动方向backwards:从右到左滚动down:从上到下滚动forwards:从左到右滚动left:从右到左滚动reverse:从上到下滚动right:从左到右滚动up:从下到上滚动
<increment>:每次移动的距离[<percentage> | <length>]large:距离常量medium:距离常量small:距离常量
<repetition>:文字滚动的重复次数- 非负整数
infinite:无限次
<style>:文字滚动的方式alternate:重复滚动none:停止滚动scroll:在定义方向上滚动slide:定义方向上滚动,内容显示完毕或者内容滚动到滚动区域另一端边框时候都会停止下来
<speed>:滚动或滑动的速度- 非负整数(毫秒单位)或带时间单位的非负整数
fastnormalslow
兼容性
- iOS 1.0 及更高版本
- Safari 3.0 及更高版本
- 大部分安卓手机
-webkit-filter
滤镜属性可以让元素本身内容(文本、背景等)及其子元素加上滤镜效果
属性值
blur(<length>):模糊,原始效果值为0px,不接受负值brightness([ <number> | <percentage> ]):亮度,原始效果值为1或100%,不接受负值contrast([ <number> | <percentage> ]):对比度,原始效果值为1或100%,不接受负值drop-shadow( <length>{2,4} <color>?):投影,原始效果值为所有长度值为0,长度值至少2个,最多4个,grayscale([ <number> | <percentage> ] ):灰度,原始效果值为0,最大值为1或100%,不接受负值hue-rotate( <angle>):相位,原始效果值为0deginvert( [ <number> | <percentage> ]):反相,原始效果值为0,最大值为1或100%,不接受负值opacity([ <number> | <percentage> ] ):透明度,原始效果值为1,最大值为1或100%,不接受负值saturate([ <number> | <percentage> ]):饱和度,原始效果值为1,不接受负值sepia([ <number> | <percentage> ]):乌贼墨,原始效果值为0,最大值为1或100%,不接受负值
兼容性
- iOS 8.0 及更高版本
- Safari 8.0 及更高版本
- Android 4.4 及更高版本
-webkit-backdrop-filter
背景滤镜属性可以让元素的背景或元素层级以下的元素加上滤镜效果
属性值
blur(<length>):模糊,原始效果值为0,不接受负值brightness([ <number> | <percentage> ]):亮度,原始效果值为1或100%,不接受负值contrast([ <number> | <percentage> ]):对比度,原始效果值为1或100%,不接受负值drop-shadow( <length>{2,3} <color>?):投影,原始效果值为所有长度值为0,长度值至少2个,最多3个,注意:不支持投影扩展值和混合投影grayscale([ <number> | <percentage> ] ):灰度,原始效果值为0,最大值为1或100%,不接受负值hue-rotate( <angle>):相位,原始效果值为0deginvert( [ <number> | <percentage> ]):反相,原始效果值为0,最大值为1或100%,不接受负值opacity([ <number> | <percentage> ] ):透明度,原始效果值为1,最大值为1或100%,不接受负值saturate([ <number> | <percentage> ]):饱和度,原始效果值为1,不接受负值sepia([ <number> | <percentage> ]):乌贼墨,原始效果值为0,最大值为1或100%,不接受负值
兼容性
- iOS 9.0 及更高版本
- Safari 9.0 及更高版本
- 安卓尚未明确
position:-webkit-sticky
可以使得元素在页面没有滚动的情况下表现得像relative,在滚动条滚到该元素区域的时候根据top值的设置使元素固定离顶部的距离,表现像 position:fixed,也就是常见的吸顶需求效果。
特性
- 依赖父级元素滚动区域
- 定位参考物始终是
viewport,transform等可以改变position:fixed定位参考物的属性也没办法改变position:-webkit-sticky的定位参考物 position:-webkit-sticky属性的元素固定区域只依赖其父元素的可滚动高度,如果其父元素高度小于元素本身的高度,fixed效果失效。
兼容性
- iOS 6.1 及更高版本
- iOS only
-apple-system
苹果操作系统会从两种不同外观和大小的字体进行自动转换去调节系统新字体 “San Francisco”,可以通过 CSS 规则
1 | font-family: -apple-system , sans-serif; |
让系统智能选择适配操作系统的字体,添加 -apple-system 可以使字体变得更圆润锐利。
兼容性
- iOS 9.0 及更高版本
- Safari 9.0 及更高版本
- iOS / OS X only
命名规范
目录命名
- 项目文件夹:projectname
- 样式文件夹:css
- 脚本文件夹:js
- 样式类图片文件夹:img
文件资源命名
- 文件名不得含有空格
- 文件名建议只使用小写字母,不使用大写字母。( 为了醒目,某些说明文件的文件名,可以使用大写字母,比如README、LICENSE。 )
- 文件名包含多个单词时,单词之间建议使用半角的连词线 ( - ) 分隔。
- 引入资源使用相对路径,不要指定资源所带的具体协议 ( http:,https: ) ,除非这两者协议都不可用。
1 | <!-- 不推荐 --> |
图片命名
命名顺序
图片命名建议以以下顺序命名:
图片业务(可选) +(mod_)图片功能类别(必选)+ 图片模块名称(可选) + 图片精度(可选)
图片业务:
- pp_:拍拍
- wx_:微信
- sq_:手Q
- jd_:京东商城
- …
图片功能类别:
- mod_:是否公共,可选
- icon:模块类固化的图标
- logo:LOGO类
- spr:单页面各种元素合并集合
- btn:按钮
- bg:可平铺或者大背景
- …
图片模块名称:
- goodslist:商品列表
- goodsinfo:商品信息
- userava tar:用户头像
- …
图片精度:
- 普清:@1x
- Retina:@2x | @3x
- …
如下面例子:
1 | 公共模块: |
交叉业务协作
业务交叉协作的时候,为了避免图片命名冲突,建议图片名加上业务和模块前辍,如拍拍侧和手Q侧的业务交叉合作时,侧栏导航icon雪碧图命名:
1 | 推荐: |
处理高清图片的时候,命名应该加上图片相应的精度说明
1 | 推荐: |
HTML/CSS文件命名
确保文件命名总是以字母开头而不是数字,且字母一律小写,以下划线连接且不带其他标点符号,如:
1 | <!-- HTML --> |
ClassName命名
ClassName的命名应该尽量精短、明确,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “_” 连接
命名原则
基于姓氏命名法(继承 + 外来)
祖先模块不能出现下划线,除了是全站公用模块,如 mod_ 系列的命名:
推荐:
1 | <div class="modulename"> |
不推荐:
1 | <div class="modulename_info"> |
在子孙模块数量可预测的情况下,严格继承祖先模块的命名前缀
1 | <div class="modulename"> |
当子孙模块超过4级或以上的时候,可以考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块
推荐:
1 | <div class="modulename"> |
不推荐:
1 | <div class="modulename"> |
模块命名
全站公共模块:以 mod_ 开头
1 | <div class="mod_yours"></div> |
业务公共模块:以 业务名_mod_ 开头
1 | <div class="paipai_mod_yours"></div> |
常用命名推荐
注意:ad、banner、gg、guanggao 等有机会和广告挂勾的字眠不建议直接用来做ClassName,因为有些浏览器插件(Chrome的广告拦截插件等)会直接过滤这些类名,因此
1 | <div class="ad"></div> |
这种广告的英文或拼音类名不应该出现
另外,敏感不和谐字眼也不应该出现,如:
1 | <div class="fuck"></div> |
| ClassName | 含义 |
|---|---|
| about | 关于 |
| account | 账户 |
| arrow | 箭头图标 |
| article | 文章 |
| aside | 边栏 |
| audio | 音频 |
| avatar | 头像 |
| bg,background | 背景 |
| bar | 栏(工具类) |
| branding | 品牌化 |
| crumb,breadcrumbs | 面包屑 |
| btn,button | 按钮 |
| caption | 标题,说明 |
| category | 分类 |
| chart | 图表 |
| clearfix | 清除浮动 |
| close | 关闭 |
| col,column | 列 |
| comment | 评论 |
| community | 社区 |
| container | 容器 |
| content | 内容 |
| copyright | 版权 |
| current | 当前态,选中态 |
| default | 默认 |
| description | 描述 |
| details | 细节 |
| disabled | 不可用 |
| entry | 文章,博文 |
| error | 错误 |
| even | 偶数,常用于多行列表或表格中 |
| fail | 失败(提示) |
| feature | 专题 |
| fewer | 收起 |
| field | 用于表单的输入区域 |
| figure | 图 |
| filter | 筛选 |
| first | 第一个,常用于列表中 |
| footer | 页脚 |
| forum | 论坛 |
| gallery | 画廊 |
| group | 模块,清除浮动 |
| header | 页头 |
| help | 帮助 |
| hide | 隐藏 |
| hightlight | 高亮 |
| home | 主页 |
| icon | 图标 |
| info,information | 信息 |
| last | 最后一个,常用于列表中 |
| links | 链接 |
| login | 登录 |
| logout | 退出 |
| logo | 标志 |
| main | 主体 |
| menu | 菜单 |
| meta | 作者、更新时间等信息栏,一般位于标题之下 |
| module | 模块 |
| more | 更多(展开) |
| msg,message | 消息 |
| nav,navigation | 导航 |
| next | 下一页 |
| nub | 小块 |
| odd | 奇数,常用于多行列表或表格中 |
| off | 鼠标离开 |
| on | 鼠标移过 |
| output | 输出 |
| pagination | 分页 |
| pop,popup | 弹窗 |
| preview | 预览 |
| previous | 上一页 |
| primary | 主要 |
| progress | 进度条 |
| promotion | 促销 |
| rcommd,recommendations | 推荐 |
| reg,register | 注册 |
| save | 保存 |
| search | 搜索 |
| secondary | 次要 |
| section | 区块 |
| selected | 已选 |
| share | 分享 |
| show | 显示 |
| sidebar | 边栏,侧栏 |
| slide | 幻灯片,图片切换 |
| sort | 排序 |
| sub | 次级的,子级的 |
| submit | 提交 |
| subscribe | 订阅 |
| subtitle | 副标题 |
| success | 成功(提示) |
| summary | 摘要 |
| tab | 标签页 |
| table | 表格 |
| txt,text | 文本 |
| thumbnail | 缩略图 |
| time | 时间 |
| tips | 提示 |
| title | 标题 |
| video | 视频 |
| wrap | 容器,包,一般用于最外层 |
| wrapper | 容器,包,一般用于最外层 |
JS 命名
变量
命名方式 : 小驼峰式命名方法
命名规范 : 类型+对象描述的方式,如果没有明确的类型,就可以使前缀为名词
| 类型 | 小写字母 |
|---|---|
| array | a |
| boolean | b |
| function | fn |
| int | i |
| object | o |
| regular | r |
| string | s |
1 | // 推荐 |
函数
命名方式 : 小驼峰方式 ( 构造函数使用大驼峰命名法 )
命名规则 : 前缀为动词
| 动词 | 含义 | 返回值 |
|---|---|---|
| can | 判断是否可执行某个动作(权限) | 函数返回一个布尔值。true:可执行;false:不可执行 |
| has | 判断是否含有某个值 | 函数返回一个布尔值。true:含有此值。false:不含有此值 |
| is | 判断是否为某个值 | 函数返回一个布尔值。true:为某个值;false:不为某个值 |
| get | 获取某个值 | 函数返回一个非布尔值 |
| set | 设置某个值 | 无返回值、返回是否设置成功或者返回链式对象 |
推荐:
1 | //是否可阅读 |
常量
命名方法 : 全部大写
命名规范 : 使用大写字母和下划线来组合命名,下划线用以分割单词。
推荐:
1 | const MAX_COUNT = 10; |
类的成员
- 公共属性和方法 : 同变量命名方式
- 私有属性和方法 : 前缀为下划线(_)后面跟公共属性和方法一样的命名方式
推荐(将name换成this是不是更熟悉了呢)
1 | function Student(name) { |
JS 规范
语言规范
类型
原始类型: 存取原始类型直接作用于值本身
- 布尔类型
- Null 类型
- Undefined 类型
- 数字类型
- BigInt 类型
- 字符串类型
- 符号类型 Symbol
1
2
3
4
5
6const foo = 1
let bar = foo
bar = 9
console.log(foo, bar) // 1, 9复杂类型: 访问复杂类型作用于值的引用
- object
- array
- function
1
2
3
4
5
6const foo = [1, 2, 3]
const bar = foo
bar[0] = 9
console.log(foo[0], bar[0]) // 9, 9
引用
- 请记得
const和let都是块级作用域,var是函数级作用域
1 | // const 和 let 只存在于定义它们的块中。 |
- 对所有引用都使用
const,不要使用var,eslint: prefer-const, no-const-assign
原因:这样做可以确保你无法重新分配引用,以避免出现错误和难以理解的代码
1 | // 不推荐: |
- 如果引用是可变动的,使用
let代替var,eslint: no-var
原因:
let是块级作用域的,而不像var属于函数级作用域
1 | //不推荐: |
对象
- 请使用字面量值创建对象,eslint: no-new-object
1 | // 不推荐: |
- 别使用保留字作为对象的键值,这样在 IE8 下不会运行
1 | // 不推荐: |
- 当使用动态属性名创建对象时,请使用对象计算属性名来进行创建
原因:因为这样做就可以让你在一个地方定义所有的对象属性
1 | function getKey(k) { |
- 请使用对象方法的简写方式,eslint: object-shorthand
1 | // 不推荐: |
请使用对象属性值的简写方式,eslint: object-shorthand
原因:这样更简短且描述更清楚
1 | const job = 'FrontEnd' |
- 将简写的对象属性分组后统一放到对象声明的开头
原因:这样更容易区分哪些属性用了简写的方式
1 | const job = 'FrontEnd' |
- 只对非法标识符的属性使用引号,eslint: quote-props
原因:因为通常来说我们认为这样主观上会更容易阅读,这样会带来代码高亮上的提升,同时也更容易被主流 JS 引擎优化
1 | // 不推荐: |
不要直接使用
Object.prototype的方法, 例如hasOwnProperty,propertyIsEnumerable和isPrototypeOf方法,eslint: no-prototype-builtins原因:这些方法可能会被对象自身的同名属性覆盖 - 比如
{ hasOwnProperty: false }或者对象可能是一个null对象(Object.create(null))
1 | // 不推荐: |
- 优先使用对象展开运算符
...来做对象浅拷贝而不是使用Object.assign,使用对象剩余操作符来获得一个包含确定的剩余属性的新对象
1 | // 非常不推荐 |
数组
- 请使用字面量值创建数组,eslint: no-array-constructor
1 | // 不推荐 |
- 向数组中添加元素时,请使用
push方法
1 | const items = [] |
- 使用展开运算符
...复制数组
1 | // 不推荐 |
- 把一个可迭代的对象转换为数组时,使用展开运算符
...而不是Array.from
1 | const foo = document.querySelectorAll('.foo') |
- 使用
Array.from来将一个类数组对象转换为数组
1 | const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 } |
- 遍历迭代器进行映射时使用
Array.from代替扩展运算符..., 因为这可以避免创建中间数组
1 | // 不推荐 |
- 使用数组的
map等方法时,请使用return声明,如果是单一声明语句的情况,可省略return
1 | // 推荐 |
- 如果一个数组有多行则要在数组的开括号后和闭括号前使用新行
1 | // 不推荐 |
解构赋值
- 当需要使用对象的多个属性时,请使用解构赋值,eslint: prefer-destructuring
愿意:解构可以避免创建属性的临时引用
1 | // 不推荐 |
- 当需要使用数组的多个值时,请同样使用解构赋值,eslint: prefer-destructuring
1 | const arr = [1, 2, 3, 4] |
- 函数需要回传多个值时,请使用对象的解构,而不是数组的解构
原因:可以非破坏性地随时增加或者改变属性顺序
1 | // 不推荐 |
字符串
- 字符串统一使用单引号的形式
'',eslint: quotes
1 | // 不推荐 |
- 字符串太长的时候,请不要使用字符串连接符换行
\,而是使用+
1 | const str = '凹凸实验室 凹凸实验室 凹凸实验室' + |
- 程序化生成字符串时,请使用模板字符串,eslint: prefer-template template-curly-spacing
1 | const test = 'test' |
不要对字符串使用
eval(),会导致太多漏洞, eslint: no-eval不要在字符串中使用不必要的转义字符, eslint: no-useless-escape
1 | // 不推荐 |
函数
- 不要使用Function构造函数创建函数, eslint: no-new-func
原因:此方式创建函数和对字符串使用
eval()一样会产生漏洞
1 | // 不推荐 |
- 在函数签名中使用空格,eslint: space-before-function-paren space-before-blocks
1 | const f = function(){} |
- 使用具名函数表达式而非函数声明,eslint: func-style
原因:这样做会导致函数声明被提升,这意味着很容易在文件中定义此函数之前引用它,不利于可读性和可维护性。如果你发现函数定义既庞大又复杂以至于不能理解文件的其他部分,或许你应该将它拆分成模块!别忘记要显式命名表达式,而不用管名字是否是从包含的变量(通常出现在现代浏览器中或者使用 Babel 编译器的时候)中推断的。这样会消除错误调用堆栈中的任何假设。 (讨论)
1 | // 不推荐 |
- 用圆括号包裹自执行匿名函数,eslint:wrap-iife
原因:一个立即执行匿名函数表达式是一个单一的单元,将其及其调用括号包装在括号中,能够清楚地表达这一点。注意,在到处都是模块的世界中几乎不需要 IIFE。
1 | // immediately-invoked function expression (IIFE) |
- 不要在非函数代码块(
if,while等)中声明函数,eslint:no-loop-func
1 | // 不推荐 |
- 不要将参数命名为
arguments,会导致该参数的优先级高于每个函数作用域内原先存在的arguments对象
1 | // 不推荐 |
不要使用
arguments,使用 剩余运算符...arguments只是一个类数组,而...是一个真正的数组
1 | // 不推荐 |
- 使用参数默认值语法而不是修改函数参数
1 | // 非常不推荐 |
- 避免参数默认值的副作用
1 | let b = 1 |
- 将参数默认值放在最后
1 | // 不推荐 |
- 不要更改参数,eslint: no-param-reassign
原因:操作作为参数传入的对象可能在原始调用中造成意想不到的变量副作用
1 | // 不推荐: |
- 不要给参数重新赋值,eslint: no-param-reassign
原因:参数重新赋值可能会导致无法预期的行为,尤其是当操作
arguments对象时,也可能导致优化问题,尤其是在 V8 引擎中
1 | // 不推荐 |
- 调用可变参数函数时建议使用展开运算符
...., eslint: prefer-spread
原因:显然你无需使用上下文,很难结合
new和apply
1 | // 不推荐 |
箭头函数
- 当你必须使用函数表达式(传递匿名函数)时,使用箭头函数标记. eslint: prefer-arrow-callback, arrow-spacing
原因:它将创建在
this上下文中执行的函数版本,通常是您想要的,并且语法更简洁
如果您有一个相当复杂的函数,则可以将该逻辑移到其自己的命名函数表达式中
1 | // 不推荐 |
- 如果函数体只包含一条没有副作用的返回表达式的语句,可以省略花括号并使用隐式的
return, 否则保留花括号并使用return语句,eslint: arrow-parens, arrow-body-style
1 | // 不推荐 |
- 一旦表达式跨多行,使用圆括号包裹以便更好阅读
1 | // 不推荐 |
- 函数如果只接收一个参数并且没使用用花括号,则省略圆括号,否则为了清晰明确则使用圆括号包裹参数,注意:总是使用圆括号也是可以接受的,eslint 中的 “always” 选项,eslint: arrow-parens
1 | // 不推荐 |
类&构造函数
- 使用
class,避免直接操作prototype
1 | // 不推荐 |
- 使用
extends来实现继承
原因:这是一个不会破坏
instanceof的内建实现原型式继承的方式
1 | // 不推荐 |
- 如果未声明构造函数,则类会有一个默认的构造函数,没必要用空的构造函数或者将其委托给父类,eslint: no-useless-constructor
1 | // 不推荐 |
- 避免类成员重复,eslint: no-dupe-class-members
原因:重复的类成员声明会默认使用最后声明的,通常会导致 bug
1 | // 不推荐 |
模块
- 使用标准的 ES6 模块语法
import和export
原因:模块是未来,让我们现在开始使用未来的特性
1 | // 不推荐 |
- 不要使用
import的通配符*,这样可以确保你只有一个默认的 export
1 | // 不推荐 |
- 同个文件每个模块只允许
import一次,有多个import请书写在一起,eslint: no-duplicate-imports
原因:这样可以让代码更易于维护
1 | // 不推荐 |
- 将所有
import语句放在文件最前方,eslint: import/imports-first
1 | // 不推荐 |
- 多行导入应该像多行数组和对象文字一样缩进
1 | // 不推荐 |
- 在模块
import声明中禁止使用Webpack的loader语法,eslint: import/no-webpack-loader-syntax
1 | // 不推荐 |
迭代器
- 不要使用
iterators,建议使用 JS 更高优先级的函数代替 for-in 或 for-of 循环,除非迫不得已,eslint: no-iterator no-restricted-syntax
1 | const numbers = [1, 2, 3, 4, 5] |
生成器
- 现阶段请不要使用生成器
generator
原因:因为不能很好地翻译成 ES5 代码
对象属性
- 使用
.来访问对象属性
1 | const joke = { |
- 当访问的属性是变量时使用
[]
1 | const luke = { |
变量声明
- 声明变量时,请使用
const、let关键字,如果没有写关键字,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突,另外,也很难明确该变量的作用域是什么。这里推荐使用const来声明变量,我们需要避免全局命名空间的污染。eslint: no-undef prefer-const
1 | // 不推荐 |
- 将所有的
const和let分组
1 | // 不推荐 |
- 变量不要进行链式赋值
原因:变量链式赋值会创建隐藏的全局变量
1 | // 不推荐 |
- 不允许出现未被使用的变量,eslint: no-unused-vars
原因:声明但未被使用的变量通常是不完全重构犯下的错误.这种变量在代码里浪费空间并会给读者造成困扰
1 | // 不推荐 |
Hoisting
var存在变量提升的情况,即var声明会被提升至该作用域的顶部,但是他们的赋值并不会。而const和let并不存在这种情况,他们被赋予了 Temporal Dead Zones, TDZ, 了解 typeof 不再安全很重要1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20function example () {
console.log(notDefined) // => throws a ReferenceError
}
function example () {
console.log(declareButNotAssigned) // => undefined
var declaredButNotAssigned = true
}
function example () {
let declaredButNotAssigned
console.log(declaredButNotAssigned) // => undefined
declaredButNotAssigned = true
}
function example () {
console.log(declaredButNotAssigned) // => throws a ReferenceError
console.log(typeof declaredButNotAssigned) // => throws a ReferenceError
const declaredButNotAssigned = true
}匿名函数的变量名会提升,但函数内容不会
1
2
3
4
5
6
7
8
9function example () {
console.log(anonymous) // => undefined
anonymous()
var anonymous = function () {
console.log('test')
}
}命名的函数表达式的变量名会被提升,但函数名和函数函数内容并不会
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21function example() {
console.log(named) // => undefined
named() // => TypeError named is not a function
superPower() // => ReferenceError superPower is not defined
var named = function superPower () {
console.log('Flying')
}
}
function example() {
console.log(named) // => undefined
named() // => TypeError named is not a function
var named = function named () {
console.log('named')
}
}
比较运算符&相等
使用
===和!==而非==和!=,eslint: eqeqeq条件声明例如
if会用ToBoolean这个抽象方法将表达式转成布尔值并遵循如下规则Objects等于trueUndefined等于falseNull等于falseBooleans等于布尔值Numbers在+0,-0, 或者NaN的情况下等于false, 其他情况是trueStrings为''时等于false, 否则是true
1
2
3
4if ([0] && []) {
// true
// 数组(即使是空数组)也是对象,对象等于true
}
分号
我们遵循
Standard的规范,不使用分号。关于应不应该使用分号的讨论有很多,本规范认为非必要的时候,应该不使用分号,好的
JS程序员应该清楚场景下是一定要加分号的,相信你也是名好的开发者。1
2
3
4
5
6
7
8
9
10
11// 不推荐
const test = 'good';
(function () {
const str = 'hahaha';
})()
// 推荐
const test = 'good'
;(() => {
const str = 'hahaha'
})();
标准特性
为了代码的可移植性和兼容性,我们应该最大化的使用标准方法,例如优先使用 string.charAt(3) 而不是 string[3]
eval()
由于 eval 方法比较 evil,所以我们约定禁止使用该方法
with() {}
由于 with 方法会产生神奇的作用域,所以我们也是禁止使用该方法的
修改内置对象的原型
不要修改内置对象,如 Object 和 Array
代码规范
单行代码块
在单行代码块中使用空格
不推荐
1 | function foo () {return true} |
推荐
1 | function foo () { return true } |
大括号风格
在编程过程中,大括号风格与缩进风格紧密联系,用来描述大括号相对代码块位置的方法有很多。在 JavaScript 中,主要有三种风格,如下:
One True Brace Style
1
2
3
4
5if (foo) {
bar()
} else {
baz()
}Stroustrup
1
2
3
4
5
6if (foo) {
bar()
}
else {
baz()
}Allman
1
2
3
4
5
6
7
8if (foo)
{
bar()
}
else
{
baz()
}
我们团队约定使用 One True Brace Style 风格
变量命名
当命名变量时,主流分为驼峰式命名(constiableName)和下划线命名(constiable_name)两大阵营。
团队约定使用驼峰式命名
拖尾逗号
在 ECMAScript5 里面,对象字面量中的拖尾逗号是合法的,但在 IE8(非 IE8 文档模式)下,当出现拖尾逗号,则会抛出错误。
拖尾逗号的例子:
1 | const foo = { |
拖尾逗号的好处是,简化了对象和数组添加或删除元素,我们只需要修改新增的行即可,并不会增加差异化的代码行数。
因为拖尾逗号有好也有不好,所以团队约定允许在最后一个元素或属性与闭括号
]或}在不同行时,可以(但不要求)使用拖尾逗号。当在同一行时,禁止使用拖尾逗号。
逗号空格
逗号前后的空格可以提高代码的可读性,团队约定在逗号后面使用空格,逗号前面不加空格。
不推荐
1 | const foo = 1,bar = 2 |
推荐
1 | const foo = 1, bar = 2 |
逗号风格
逗号分隔列表时,在 JavaScript 中主要有两种逗号风格:
- 标准风格,逗号放置在当前行的末尾
- 逗号前置风格,逗号放置在下一行的开始位置
团队约定使用标准风格
不推荐
1 | const foo = 1 |
推荐
1 | const foo = 1, |
计算属性的空格
团队约定在对象的计算属性内,禁止使用空格
不推荐
1 | obj['foo' ] |
推荐
1 | obj['foo'] |
拖尾换行
在非空文件中,存在拖尾换行是一个常见的 UNIX 风格,它的好处是可以方便在串联和追加文件时不会打断 Shell 的提示。在日常的项目中,保留拖尾换行的好处是,可以减少版本控制时的代码冲突。
不推荐
1 | function func () { |
推荐
1 | function func () { |
可以通过 .editorconfig 添加 EOL
函数调用
为了避免语法错误,团队约定在函数调用时,禁止使用空格
不推荐
1 | fn () |
推荐
1 | fn() |
缩进
代码保持一致的缩进,是作为工程师的职业素养。但缩进用两个空格,还是四个空格,是用 Tab 还是空格呢?这样的争论太多了,也得不出答案。本规范结合了市面上优秀的开源项目,姑且约定使用 空格 来缩进,而且缩进使用两个空格。
那是不是不能使用 Tab 进行缩进了?我们可以通过配置 .editorconfig ,将 Tab 自动转换为空格。
对象字面量的键值缩进
团队约定对象字面量的键和值之间不能存在空格,且要求对象字面量的冒号和值之间存在一个空格
1 | // 不推荐 |
构造函数首字母大写
在 JavaScript 中 new 操作符用来创建某个特定类型的对象的一个实例,该类型的对象是由一个构造函数表示的。由于构造函数只是常规函数,唯一区别是使用 new 来调用。所以我们团队约定构造函数的首字母要大小,以此来区分构造函数和普通函数。
1 | // 不推荐 |
构造函数的参数
在 JavaScript 中,通过 new 调用构造函数时,如果不带参数,可以省略后面的圆括号。但这样会造成与整体的代码风格不一致,所以团队约定使用圆括号
1 | // 不推荐 |
链式调用
链式调用如果放在同一行,往往会造成代码的可读性差,但有些时候,短的链式调用并不会影响美观。所以本规范约定一行最多只能有四个链式调用,超过就要求换行。
空行
空白行对于分离代码逻辑有帮助,但过多的空行会占据屏幕的空间,影响可读性。团队约定最大连续空行数为 2
不推荐
1 | const a = 1 |
推荐
1 | const a = 1 |
链式赋值
链式赋值容易造成代码的可读性差,所以团队约定禁止使用链式赋值
不推荐
1 | const a = b = c = 1 |
推荐
1 | const a = 1 |
变量声明
JavaScript 允许在一个声明中,声明多个变量。团队约定在声明变量时,一个声明只能有一个变量
不推荐
1 | const a, b, c |
推荐
1 | const a |
分号
JavaScript 在所有类 C 语言中是比较独特的,它不需要在每个语句的末尾有分号。在很多情况下,JavaScript 引擎可以确定一个分号应该在什么位置然后自动添加它。此特征被称为 自动分号插入 (ASI),被认为是 JavaScript 中较为有争议的特征。
团队中对于是否应该使用分号,也有许多争论,本规范推荐不使用分号,因为我们认为好的工程师应该知道什么时候该加,什么时候不该加。
相关参考 :semi
代码块空格
一致性是任何风格指南的重要组成部分。虽然在哪里放置块的开括号纯属个人偏好,但在整个项目中应该保持一致。不一致的风格将会分散读者阅读代码的注意力。
团队约定代码块前要添加空格
不推荐
1 | if (a){ |
推荐
1 | if (a) { |
函数声明的空格
当格式化一个函数,函数名或 function 关键字与左括号之间允许有空白。命名函数要求函数名和 function 关键字之间有空格,但是匿名函数要求不加空格。
团队约定函数括号前要加空格
1 | // 不推荐 |
操作符的空格
团队约定操作符前后都需要添加空格
1 | // 不推荐 |
BOM
Unicode 字节顺序标记 (BOM) 用来指定代码单元是高字节序还是低字节序。也就是说,是高位在前还是低位在前。UTF-8 不需要 BOM 来表明字节顺序,因为单个字节并不影响字节顺序。
相信不少同学遇到过 BOM 的坑,这里不多说了,切记不要使用 windows 的记事本改代码!
注释规范
单行注释 ( // )
- 单独一行://(双斜线)与注释文字之间保留一个空格
- 在代码后面添加注释://(双斜线)与代码之间保留一个空格,并且//(双斜线)与注释文字之间保留一个空格。
- 注释代码://(双斜线)与代码之间保留一个空格。
推荐 :
1 | // 调用了一个函数;1)单独在一行 |
多行注释 ( / 注释说明 / )
- 若开始(/和结束(/)都在一行,推荐采用单行注释
- 若至少三行注释时,第一行为/,最后行为/,其他行以开始,并且注释文字与保留一个空格。
推荐 :
1 | /* |
函数 ( 方法 ) 注释
函数(方法)注释也是多行注释的一种,但是包含了特殊的注释要求,参照 javadoc(百度百科)
语法:
1 | /** |
常用注释关键字:(只列出一部分,并不是全部)
| 注释名 | 语法 | 含义 | 示例 |
|---|---|---|---|
| @function | @function 简要描述 | 用于定义当前对象是一个函数,后面可跟描述 | @function 处理表格的行 |
| @description | @description 描述信息 | 用于描述 | @description 合并Grid的行 |
| @param | @param 参数名 {参数类型} 描述信息 | 描述参数的信息 | @param name {String} 传入名称 |
| @return | @return {返回类型} 描述信息 | 描述返回值的信息 | @return {Boolean} true:可执行;false:不可执行 |
| @author | @author 作者信息 [附属信息:如邮箱、日期] | 描述此函数作者的信息 | @author 张三 2015/07/21 |
| @version | @version XX.XX.XX | 描述此函数的版本号 | @version 1.0.3 |
| @example | @example 示例代码 | 演示函数的使用 | @example setTitle(‘测试’) |
推荐:
1 | /** |
Vue 项目规范
这部分转载自:Vue 2 官方文档风格指南
组件名为多个单词
组件名应该始终是多个单词的,根组件 App 以及 <transition>、<component> 之类的 Vue 内置组件除外。
这样做可以避免跟现有的以及未来的 HTML 元素相冲突,因为所有的 HTML 元素名称都是单个单词的。
不推荐:
1 | Vue.component('todo', { |
1 | export default { |
推荐:
1 | Vue.component('todo-item', { |
1 | export default { |
组件数据
组件的 data 必须是一个函数。
当在组件中使用 data property 的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。
不推荐:
1 | Vue.component('some-comp', { |
1 | export default { |
推荐:
1 | Vue.component('some-comp', { |
1 | // In a .vue file |
1 | // 在一个 Vue 的根实例上直接使用对象是可以的, |
Prop 定义
Prop 定义应该尽量详细。
在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。
不推荐:
1 | // 这样做只有开发原型系统时可以接受 |
推荐:
1 | props: { |
1 | // 更好的做法! |
为 v-for 设置键值
总是用 key 配合 v-for。
在组件上总是必须用 key 配合 v-for,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。
不推荐:
1 | <ul> |
推荐:
1 | <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)。
不推荐:
1 | <ul> |
推荐:
1 | <ul> |
为组件样式设置作用域
对于应用来说,顶级 App 组件和布局组件中的样式可以是全局的,但是其它所有组件都应该是有作用域的。
这条规则只和单文件组件有关。你不一定要使用 scoped attribute。设置作用域也可以通过 CSS Modules,那是一个基于 class 的类似 BEM 的策略,当然你也可以使用其它的库或约定。
不管怎样,对于组件库,我们应该更倾向于选用基于 class 的策略而不是 scoped attribute。
这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。
不推荐:
1 | <template> |
推荐:
1 | <template> |
1 | <template> |
1 | <template> |
私有 property 名
使用模块作用域保持不允许外部访问的函数的私有性。如果无法做到这一点,就始终为插件、混入等不考虑作为对外公共 API 的自定义私有 property 使用 $_ 前缀。并附带一个命名空间以回避和其它作者的冲突 (比如 $_yourPluginName_)。
不推荐:
1 | var myGreatMixin = { |
1 | var myGreatMixin = { |
1 | var myGreatMixin = { |
1 | var myGreatMixin = { |
推荐:
1 | var myGreatMixin = { |
1 | // 甚至更好! |
组件文件
只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。
不推荐:
1 | Vue.component('TodoList', { |
推荐:
1 | components/ |
1 | components/ |
单文件组件文件名的大小写
单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)。
单词大写开头对于代码编辑器的自动补全最为友好,因为这使得我们在 JS(X) 和模板中引用组件的方式尽可能的一致。然而,混用文件命名方式有的时候会导致大小写不敏感的文件系统的问题,这也是横线连接命名同样完全可取的原因。
不推荐:
1 | components/ |
1 | components/ |
推荐:
1 | components/ |
1 | components/ |
基础组件名
应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。
不推荐:
1 | components/ |
推荐:
1 | components/ |
1 | components/ |
1 | components/ |
单例组件名
只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。
不推荐:
1 | components/ |
推荐:
1 | components/ |
紧密耦合的组件名
和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。
不推荐:
1 | components/ |
1 | components/ |
推荐:
1 | components/ |
1 | components/ |
组件名中的单词顺序
组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。
不推荐:
1 | components/ |
推荐:
1 | components/ |
自闭合组件
在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。
自闭合组件表示它们不仅没有内容,而且刻意没有内容。其不同之处就好像书上的一页白纸对比贴有“本页有意留白”标签的白纸。而且没有了额外的闭合标签,你的代码也更简洁。
不幸的是,HTML 并不支持自闭合的自定义元素——只有官方的“空”元素。所以上述策略仅适用于进入 DOM 之前 Vue 的模板编译器能够触达的地方,然后再产出符合 DOM 规范的 HTML。
不推荐:
1 | <!-- 在单文件组件、字符串模板和 JSX 中 --> |
1 | <!-- 在 DOM 模板中 --> |
推荐:
1 | <!-- 在单文件组件、字符串模板和 JSX 中 --> |
1 | <!-- 在 DOM 模板中 --> |
模板中的组件名大小写
对于绝大多数项目来说,在单文件组件和字符串模板中组件名应该总是 PascalCase 的——但是在 DOM 模板中总是 kebab-case 的。
PascalCase 相比 kebab-case 有一些优势:
- 编辑器可以在模板里自动补全组件名,因为 PascalCase 同样适用于 JavaScript。
<MyComponent>视觉上比<my-component>更能够和单个单词的 HTML 元素区别开来,因为前者的不同之处有两个大写字母,后者只有一个横线。- 如果你在模板中使用任何非 Vue 的自定义元素,比如一个 Web Component,PascalCase 确保了你的 Vue 组件在视觉上仍然是易识别的。
不幸的是,由于 HTML 是大小写不敏感的,在 DOM 模板中必须仍使用 kebab-case。
还请注意,如果你已经是 kebab-case 的重度用户,那么与 HTML 保持一致的命名约定且在多个项目中保持相同的大小写规则就可能比上述优势更为重要了。在这些情况下,在所有的地方都使用 kebab-case 同样是可以接受的。
不推荐:
1 | <!-- 在单文件组件和字符串模板中 --> |
1 | <!-- 在单文件组件和字符串模板中 --> |
1 | <!-- 在 DOM 模板中 --> |
推荐:
1 | <!-- 在单文件组件和字符串模板中 --> |
1 | <!-- 在 DOM 模板中 --> |
或者
1 | <!-- 在所有地方 --> |
JS/JSX 中的组件名大小写
JS/JSX 中的组件名应该始终是 PascalCase 的,尽管在较为简单的应用中只使用 Vue.component 进行全局组件注册时,可以使用 kebab-case 字符串。
不推荐:
1 | Vue.component('myComponent', { |
1 | import myComponent from './MyComponent.vue' |
1 | export default { |
1 | export default { |
推荐:
1 | Vue.component('MyComponent', { |
1 | Vue.component('my-component', { |
1 | import MyComponent from './MyComponent.vue' |
1 | export default { |
完整单词的组件名
组件名应该倾向于完整单词而不是缩写。
编辑器中的自动补全已经让书写长命名的代价非常之低了,而其带来的明确性却是非常宝贵的。不常用的缩写尤其应该避免。
不推荐:
1 | components/ |
推荐:
1 | components/ |
Prop 名大小写
在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板和 JSX 中应该始终使用 kebab-case。
我们单纯的遵循每个语言的约定。在 JavaScript 中更自然的是 camelCase。而在 HTML 中则是 kebab-case。
不推荐:
1 | props: { |
1 | <WelcomeMessage greetingText="hi"/> |
推荐:
1 | props: { |
1 | <WelcomeMessage greeting-text="hi"/> |
多个 attribute 的元素
多个 attribute 的元素应该分多行撰写,每个 attribute 一行。
在 JavaScript 中,用多行分隔对象的多个 property 是很常见的最佳实践,因为这样更易读。模板和 JSX 值得我们做相同的考虑。
不推荐:
1 | <img src="https://vuejs.org/images/logo.png" alt="Vue Logo"> |
1 | <MyComponent foo="a" bar="b" baz="c"/> |
推荐:
1 | <img |
1 | <MyComponent |
模板中简单的表达式
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
不推荐:
1 | {{ |
推荐:
1 | <!-- 在模板中 --> |
1 | // 复杂表达式已经移入一个计算属性 |
简单的计算属性
应该把复杂计算属性分割为尽可能多的更简单的 property。
不推荐:
1 | computed: { |
推荐:
1 | computed: { |
带引号的 attribute 值
非空 HTML attribute 值应该始终带引号 (单引号或双引号,以 JS 中未使用的为准)。
在 HTML 中不带空格的 attribute 值是可以没有引号的,但这鼓励了大家在特征值里不写空格,导致可读性变差。
不推荐:
1 | <input type=text> |
1 | <AppSidebar :style={width:sidebarWidth+'px'}> |
推荐:
1 | <input type="text"> |
1 | <AppSidebar :style="{ width: sidebarWidth + 'px' }"> |
指令缩写
指令缩写 (用 : 表示 v-bind:、用 @ 表示 v-on: 和用 # 表示 v-slot:) 应该要么都用要么都不用。
不推荐:
1 | <input |
1 | <input |
1 | <template v-slot:header> |
推荐:
1 | <input |
1 | <input |
1 | <input |
1 | <input |
1 | <template v-slot:header> |
1 | <template #header> |
组件/实例的选项的顺序
组件/实例的选项应该有统一的顺序。
这是我们推荐的组件选项默认顺序。它们被划分为几大类,所以你也能知道从插件里添加的新 property 应该放到哪里。
- 副作用 (触发组件外的影响)
el
- 全局感知 (要求组件以外的知识)
nameparent
- 组件类型 (更改组件的类型)
functional
- 模板修改器 (改变模板的编译方式)
delimiterscomments
- 模板依赖 (模板内使用的资源)
componentsdirectivesfilters
- 组合 (向选项里合并 property)
extendsmixins
- 接口 (组件的接口)
inheritAttrsmodelprops/propsData
- 本地状态 (本地的响应式 property)
datacomputed
- 事件 (通过响应式事件触发的回调)
watch- 生命周期钩子 (按照它们被调用的顺序)
beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedactivateddeactivatedbeforeDestroydestroyed
- 非响应式的 property (不依赖响应系统的实例 property)
methods
- 渲染 (组件输出的声明式描述)
template/renderrenderError
元素 attribute 的顺序
元素 (包括组件) 的 attribute 应该有统一的顺序。
这是我们为组件选项推荐的默认顺序。它们被划分为几大类,所以你也能知道新添加的自定义 attribute 和指令应该放到哪里。
- 定义 (提供组件的选项)
is
- 列表渲染 (创建多个变化的相同元素)
v-for
- 条件渲染 (元素是否渲染/显示)
v-ifv-else-ifv-elsev-showv-cloak
- 渲染方式 (改变元素的渲染方式)
v-prev-once
- 全局感知 (需要超越组件的知识)
id
- 唯一的 attribute (需要唯一值的 attribute)
refkey
- 双向绑定 (把绑定和事件结合起来)
v-model
- 其它 attribute (所有普通的绑定或未绑定的 attribute)
- 事件 (组件事件监听器)
v-on
- 内容 (覆写元素的内容)
v-htmlv-text
组件/实例选项中的空行
你可能想在多个 property 之间增加一个空行,特别是在这些选项一屏放不下,需要滚动才能都看到的时候。
当你的组件开始觉得密集或难以阅读时,在多个 property 之间添加空行可以让其变得容易。在一些诸如 Vim 的编辑器里,这样格式化后的选项还能通过键盘被快速导航。
好例子:
1 | props: { |
1 | // 没有空行在组件易于阅读和导航时也没问题。 |
单文件组件的顶级元素的顺序推
单文件组件应该总是让 <script>、<template> 和 <style> 标签的顺序保持一致。且 <style> 要放在最后,因为另外两个标签至少要有一个。
反例:
1 | <style>/* ... */</style> |
1 | <!-- ComponentA.vue --> |
好例子:
1 | <!-- ComponentA.vue --> |
1 | <!-- ComponentA.vue --> |
React 书写规范
本规范基本基于标准的 JavaScript 语法规范
基本规则
- 每个文件只包含一个 React 类组件
- 但是多个函数式组件可以放到一个文件中,eslint: react/no-multi-comp
- 一般使用 JSX 语法
- 除非是在非 JSX 文件中初始化应用,否则不要使用
React.createElement
命名规范
- 组件文件扩展名
如果使用 JavaScript,则文件扩展名为 .js;如果使用 TypeScript,则文件扩展名为 .tsx
- 组件文件名
如果是组件文件,则使用 PascalCase,如 MyComponent.js
如果组件是一个目录,则组件主入口命名为 index,如 index.js
- 引用命名
React 组件使用 PascalCase,组件实例使用 CamelCase,eslint: react/jsx-pascal-case
1 | // 不推荐 |
- 组件命名
使用文件名作为组件名字,例如, ReservationCard.js 应该包含名为 ReservationCard 的引用,然而对于文件夹中的根组件, 使用 index.js 作为文件名,使用文件夹的名字作为组件的名字
1 | // 不推荐 |
- 组件属性名
React DOM 使用小驼峰式命名法来定义属性的名称,而不使用 HTML 属性名称的命名约定,例如
1 | <div onClick={this.handler} /> |
Class Component VS Functional Component
只允许使用 Class Component 和 Functional Component 两种形态来书写组件,建议尽量使用函数式组件配合 Hooks 来进行开发
对齐
遵循以下JSX语法的对齐风格,eslint: react/jsx-closing-bracket-location
1 | // 不推荐 |
空格
- 自闭合的标签前要加一个空格,eslint: no-multi-spaces, react/jsx-tag-spacing
1 | // 不推荐 |
- 不要在 JSX 的花括号里边加空格,eslint: react/jsx-curly-spacing
1 | // 不推荐 |
引号
JSX 属性要使用单引号,与其他普通 JS 保持一致
1 | // 不推荐 |
属性
- 属性名使用 CamelCase
1 | // 不推荐 |
- 当属性值为true时可以省略, eslint: react/jsx-boolean-value
1 | // 不推荐 |
- 避免使用数组的索引作为 key 属性值, 建议使用稳定的ID,eslint: react/no-array-index-key
原因:不使用稳定的 ID 会对性能产生副作用并且组件状态会出问题,是一种反模式
1 | // 不推荐 |
- 为所有的非必需属性定义使用 defaultProps 明确的默认值
1 | // 不推荐 |
Refs
避免使用字符串引用,请使用回调函数作为引用,eslint: react/no-string-refs
1 | // 不推荐 |
圆括号
当 JSX 标签超过一行时使用圆括号包裹, eslint: react/wrap-multilines
1 | // 不推荐 |
标签
- 没有子元素的标签请自闭合,eslint: react/self-closing-comp
1 | // 不推荐 |
- 如果组件包含多行属性,在新的一行闭合标签,eslint: react/jsx-closing-bracket-location
1 | // 不推荐 |
方法
- 使用箭头函数包裹本地变量
1 | function ItemList (props) { |
- 类组件的内部方法不要使用下划线前缀
1 | // 不推荐 |
- 确保在 render 方法中存在返回值,eslint: require-render-return
1 | // 不推荐 |
Hooks 书写规范
- Hooks 只能应用于函数式组件中
- 只在 React 函数最顶层使用 Hooks
不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们
1 | // 不推荐 |
