首页
关于
Search
1
唤端-LaunchApp
211 阅读
2
前端风格指南
172 阅读
3
前端CI/CD简述
141 阅读
4
H5兼容性问题(持续更新...)
130 阅读
5
IOS风格指南
127 阅读
默认分类
前端
javascript
CSS
基础
移动APP
后端
flutter
登录
Search
yu.zhai
累计撰写
6
篇文章
累计收到
1
条评论
首页
栏目
默认分类
前端
javascript
CSS
基础
移动APP
后端
flutter
页面
关于
搜索到
6
篇与
的结果
2022-07-21
前端风格指南
前端规范HTMLDOCTYPE 声明一个DOCTYPE必须包含以下部分,并严格按照顺序出现:A string that is an ASCII case-insensitive match for the string “<!DOCTYPE”.One or more space characters.A string that is an ASCII case-insensitive match for the string “html”.Optionally, a DOCTYPE legacy string or an obsolete permitted DOCTYPE string (defined below).Zero or more space characters.A “>” (U+003E) character.一个ASCII字符串 “<!DOCTYPE” ,大小写不敏感一个或多个空白字符一个ASCII字符串”html”,大小写不敏感一个可选的历史遗留的DOCTYPE字符串 (DOCTYPE legacy string),或者一个可选的已过时但被允许的DOCTYPE字符串 (obsolete permitted DOCTYPE string) 字符串一个或多个空白字符一个编码为 U+003E 的字符 “>”页面语言LANGLang属性的取值应该遵循互联网工程任务组–IETF(The Internet Engineering Task Force)制定的关于语言标签的文档 BCP 47 - Tags for Identifying Languages团队约定推荐使用属性值 cmn-Hans-CN(简体, 中国大陆),但是考虑浏览器和操作系统的兼容性,目前仍然使用 zh-CN 属性值<html lang="zh-CN">更多地区语言参考:zh-SG 中文 (简体, 新加坡) 对应 cmn-Hans-SG 普通话 (简体, 新加坡) zh-HK 中文 (繁体, 香港) 对应 cmn-Hant-HK 普通话 (繁体, 香港) zh-MO 中文 (繁体, 澳门) 对应 cmn-Hant-MO 普通话 (繁体, 澳门) zh-TW 中文 (繁体, 台湾) 对应 cmn-Hant-TW 普通话 (繁体, 台湾)CHARSETBecause the character sets in ISO-8859 was limited in size, and not compatible in multilingual environments, the Unicode Consortium developed the Unicode Standard.The Unicode Standard covers (almost) all the characters, punctuations, and symbols in the world.Unicode enables processing, storage, and transport of text independent of platform and language.The default character encoding in HTML-5 is UTF-8.因为 ISO-8859 中字符集大小是有限的,且在多语言环境中不兼容,所以 Unicode 联盟开发了 Unicode 标准。Unicode 标准覆盖了(几乎)所有的字符、标点符号和符号。Unicode 使文本的处理、存储和运输,独立于平台和语言。HTML-5 中默认的字符编码是 UTF-8参阅 HTML Unicode (UTF-8) Reference团队约定一般情况下统一使用 “UTF-8” 编码<meta charset="UTF-8">由于历史原因,有些业务可能会使用 “GBK” 编码<meta charset="GBK">请尽量统一写成标准的 “UTF-8”,不要写成 “utf-8” 或 “utf8” 或 “UTF8”。根据 IETF对UTF-8的定义,其编码标准的写法是 “UTF-8”;而 UTF8 或 utf8 的写法只是出现在某些编程系统中,如 .NET framework 的类 System.Text.Encoding 中的一个属性名就叫 UTF8。UTF-8写法: UTF8 or UTF-8?GBK:Application of IANA Charset Registration for GBKCharset :character-encoding-declaration元素及标签闭合HTML元素共有以下5种:空元素:area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr原始文本元素:script、styleRCDATA元素:textarea、title外来元素:来自MathML命名空间和SVG命名空间的元素。常规元素:其他HTML允许的元素都称为常规元素。元素标签的闭合应遵循以下原则:Tags are used to delimit the start and end of elements in the markup. Raw text, escapable raw text, and normal elements have a start tag to indicate where they begin, and an end tag to indicate where they end. The start and end tags of certain normal elements can be omitted, as described below in the section on optional tags. Those that cannot be omitted must not be omitted. Void elements only have a start tag; end tags must not be specified for void elements. Foreign elements must either have a start tag and an end tag, or a start tag that is marked as self-closing, in which case they must not have an end tag.原始文本元素、RCDATA元素以及常规元素都有一个开始标签来表示开始,一个结束标签来表示结束。某些元素的开始和结束标签是可以省略的,如果规定标签不能被省略,那么就绝对不能省略它。空元素只有一个开始标签,且不能为空元素设置结束标签。外来元素可以有一个开始标签和配对的结束标签,或者只有一个自闭合的开始标签,且后者情况下该元素不能有结束标签。团队约定为了能让浏览器更好的解析代码以及能让代码具有更好的可读性,有如下约定:所有具有开始标签和结束标签的元素都要写上起止标签,某些允许省略开始标签或和束标签的元素亦都要写上。空元素标签都不加 “/” 字符推荐:<div> <h1>我是h1标题</h1> <p>我是一段文字,我有始有终,浏览器能正确解析</p> </div> <br>不推荐:<div> <h1>我是h1标题</h1> <p>我是一段文字,我有始无终,浏览器亦能正确解析 </div> <br/>更多关于元素及标签关闭:#Elements书写风格HTML代码大小写HTML标签名、类名、标签属性和大部分属性值统一用小写推荐:<div class="demo"></div>不推荐:<div class="DEMO"></div> <DIV CLASS="DEMO"></DIV>HTML文本、CDATA、JavaScript、meta标签某些属性等内容可大小写混合<!-- 优先使用 IE 最新版本和 Chrome Frame --> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/> <!-- HTML文本内容 --> <h1>I AM WHAT I AM </h1> <!-- JavaScript 内容 --> <script type="text/javascript"> var demoName = 'demoName'; ... </script> <!-- CDATA 内容 --> <script type="text/javascript"><![CDATA[ ... ]]></script>类型属性不需要为 CSS、JS 指定类型属性,HTML5 中默认已包含推荐:<link rel="stylesheet" href="" > <script src=""></script>不推荐:<link rel="stylesheet" type="text/css" href="" > <script type="text/javascript" src="" ></script>元素属性元素属性值使用双引号语法元素属性值可以写上的都写上推荐:<input type="text"> <input type="radio" name="name" checked="checked" >不推荐:<input type=text> <input type='text'> <input type="radio" name="name" checked >更多关于元素属性:#Attributes特殊字符引用In certain cases described in other sections, text may be mixed with character references. These can be used to escape characters that couldn’t otherwise legally be included in text.文本可以和字符引用混合出现。这种方法可以用来转义在文本中不能合法出现的字符。在 HTML 中不能使用小于号 “<” 和大于号 “>”特殊字符,浏览器会将它们作为标签解析,若要正确显示,在 HTML 源代码中使用字符实体推荐:<a href="#">more>></a>不推荐:<a href="#">more>></a>更多关于符号引用:#Character references代码缩进统一使用四个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置)<div class="jdc"> <a href="#"></a> </div>纯数字输入框使用 type="tel" 而不是 type="number"<input type="tel">代码嵌套元素嵌套规范,每个块状元素独立一行,内联元素可选推荐:<div> <h1></h1> <p></p> </div> <p><span></span><span></span></p>不推荐:<div> <h1></h1><p></p> </div> <p> <span></span> <span></span> </p>段落元素与标题元素只能嵌套内联元素推荐:<h1><span></span></h1> <p><span></span><span></span></p>不推荐:<h1><div></div></h1> <p><div></div><div></div></p>注释规范遵循标准HTML注释规范写法应该遵循以下标准:Comments must start with the four character sequence U+003C LESS-THAN SIGN, U+0021 EXCLAMATION MARK, U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS (<!–). Following this sequence, the comment may have text, with the additional restriction that the text must not start with a single “>” (U+003E) character, nor start with a U+002D HYPHEN-MINUS character (-) followed by a “>” (U+003E) character, nor contain two consecutive U+002D HYPHEN-MINUS characters (–), nor end with a U+002D HYPHEN-MINUS character (-). Finally, the comment must be ended by the three character sequence U+002D HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN (–>).必须以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,即 “–>”标准写法:<!--Comment Text-->错误的写法:<!-->The Wrong Comment Text--> <!--->The Wrong Comment Text--> <!--The--Wrong--Comment Text--> <!--The Wrong Comment Text--->参考 www.w3.org #Comments团队约定单行注释一般用于简单的描述,如某些状态描述、属性描述等注释内容前后各一个空格字符,注释位于要注释代码的上面,单独占一行推荐:<!-- Comment Text --> <div>...</div>不推荐:<div>...</div><!-- Comment Text --> <div><!-- Comment Text --> ... </div>模块注释一般用于描述模块的名称以及模块开始与结束的位置注释内容前后各一个空格字符,<!-- S Comment Text --> 表示模块开始,<!-- E Comment Text --> 表示模块结束,模块与模块之间相隔一行推荐写法:<!-- S Comment Text A --> <div class="mod_a"> ... </div> <!-- E Comment Text A --> <!-- S Comment Text B --> <div class="mod_b"> ... </div> <!-- E Comment Text B -->不推荐写法:<!-- S Comment Text A --> <div class="mod_a"> ... </div> <!-- E Comment Text A --> <!-- S Comment Text B --> <div class="mod_b"> ... </div> <!-- E Comment Text B -->嵌套模块注释当模块注释内再出现模块注释的时候,为了突出主要模块,嵌套模块不再使用<!-- S Comment Text --> <!-- E Comment Text -->而改用<!-- /Comment Text -->注释写在模块结尾标签底部,单独一行。<!-- S Comment Text A --> <div class="mod_a"> <div class="mod_b"> ... </div> <!-- /mod_b --> <div class="mod_c"> ... </div> <!-- /mod_c --> </div> <!-- E Comment Text A -->文件模版HTML模版指的是团队使用的初始化HTML文件,里面会根据不同平台而采用不一样的设置,一般主要不同的设置就是 mata 标签的设置,以下是 PC 和移动端的 HTML 模版。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>Web MetaWebApp Meta 标签设置(iOS)A web application is designed to look and behave in a way similar to a native application—for example, it is scaled to fit the entire screen on iOS. You can tailor your web application for Safari on iOS even further, by making it appear like a native application when the user adds it to the Home screen. You do this by using settings for iOS that are ignored by other platforms.WebApp目的在于使其界面和行为在某种程度上类似于原生APP应用。例如,WebApp 可以在 iOS 设备上通过缩放去适配设备屏幕。当用户将WebApp程序添加到主屏幕后,会使得它看上去像原生APP一样,以此,你可以进一步为 Safari 定制自己的 WebApp,而使用某些专为 iOS 平台设定的设置就可以做到。WebApp可以通过设置 meta 标签来改变页面的一些表现,有些 meta 设置在 Safari 应用或原生 App 的内嵌网页中都可以生效,而有些设置侧需要将应用添加到主屏幕的时候才会生效。Viewport Meta Tag通用类设置<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">width – viewport的宽度height – viewport的高度initial-scale – 初始的缩放比例minimum-scale – 允许用户缩放到的最小比例maximum-scale – 允许用户缩放到的最大比例user-scalable – 是否允许用户缩放Safari on iOS viewportThe width of the viewport in pixels. The default is 980. The range is from 200 to 10,000.The minimum-scale and maximum-scale properties also affect the behavior when changing orientations. The range of these property values is from >0 to 10.0. The default value for minimum-scale is 0.25 and maximum-scale is 5.0user-scalable – The default is yes.Setting user-scalable to no also prevents a webpage from scrolling when entering text in an input field.默认宽度是 980px,范围从 200px 到 10000pxinitial-scale 缩放比例范围值是 从 >0 到 10 之间minimum-scale 默认值是 0.25maximum-scale 默认值是 5user-scalable – 默认值是 yes,设置 no 还可以在文本框输入文本的时候阻止页面滚动更多关于 Safari on iOS viewport 的设置:Configuring the ViewportSafari HTML ReferenceApple-Specific Meta Tag Keysapple-mobile-web-app-capable设置 WebApp 是否进入全屏模式,该设置需要添加到主屏幕才生效<meta name="apple-mobile-web-app-capable" content="yes">If content is set to yes, the web application runs in full-screen mode;otherwise, it does not. The default behavior is to use Safari to display web content.You can determine whether a webpage is displayed in full-screen mode using the window.navigator.standalone read-only Boolean JavaScript property.content设置 yes 进入全屏模式默认会启动 Safari 应用,使用 Safari 应用浏览通过检测 window.navigator.standalone 的 Boolean 值可以判断 web 应用是否处于全屏模式apple-mobile-web-app-status-bar-style为 webapp 设置状态栏样式<meta name="apple-mobile-web-app-status-bar-style" content="black">This meta tag has no effect unless you first specify full-screen mode as described in apple-apple-mobile-web-app-capable.If content is set to default, the status bar appears normal. If set to black, the status bar has a black background. If set to black-translucent, the status bar is black and translucent. If set to default or black, the web content is displayed below the status bar. If set to black-translucent, the web content is displayed on the entire screen, partially obscured by the status bar. The default value is default.此 meta 设置只在全屏模式生效默认值是 defaultcontent=”black”,状态栏背景黑色,网页内容在状态栏下面content=”black-translucent”,状态栏半透明,背景黑色,网页内容占满全屏该设置在 iOS6 和 iOS7 表现还可以,但到了 iOS8 后会出现各种问题,而且在 iOS9 中并没有生效。参阅:iOS 8: web app status bar position and resizing problemsformat-detection自动识别页面中有可能是电话格式的数字<meta name="format-detection" content="telephone=no">By default, Safari on iOS detects any string formatted like a phone number and makes it a link that calls the number. Specifying telephone=no disables this feature.iOS中的 Safari 会默认识别与电话格式相似的数字并生成一个可以拉起电话应用并将该数字作为电话号码拨打的链接。定义 telephone=no 可以屏蔽该功能更多 WebApp 设置参考 Configuring Web Applications图片格式图片格式常见的图片格式有 GIF、PNG8、PNG24、JPEG、WEBP,根据图片格式的特性和场景需要选取适合的图片格式。GIFGIF图象是基于颜色列表的(存储的数据是该点的颜色对应于颜色列表的索引值),最多只支持8位(256色)。GIF文件内部分成许多存储块,用来存储多幅图象或者是决定图象表现行为的控制块,用以实现动画和交互式应用。GIF文件还通过LZW压缩算法压缩图象数据来减少图象尺寸特性优秀的压缩算法使其在一定程度上保证图像质量的同时将体积变得很小。可插入多帧,从而实现动画效果。可设置透明色以产生对象浮现于背景之上的效果。由于采用了8位压缩,最多只能处理256种颜色,故不宜应用于真彩色图片。更多关于GIF:维基百科 - GIFGIF文档PNGPNG是20世纪90年代中期开始开发的图像文件存储格式,其目的是企图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。流式网络图形格式(Portable Network Graphic Format,PNG)名称来源于非官方的“PNG’s Not GIF”,是一种位图文件(bitmap file)存储格式,读成“ping”。PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且还可存储多到16位的α通道数据。PNG使用从LZ77派生的无损数据压缩算法。特性支持256色调色板技术,文件体积小。无损压缩最高支持48位真彩色图像以及16位灰度图像。支持Alpha通道的透明/半透明特性。支持图像亮度的Gamma校准信息。支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。渐近显示和流式读写,适合在网络传输中快速显示预览效果后再展示全貌。使用CRC防止文件出错。最新的PNG标准允许在一个文件内存储多幅图像。更多关于PNG:PNG官方站 - PNG General InformationPNG格式维基百科 - PNGJPEGJPEG是一种针对照片视频而广泛使用的一种有损压缩标准方法。这个名称代表Joint Photographic Experts Group(联合图像专家小组)。此团队创立于公元1986年,1992年发布了JPEG的标准而在1994年获得了ISO 10918-1的认定特性适用于储存24位元全采影像采取的压缩方式通常为有损压缩不支持透明或动画压缩比越高影像耗损越大,失真越严重压缩比在10左右肉眼无法辨出压缩图与原图的差别更多关于JPEG:维基百科 - JPEGWEBPWebP,是一种同时提供了有损压缩与无损压缩的图片文件格式,派生自视频编码格式 VP8,是由Google在购买On2 Technologies后发展出来。WebP最初在2010年发布,2011年11月8日,Google开始让WebP支持无损压缩和透明色的功能,而在2012年8月16日的参考实做libwebp 0.2.0中正式支持特性同时提供有损压缩和无损压缩两种图片文件格式文件体积小,无损压缩后,比 PNG 文件少了 45% 的文件大小;有损压缩后,比 JPEG 文件少了 25% - 34% 文件大小浏览器兼容差,目前只支持客户端 Chrome 和 Opera 浏览器以及安卓原生浏览器(Andriod 4.0+),WebP兼容性更多关于WebP:维基百科 - WEBPWEBP探寻之路团队约定内容图内容图多以商品图等照片类图片形式存在,颜色较为丰富,文件体积较大优先考虑 JPEG 格式,条件允许的话优先考虑 WebP 格式尽量不使用PNG格式,PNG8 色位太低,PNG24 压缩率低,文件体积大背景图背景图多为图标等颜色比较简单、文件体积不大、起修饰作用的图片PNG 与 GIF 格式,优先考虑使用 PNG 格式,PNG格式允许更多的颜色并提供更好的压缩率图像颜色比较简单的,如纯色块线条图标,优先考虑使用 PNG8 格式,避免使用 JPEG 格式图像颜色丰富而且图片文件不太大的(40KB 以下)或有半透明效果的优先考虑 PNG24 格式图像颜色丰富而且文件比较大的(40KB - 200KB)优先考虑 JPEG 格式条件允许的,优先考虑 WebP 代替 PNG 和 JPEG 格式图片大小图片大小全国网速现状固定网络据文章 《2015年Q3中国宽带速率状况报告》,2015第三季全国平均速度整体情况:中国固定宽带互联网网络平均网络下载速率达到7.90 Mbit/s,用户进行网页浏览的平均首屏呈现时间为2.18s,平均视频下载速率为6.41Mbit/s移动网络3G网络传输速率理论峰值在3.5Mbps,4G网络传输速率理论上可达到20Mbps,最高可以达到100Mbps。根据 128KB/s=128×8(Kb/s)=1024Kb/s=1Mb/s 的转换来算,3G网络的理论传输速率可达到450KB/s,4G网络的理论传输速率可达到 2.5MB/s ~ 12.5MB/s受用户计算机性能、网络设备质量、资源使用情况、网络高峰期、网站服务能力、线路衰耗、信号衰减等多因素影响,3G和4G的实际平均传输速率约为:3G:最高值100KB/s,平均值40~50KB/s4G:最高值2.75MB/s,平均500~1000KB/s3G/4G用户占比2015年8月移动宽带(3G/4G)用户占比各省分布情况:据文章 《工信部:2015年7月底中国4G用户累计超过2.5亿》 介绍:截至2015年7月底,中国4G用户累计超过2.5亿(全球LTE用户超过7.9亿,全球TD-LTE用户超过2.78亿),已建设4G基站超过153万个,其中完成TD-LTE基站建设超过100万个,多载波聚合等TD-LTE演进技术逐步商用,4G智能手机已经占到国内智能手机市场的82.7%。团队约定中国普通家庭的宽带基本能达到8Mbps,实际速率大约为500—900KB/s,全国3G/4G用户占有比超过了50%,为了保证图片能更好地加载展示给用户看,团队约定:PC平台单张的图片的大小不应大于 200KB。移动平台单张的图片的大小不应大于 100KB。(图片的大小约定标准随全国网速的改变而改变)图片质量上线的图片都应该经过压缩处理,压缩后的图片不应该出现肉眼可感知的失真区域60质量的JPEG格式图片与质量大于60的相比,肉眼已看不出明显的区别,因此保存 JPEG 图的时候,质量一般控制在60,若保真度要求高的图片可适量提高到 80,图片大小控制在 200KB 以内图片引入图片引入测试内容图应该写上表明图片尺寸的占位图,可以用线上占位图生成服务,如:http://placeholder.qiniudn.com/300x200HTML 中图片引入不需添加 width、height 属性,alt 属性应该写上推荐:<img src="" alt="" >不推荐:<img src="" width="" height="" >CSS 中图片引入不需要引号.jdc { background-image: url(icon.png); }CSS Sprites VS Data URIsCSS Sprites特点减少请求数加速图片的显示维护更新成本大更多的内存消耗,特别是大体积或有过多空白的 Sprites 图图片渗漏,相邻的不需展示的图片有可能出现在展示元素中,特别是在高清设备移动设备上Data URIs(base64编码)减少请求数转换文件体积大,大约比原始的二进制大33%IE6 / IE7 不支持图片显示相对较慢,需要更多的CPU消耗更多关于 CSS Sprites 和 Data URIs 可以阅读:《When to Base64 Encode Images (and When Not To)》《Data URI 最佳实践》《Data URI&MHTML: 用还是不用?》CSS Sprites vs. Data URIs: Which is Faster on Mobile?团队约定CSS Sprites 使用建议适合使用频率高更新频率低的小图标尽量不留太多的空白体积较大的图片不合并确保要合并的小图坐标数值和合并后的 Sprites 图尺寸均为偶数Data URIs(base64编码)使用建议适合更新频率高的小图片,如某些具备自定义功能的标题icon等转换成 Base64 编码的图片应小于 2KB移动端不使用 Base64 编码要兼容 IE6/IE7 的不使用CSS编码规范CSS样式表是一个序列通用字符集,传输和存储过程中,这些字符必须由支持 US-ASCII(例如 UTF-8, ISO 8859-x, SHIFT JIS 等)字符编码方式编译文档内嵌样式表编码When a style sheet is embedded in another document, such as in the STYLE element or “style” attribute of HTML, the style sheet shares the character encoding of the whole document.当样式出现在其它文档,如 HTML 的 STYLE 标签或标签属性 “style”,样式的编码由文档的决定。文档外链样式表编码When a style sheet resides in a separate file, user agents must observe the following priorities when determining a style sheet’s character encoding (from highest priority to lowest):An HTTP “charset” parameter in a “Content-Type” field (or similar parameters in other protocols)BOM and/or @charsetor other metadata from the linking mechanism (if any)charset of referring style sheet or document (if any)Assume UTF-8文档外链样式表的编码可以由以下各项按照由高到低的优先级顺序决定:HTTP “Content-Type” 字段参数 “charset”(或其它协议相似的参数)BOM(byte-order mark)和(或)@charsetLink 中的元数据设置(如果有的话)引用样式表字符集或文档编码(如果有的话)假定为 UTF-8 编码样式表编码Authors using an @charset rule must place the rule at the very beginning of the style sheet, preceded by no characters. (If a byte order mark is appropriate for the encoding used, it may precede the @charset rule.)@charset must be written literally, i.e., the 10 characters ‘@charset “‘ (lowercase, no backslash escapes), followed by the encoding name, followed by ‘“;’.@charset规则一定要在样式文件的第一行首个字符位置开始,否则的话就会有机会让 BOM 设置生效(如果有设置 BOM 的话)而优于 @charset 作为样式表的编码@charset ""; 一定要写上,并且用小写字母,不能出现转义符团队约定样式文件必须写上 @charset 规则,并且一定要在样式文件的第一行首个字符位置开始写,编码名用 “UTF-8”字符 @charset “”; 都用小写字母,不能出现转义符,编码名允许大小混写考虑到在使用“UTF-8”编码情况下 BOM 对代码的污染和编码显示的问题,在可控范围下,坚决不使用 BOM。(更多关于 BOM 可参考 BOM的介绍 和 「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别? )推荐:@charset "UTF-8"; .jdc{}不推荐:/** * @desc File Info * @author Author Name * @date 2015-10-10 */ /* @charset规则不在文件首行首个字符开始 */ @charset "UTF-8"; .jdc{} @CHARSET "UTF-8"; /* @charset规则没有用小写 */ .jdc{} /* 无@charset规则 */ .jdc{}更多关于样式编码:CSS style sheet representation代码风格代码格式化样式书写一般有两种:一种是紧凑格式 (Compact).jdc{ display: block;width: 50px;}一种是展开格式(Expanded).jdc{ display: block; width: 50px; }团队约定统一使用展开格式书写样式代码大小写样式选择器,属性名,属性值关键字全部使用小写字母书写,属性字符串允许使用大小写。/* 推荐 */ .jdc{ display:block; } /* 不推荐 */ .JDC{ DISPLAY:BLOCK; }选择器尽量少用通用选择器 *不使用 ID 选择器不使用无具体语义定义的标签选择器/* 推荐 */ .jdc {} .jdc li {} .jdc li p{} /* 不推荐 */ *{} #jdc {} .jdc div{}代码缩进统一使用四个空格进行代码缩进,使得各编辑器表现一致(各编辑器有相关配置).jdc { width: 100%; height: 100%; }分号每个属性声明末尾都要加分号;.jdc { width: 100%; height: 100%; }代码易读性左括号与类名之间一个空格,冒号与属性值之间一个空格推荐:.jdc { width: 100%; }不推荐:.jdc{ width:100%; }逗号分隔的取值,逗号之后一个空格推荐:.jdc { box-shadow: 1px 1px 1px #333, 2px 2px 2px #ccc; }不推荐:.jdc { box-shadow: 1px 1px 1px #333,2px 2px 2px #ccc; }为单个css选择器或新申明开启新行推荐:.jdc, .jdc_logo, .jdc_hd { color: #ff0; } .nav{ color: #fff; }不推荐:.jdc,jdc_logo,.jdc_hd { color: #ff0; }.nav{ color: #fff; }颜色值 rgb() rgba() hsl() hsla() rect() 中不需有空格,且取值不要带有不必要的 0推荐:.jdc { color: rgba(255,255,255,.5); }不推荐:.jdc { color: rgba( 255, 255, 255, 0.5 ); }属性值十六进制数值能用简写的尽量用简写推荐:.jdc { color: #fff; }不推荐:.jdc { color: #ffffff; }不要为 0 指明单位推荐:.jdc { margin: 0 10px; }不推荐:.jdc { margin: 0px 10px; }属性值引号css属性值需要用到引号时,统一使用单引号/* 推荐 */ .jdc { font-family: 'Hiragino Sans GB'; } /* 不推荐 */ .jdc { font-family: "Hiragino Sans GB"; }属性书写顺序建议遵循以下顺序:布局定位属性: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 ….jdc { display: block; position: relative; float: left; width: 100px; height: 100px; margin: 0 10px; padding: 20px 0; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; color: #333; background: rgba(0,0,0,.5); -webkit-border-radius: 10px; -moz-border-radius: 10px; -o-border-radius: 10px; -ms-border-radius: 10px; border-radius: 10px; }mozilla官方属性顺序推荐CSS3浏览器私有前缀写法CSS3 浏览器私有前缀在前,标准前缀在后.jdc { -webkit-border-radius: 10px; -moz-border-radius: 10px; -o-border-radius: 10px; -ms-border-radius: 10px; border-radius: 10px; }更多关于浏览器私有前辍写法:#Vendor-specific extensionsSASS规范语法选用SASS有两种语法格式,一种是 SCSS (Sassy CSS),另一种是缩进格式(Indented Syntax),有时称之为 Sass。SCSSSCSS语法基于 CSS 语法扩展,每一个有效的 CSS 文件都是一个有效的具有相同含义的 SCSS 文件,换种说法就是 SCSS 能识别大多数的 CSS hacks 写法和浏览器前缀写法以及早期的 IE 滤镜写法,这种格式以 .scss 作为扩展名。SassSass 使用 “缩进” 代替 “花括号” 表示属性属于某个选择器,用 “换行” 代替 “分号” 分隔属性,很多人认为这样做比 SCSS 更容易阅读,书写也更快速。缩进格式也可以使用 Sass 的全部功能,只是与 SCSS 相比个别地方采取了不同的表达方式,具体请查看 the indented syntax reference。这种格式以 .sass 作为拓展名。更详细的用法请阅读 SASS 官网文档:DOCUMENTATION团队约定考虑到 SCSS 语法对 CSS 语法友好的兼容性和扩展性,我们在使用 SASS 编写样式的时候,统一使用 SCSS 语法编码格式When running on Ruby 1.9 and later, Sass is aware of the character encoding of documents. Sass follows the CSS spec to determine the encoding of a stylesheet, and falls back to the Ruby string encoding. This means that it first checks the Unicode byte order mark, then the @charset declaration, then the Ruby string encoding. If none of these are set, it will assume the document is in UTF-8.当在 Ruby1.9或更新的版本运行的时候,SASS 能识辨文档的字符编码。SASS 遵循 CSS 规范去确定样式文件的编码,进而转回 Ruby 字符串编码。这意味着SASS编译的时候会首先检测 BOM,然后到 @charset 声明,再到 Ruby 字符串编码,如果以上都没有设置,SASS 会认为文档的编码为 UTF-8团队约定严格遵守上面 “CSS规范” 中的 “编码规范”更多关于 SASS 编码:SASS EncodingsSASS注释规范SASS支持 CSS 标准的多行注释 /* */,同时也支持单行注释 //。多行注释在使用非 Compressed 模式进行编译后的输出文件中会保留下来,单行注释 // 侧会被移除多行注释和单行注释在 SASS 编译后输出的压缩 CSS 文件都会被移除当多行注释内容第一个字符是感叹号 “!” 的时候,即 /*! */,SASS 无论用哪一种编译方式编译注释都会保留注释内容可以加入 SASS 变量团队约定SCSS 文件内全部遵循 CSS 注释规范不使用 /*! */ 注释方式注释内不放 SASS 变量标准的注释规范如下:@charset "UTF-8"; /** * @desc File Info * @author liqinuo * @date 2015-10-10 */ /* Module A ----------------------------------------------------------------*/ .mod_a {} /* module A logo */ .mod_a_logo {} /* module A nav */ .mod_a_nav {} /* Module B ----------------------------------------------------------------*/ .mod_b {} /* module B logo */ .mod_b_logo {} /* module B nav */ .mod_b_nav {}嵌套规范选择器嵌套/* CSS */ .jdc {} body .jdc {} /* SCSS */ .jdc { body & {} } /* CSS */ .jdc {} .jdc_cover {} .jdc_info {} .jdc_info_name {} /* SCSS */ .jdc { &_cover {} &_info { &_name {} } }属性嵌套/* CSS */ .jdc { background-color: red; background-repeat: no-repeat; background-image: url(/img/icon.png); background-position: 0 0; } /* SCSS */ .jdc { background: { color: red; repeat: no-repeat; image: url(/img/icon.png); position: 0 0; } }变量可复用属性尽量抽离为页面变量,易于统一维护// CSS .jdc { color: red; border-color: red; } // SCSS $color: red; .jdc { color: $color; border-color: $color; }混合(mixin)根据功能定义模块,然后在需要使用的地方通过 @include 调用,避免编码时重复输入代码段// CSS .jdc_1 { -webkit-border-radius: 5px; border-radius: 5px; } .jdc_2 { -webkit-border-radius: 10px; border-radius: 10px; } // SCSS @mixin radius($radius:5px) { -webkit-border-radius: $radius; border-radius: $radius; } .jdc_1 { @include radius; //参数使用默认值 } .jdc_2 { @include radius(10px); } // CSS .jdc_1 { background: url(/img/icon.png) no-repeat -10px 0; } .jdc_2 { background: url(/img/icon.png) no-repeat -20px 0; } // SCSS @mixin icon($x:0, $y:0) { background: url(/img/icon.png) no-repeat $x, $y; } .jdc_1 { @include icon(-10px, 0); } .jdc_2 { @include icon(-20px, 0); }占位选择器 %如果不调用则不会有任何多余的 css 文件,占位选择器以 % 标识定义,通过 @extend 调用//scss %borderbox { -webkit-box-sizing: border-box; box-sizing: border-box; } .jdc { @extend %borderbox; }extend 继承// CSS .jdc_1 { font-size: 12px; color: red; } .jdc_2 { font-size: 12px; color: red; font-weight: bold; } // SCSS .jdc_1 { font-size: 12px; color: red; } .jdc_2 { @extend .jdc_1; font-weight: bold; } // 或者 %font_red { font-size: 12px; color: red; } .jdc_1 { @extend %font_red; } .jdc_2 { @extend %font_red; font-weight: bold; }for 循环// CSS .jdc_1 {background-position: 0 -20px;} .jdc_2 {background-position: 0 -40px;} .jdc_3 {background-position: 0 -60px;} // SCSS @for $i from 1 through 3 { .jdc_#{$i} { background-position: 0 (-20px) * $i; } }注意:#{} 是连接符,变量连接使用时需要依赖each 循环// CSS .jdc_list { background-image: url(/img/jdc_list.png); } .jdc_detail { background-image: url(/img/jdc_detail.png); } // SCSS @each $name in list, detail { .jdc_#{$name} { background-image: url(/img/jdc_#{$name}.png); } } // CSS .jdc_list { background-image: url(/img/jdc_list.png); background-color: red; } .jdc_detail { background-image: url(/img/jdc_detail.png); background-color: blue; } // SCSS @each $name, $color in (list, red), (detail, blue) { .jdc_#{$name} { background-image: url(/img/jdc_#{$name}.png); background-color: $color; } }function 函数@function pxToRem($px) { @return $px / 10px * 1rem; } .jdc { font-size: pxToRem(12px); }运算规范运算符之间空出一个空格.jdc { width: 100px - 50px; height: 30px / 5; }注意运算单位,单位同时参与运算,所以 10px 不等于 10,乘除运算时需要特别注意// 正确的运算格式 .jdc { width: 100px - 50px; width: 100px + 50px; width: 100px * 2; width: 100px / 2; }重置样式移动端* { -webkit-tap-highlight-color: transparent; outline: 0; margin: 0; padding: 0; vertical-align: baseline; } body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset, legend, button, input, textarea, th, td { margin: 0; padding: 0; vertical-align: baseline; } img { border: 0 none; vertical-align: top; } i, em { font-style: normal; } ol, ul { list-style: none; } input, select, button, h1, h2, h3, h4, h5, h6 { font-size: 100%; font-family: inherit; } table { border-collapse: collapse; border-spacing: 0; } a { text-decoration: none; color: #666; } body { margin: 0 auto; min-width: 320px; max-width: 640px; height: 100%; font-size: 14px; font-family: -apple-system,Helvetica,sans-serif; line-height: 1.5; color: #666; -webkit-text-size-adjust: 100% !important; text-size-adjust: 100% !important; } input[type="text"], textarea { -webkit-appearance: none; -moz-appearance: none; appearance: none; }PC端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; } h1, h2, h3, h4, h5, h6 { font-size: 100%; font-weight: normal } article, aside, dialog, figure, footer, header, hgroup, nav, section, blockquote { display: block; } ul, ol { list-style: none; } img { border: 0 none; vertical-align: top; } blockquote, q { quotes: none; } blockquote:before, blockquote:after, q:before, q:after { content: none; } table { border-collapse: collapse; border-spacing: 0; } strong, em, i { font-style: normal; font-weight: normal; } ins { text-decoration: underline; } del { text-decoration: line-through; } mark { background: none; } input::-ms-clear { display: none !important; } body { font: 12px/1.5 \5FAE\8F6F\96C5\9ED1, \5B8B\4F53, "Hiragino Sans GB", STHeiti, "WenQuanYi Micro Hei", "Droid Sans Fallback", SimSun, sans-serif; background: #fff; } a { text-decoration: none; color: #333; } a:hover { text-decoration: underline; }媒体查询设备尺寸参考 :Mobile devices媒体查询类型浏览器支持情况:CSS3 Media Queries overview常用查询语句判断设备横竖屏/* 横屏 */ @media all and (orientation :landscape) { } /* 竖屏 */ @media all and (orientation :portrait) { }判断设备宽高/* 设备宽度大于 320px 小于 640px */ @media all and (min-width:320px) and (max-width:640px) { }判断设备像素比/* 设备像素比为 1 */ @media only screen and (-webkit-min-device-pixel-ratio: 1), only screen and (min-device-pixel-ratio: 1) { } /* 设备像素比为 1.5 */ @media only screen and (-webkit-min-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) { } /* 设备像素比为 2 */ @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { }常用设备设置iPhones/* ----------- iPhone 4 and 4S ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) { } /* Portrait */ @media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) { } /* Landscape */ @media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) { } /* ----------- iPhone 5 and 5S ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) { } /* Portrait */ @media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) { } /* Landscape */ @media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) { } /* ----------- iPhone 6 ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) { } /* Portrait */ @media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: portrait) { } /* Landscape */ @media only screen and (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) and (orientation: landscape) { } /* ----------- iPhone 6+ ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) { } /* Portrait */ @media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) and (orientation: portrait) { } /* Landscape */ @media only screen and (min-device-width: 414px) and (max-device-width: 736px) and (-webkit-min-device-pixel-ratio: 3) and (orientation: landscape) { }Galaxy Phones/* ----------- Galaxy S3 ----------- */ /* Portrait and Landscape */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) { } /* Portrait */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait) { } /* Landscape */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape) { } /* ----------- Galaxy S4 ----------- */ /* Portrait and Landscape */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) { } /* Portrait */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) { } /* Landscape */ @media screen and (device-width: 320px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) { } /* ----------- Galaxy S5 ----------- */ /* Portrait and Landscape */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) { } /* Portrait */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) { } /* Landscape */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) { }HTC Phones/* ----------- HTC One ----------- */ /* Portrait and Landscape */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) { } /* Portrait */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait) { } /* Landscape */ @media screen and (device-width: 360px) and (device-height: 640px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape) { }iPads/* ----------- iPad mini ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) { } /* Portrait */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 1) { } /* Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) { } /* ----------- iPad 1 and 2 ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) { } /* Portrait */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 1) { } /* Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) { } /* ----------- iPad 3 and 4 ----------- */ /* Portrait and Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) { } /* Portrait */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: portrait) and (-webkit-min-device-pixel-ratio: 2) { } /* Landscape */ @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 2) { }移动端常用私有属性目前两大主流移动平台为 iOS 和 Android,有不少带 -webkit- 前辍的 CSS 私有属性以及一些 iOS only 属性,当中好些属性在日常需求中经常应用到。WebKit CSS 属性中的一部分已经被包含在 CSS 规范草案中,并且可能成为最后的推荐标准,但目前仍然是试验性的属性,还有一些属性是不规范的属性,它们没有出现在跟踪规范中。-webkit-scrollbar-webkit-scrollbar 是-webkit-私有的伪元素,用于对拥有overflow属性的区域 自定义滚动条的样式。譬如,为了隐藏滚动条,你可以这么做:.scroll::-webkit-scrollbar { width: 0; height: 0; }除了对整个滚动条的控制外,Webkit还提供了控制对滚动条各组成部分的表现渲染的伪元素,甚至具体到滚动条的各种状态行为的伪类。滚动条各块组成表现渲染的伪元素一般而言,滚动条的主要组成部分包括:滚动按钮 — 滚动按钮的夹角则被称为滚动角(corner)。轨道 — 轨道(track)可以进一步分为轨枕(track pieces) 和滑块(thumb)。Webkit则根据滚动条各组成部分,提供了不同的伪元素来自定义样式。::-webkit-scrollbar { /* 1 */ } ::-webkit-scrollbar-button { /* 2 */ } ::-webkit-scrollbar-track { /* 3 */ } ::-webkit-scrollbar-track-piece { /* 4 */ } ::-webkit-scrollbar-thumb { /* 5 */ } ::-webkit-scrollbar-corner { /* 6 */ } ::-webkit-resizer { /* 7 */ }下图则是各伪元素对应的滚动条各部分:::-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等伪类同样在滚动条中适用。为了更好地理解,以下是几个伪元素组合伪类的应用例子:::-webkit-scrollbar-track-piece:start { /\*滚动条上半边或左半边\*/ } ::-webkit-scrollbar-thumb:window-inactive { /\*当焦点不在当前区域滑块的状态\*/ ::-webkit-scrollbar-button:horizontal:decrement:hover { /\*当鼠标在水平滚动条下面的按钮上的状态\*/或者,读者可以去阅读官方例子参考资料:Webkit-Styling Scrollbars自定义浏览器滚动条的样式,打造属于你的滚动条风格-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 可点击脚本的元素,系统会为这些被点击元素加上一个默认的透明色值,该属性可以覆盖该透明值。属性值:颜色值兼容性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:可以用来多行文本的情况下,用省略号“…”隐藏超出范围的文本。属性值:块元素显示的文本的行数兼容性iOSAndriod-webkit-appearance-webkit-appearance 是一个不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。改变按钮和其他控件的外观,使其类似于原生控件。属性值none:去除系统默认 appearance 的样式,常用于 iOS 下移除原生样式button:渲染成 button 的风格checkbox:渲染成 input checkbox 样式的复选框按钮radio:渲染成 radio 的风格…更多属性值参考 mozilla:-webkit-appearance 属性兼容性iOS 2.0及更高版本的Safari浏览器可用Android 尚不明确-webkit-font-smoothing字体平滑,该属性定义文本的平滑属性,但要注意以下说明:非标准属性,不建议用于网页上,这个属性不能保证所有用户都能看到相同效果,这会使网站的字体渲染造成不一致,而此属性的渲染行为日后也有可能会改变属性值none:去掉字体平滑效果,使字体带锯齿antialiased:使字体在像素级别更平滑更轻细subpixel-antialiased:在多数非 Retina 显示设备中字体将会更锐利。注意:以上属性在 Retina 设备上会有明显的效果,在非 Retina 设备上看不出差异兼容性部分高清设备,如 Retina Mac-webkit-backface-visibilitybackface-visibility 在 W3文档 有定义描述定义转换元素的背面是否显示属性值visible:显示(默认值)hidden:隐藏兼容性iOS 2.0 及更高版本的 Safari 浏览器可用大部分 Android-webkit-mask定义多样的蒙板效果属性(缩写属性,类似 margin)使用语法<mask-image> [<mask-repeat> || <mask-attachment> || <mask-position> || <mask-origin> || <mask-clip> || <mask-composite>]* where <mask-position> = [ <percentage> | <length> | left | center | right ] [ <percentage> | <length> | top | center | bottom ]?默认值:-webkit-mask: none repeat scroll 0% 0% padding border add;属性值:为元素设置蒙板图片,蒙板图片会根据图片的透明区域对元素可视部分进行裁剪:图片链接作为蒙板图片:渐变函数 -webkit-gradient 作为蒙板图片none:去掉蒙板图片:定义蒙板图片是否平铺或平铺的方式repeat:默认值,水平和垂直方向平铺repeat-x:水平方向平铺repeat-y:垂直方向平铺no-repeat:不平铺:如果 -webkit-mask-image 属性有设置,attachment 决定该图片是否相对视窗固定或随着其容器滚动scroll:默认值,随容器滚动fixed:相地视窗固定:定义蒙板图片的初始位置,书写格式类似 background-position—-<mask-position>[, <mask-position>]*leftrightcenter:定义蒙板图片定位相对起点,与 webkit-mask-position 属性相关。当 -webkit-mask-attachment:fixed 的时候,该属性不生效。padding:默认值,蒙板定位相对边距border:蒙板定位相对边框content:蒙板定位相对元素盒子内容:如果 -webkit-mask-image 属性有设置,-webkit-mask-clip 将定义蒙板图片的裁剪区域border:默认值,蒙板图片延伸到容器的边框padding:蒙板图片延伸到容器的边距content:蒙板图片裁剪到元素盒子内容范围text:蒙板图片裁剪到元素文本范围:定义蒙板图片重合的裁剪显示方式add:默认值,图片重合不裁剪subtract:去掉层级低的图形以及图片重合部分图形,只留层级高非重合部分图形intersect:只留重合部分图形exclude:只去掉重合部分图形有关属性更详细描述请参考:w3 - css-maskingMDN - -webkit-mask携程 UED - -webkit-mask兼容性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 共用。属性值:长度单位:颜色值兼容性iOS 2.0 及更高版本Safari 3.0 及更高版本安卓尚不明确-webkit-text-fill-color定义文本填充,一般与文本描边属性 -webkit-text-stroke 共用。属性值:颜色值currentcolor:元素 color 属性值-webkit-activelink:链接被点击时系统的默认颜色更多属性值参考:Safari CSS Reference -webkit-text-fill-color兼容性iOS 2.0 及更高版本Safari 3.0 及更高版本安卓尚不明确-webkit-text-size-adjust定义 iOS Safari 网页文本大小调整属性属性值:百分比值,字体显示调整值auto:字体自动调整none:字体不能自动调整兼容性iOS 1.0 及更高版本Safari on iOS only安卓尚不明确-webkit-marquee定义滚动文本内容属性(缩写属性,类似margin)。使用语法-webkit-marquee: direction increment repetition style speed属性值:滚动方向ahead:从下到上滚动auto:默认滚动方向backwards:从右到左滚动down:从上到下滚动forwards:从左到右滚动left:从右到左滚动reverse:从上到下滚动right:从左到右滚动up:从下到上滚动:每次移动的距离[ | ]large:距离常量medium:距离常量small:距离常量:文字滚动的重复次数非负整数infinite:无限次\<style\>:文字滚动的方式\<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%,不接受负值关于 -webkit-filter 与 -webkit-backdrop-filter 的属性对比可以参考:What’s New in Safari 9.0 - backdrop-filter兼容性iOS 8.0 及更高版本Safari 8.0 及更高版本Android 4.4 及更高版本-webkit-backdrop-filter背景滤镜属性可以让元素的背景或元素层级以下的元素加上滤镜效果属性值blur(<length>):模糊,原始效果值为 0px,不接受负值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%,不接受负值关于 -webkit-filter 与 -webkit-backdrop-filter 的属性对比可以参考:What’s New in Safari 9.0兼容性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 规则font-family: -apple-system , sans-serif;让系统智能选择适配操作系统的字体,添加 -apple-system 可以使字体变得更圆润锐利。关于 -apple-system 更详细的介绍可以参考:What’s New in Safari 9.0兼容性iOS 9.0 及更高版本Safari 9.0 及更高版本iOS / OS X only更多 WebKit CSS 属性更多 -webkit- CSS 属性介绍请参考:MDN文档 - Webkit Extensions携程 UED - webkitcssHTML/CSS文件命名确保文件命名总是以字母开头而不是数字,且字母一律小写,以下划线连接且不带其他标点符号,如:<!-- HTML --> jdc.html jdc_list.html jdc_detail.html <!-- SASS --> jdc.scss jdc_list.scss jdc_detail.scssClassName命名ClassName的命名应该尽量精短、明确,必须以字母开头命名,且全部字母为小写,单词之间统一使用下划线 “_” 连接命名原则基于姓氏命名法(继承 + 外来),如下图:祖先模块不能出现下划线,除了是全站公用模块,如 mod_ 系列的命名:推荐:<div class="modulename"> <div class="modulename_info"> <div class="modulename_son"></div> <div class="modulename_son"></div> ... </div> </div> <!-- 这个是全站公用模块,祖先模块允许直接出现下划线 --> <div class="mod_info"> <div class="mod_info_son"></div> <div class="mod_info_son"></div> ... </div>不推荐:<div class="modulename_info"> <div class="modulename_info_son"></div> <div class="modulename_info_son"></div> ... </div>在子孙模块数量可预测的情况下,严格继承祖先模块的命名前缀<div class="modulename"> <div class="modulename_cover"></div> <div class="modulename_info"></div> </div>当子孙模块超过4级或以上的时候,可以考虑在祖先模块内具有识辨性的独立缩写作为新的子孙模块推荐:<div class="modulename"> <div class="modulename_cover"></div> <div class="modulename_info"> <div class="modulename_info_user"> <div class="modulename_info_user_img"> <img src="" alt=""> <!-- 这个时候 miui 为 modulename_info_user_img 首字母缩写--> <div class="miui_tit"></div> <div class="miui_txt"></div> ... </div> </div> <div class="modulename_info_list"></div> </div> </div>不推荐:<div class="modulename"> <div class="modulename_cover"></div> <div class="modulename_info"> <div class="modulename_info_user"> <div class="modulename_info_user_img"> <img src="" alt=""> <div class="modulename_info_user_img_tit"></div> <div class="modulename_info_user_img_txt"></div> ... </div> </div> <div class="modulename_info_list"></div> </div> </div>模块命名全站公共模块:以 mod_ 开头<div class="mod_yours"></div>业务公共模块:以 业务名_mod_ 开头<div class="paipai_mod_yours"></div>常用命名推荐注意:ad、banner、gg、guanggao 等有机会和广告挂勾的字眠不建议直接用来做ClassName,因为有些浏览器插件(Chrome的广告拦截插件等)会直接过滤这些类名,因此<div class="ad"></div>这种广告的英文或拼音类名不应该出现另外,敏感不和谐字眼也不应该出现,如:<div class="fuck"></div> <div class="jer"></div> <div class="sm"></div> <div class="gcd"></div> <div class="ass"></div> <div class="KMT"></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容器,包,一般用于最外层JavaScript语言规范JavaScript 是一种客户端脚本语言,这里列出了编写 JavaScript 时需要遵守的规则。类型原始类型: 存取原始类型直接作用于值本身布尔类型Null 类型Undefined 类型数字类型BigInt 类型字符串类型符号类型 Symbolconst foo = 1 let bar = foo bar = 9 console.log(foo, bar) // 1, 9复杂类型: 访问复杂类型作用于值的引用objectarrayfunctionconst foo = [1, 2, 3] const bar = foo bar[0] = 9 console.log(foo[0], bar[0]) // 9, 9引用请记得 const 和 let 都是块级作用域,var 是函数级作用域// const and let only exist in the blocks they are defined in. { let a = 1 const b = 1 } console.log(a) // ReferenceError console.log(b) // ReferenceError对所有引用都使用 const,不要使用 var,eslint: prefer-const, no-const-assign原因:这样做可以确保你无法重新分配引用,以避免出现错误和难以理解的代码// bad var a = 1 var b = 2 // good const a = 1 const b = 2如果引用是可变动的,使用 let 代替 var,eslint: no-var原因:let 是块级作用域的,而不像 var 属于函数级作用域// bad var count = 1 if (count < 10) { count += 1 } // good let count = 1 if (count < 10) { count += 1 }对象请使用字面量值创建对象,eslint: no-new-object// bad const a = new Object{} // good const a = {}别使用保留字作为对象的键值,这样在 IE8 下不会运行// bad const a = { default: {}, // default 是保留字 common: {} } // good const a = { defaults: {}, common: {} }当使用动态属性名创建对象时,请使用对象计算属性名来进行创建原因:因为这样做就可以让你在一个地方定义所有的对象属性function getKey(k) { return `a key named ${k}` } // bad const obj = { id: 5, name: 'San Francisco' }; obj[getKey('enabled')] = true // good const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true };请使用对象方法的简写方式,eslint: object-shorthand// bad const item = { value: 1, addValue: function (val) { return item.value + val } } // good const item = { value: 1, addValue (val) { return item.value + val } }请使用对象属性值的简写方式,eslint: object-shorthand原因:这样更简短且描述更清楚const job = 'FrontEnd' // bad const item = { job: job } // good const item = { job }将简写的对象属性分组后统一放到对象声明的开头原因:这样更容易区分哪些属性用了简写的方式const job = 'FrontEnd' const department = 'JDC' // bad const item = { sex: 'male', job, age: 25, department } // good const item = { job, department, sex: 'male', age: 25 }只对非法标识符的属性使用引号,eslint: quote-props原因:因为通常来说我们认为这样主观上会更容易阅读,这样会带来代码高亮上的提升,同时也更容易被主流 JS 引擎优化// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5 } // good const good = { foo: 3, bar: 4, 'data-blah': 5 }不要直接使用Object.prototype的方法, 例如hasOwnProperty,propertyIsEnumerable和isPrototypeOf方法,eslint:no-prototype-builtins原因:这些方法可能会被对象自身的同名属性覆盖 - 比如 { hasOwnProperty: false } 或者对象可能是一个 null 对象(Object.create(null))// bad console.log(object.hasOwnProperty(key)) // good console.log(Object.prototype.hasOwnProperty.call(object, key)) // best const has = Object.prototype.hasOwnProperty // cache the lookup once, in module scope. console.log(has.call(object, key)) /* or */ import has from 'has' // https://www.npmjs.com/package/has console.log(has(object, key))优先使用对象展开运算符 ... 来做对象浅拷贝而不是使用 Object.assign,使用对象剩余操作符来获得一个包含确定的剩余属性的新对象// very bad const original = { a: 1, b: 2 } const copy = Object.assign(original, { c: 3 }) // this mutates `original` ಠ_ಠ delete copy.a // so does this // bad const original = { a: 1, b: 2 } const copy = Object.assign({}, original, { c: 3 }) // copy => { a: 1, b: 2, c: 3 } // good const original = { a: 1, b: 2 } const copy = { ...original, c: 3 } // copy => { a: 1, b: 2, c: 3 } const { a, ...noA } = copy // noA => { b: 2, c: 3 }数组请使用字面量值创建数组,eslint: no-array-constructor// bad const items = new Array() // good const items = []向数组中添加元素时,请使用 push 方法const items = [] // bad items[items.length] = 'test' // good items.push('test')使用展开运算符 ... 复制数组// bad const items = [] const itemsCopy = [] const len = items.length let i // bad for (i = 0; i < len; i++) { itemsCopy[i] = items[i] } // good itemsCopy = [...items]把一个可迭代的对象转换为数组时,使用展开运算符 ... 而不是 Array.fromconst foo = document.querySelectorAll('.foo') // good const nodes = Array.from(foo) // best const nodes = [...foo]使用 Array.from 来将一个类数组对象转换为数组const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 } // bad const arr = Array.prototype.slice.call(arrLike) // good const arr = Array.from(arrLike)遍历迭代器进行映射时使用 Array.from 代替扩展运算符 ..., 因为这可以避免创建中间数组// bad const baz = [...foo].map(bar) // good const baz = Array.from(foo, bar)使用数组的 map 等方法时,请使用 return 声明,如果是单一声明语句的情况,可省略 return// good [1, 2, 3].map(x => { const y = x + 1 return x * y }) // good [1, 2, 3].map(x => x + 1) // bad const flat = {} [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { const flatten = memo.concat(item) flat[index] = flatten }) // good const flat = {} [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => { const flatten = memo.concat(item) flat[index] = flatten return flatten }) // bad inbox.filter((msg) => { const { subject, author } = msg if (subject === 'Mockingbird') { return author === 'Harper Lee' } else { return false } }) // good inbox.filter((msg) => { const { subject, author } = msg if (subject === 'Mockingbird') { return author === 'Harper Lee' } return false })如果一个数组有多行则要在数组的开括号后和闭括号前使用新行// bad const arr = [ [0, 1], [2, 3], [4, 5] ] const objectInArray = [{ id: 1 }, { id: 2 }] const numberInArray = [ 1, 2 ] // good const arr = [[0, 1], [2, 3], [4, 5]] const objectInArray = [ { id: 1 }, { id: 2 } ] const numberInArray = [ 1, 2 ]解构赋值当需要使用对象的多个属性时,请使用解构赋值,eslint: prefer-destructuring愿意:解构可以避免创建属性的临时引用// bad function getFullName (user) { const firstName = user.firstName const lastName = user.lastName return `${firstName} ${lastName}` } // good function getFullName (user) { const { firstName, lastName } = user return `${firstName} ${lastName}` } // better function getFullName ({ firstName, lastName }) { return `${firstName} ${lastName}` }当需要使用数组的多个值时,请同样使用解构赋值,eslint: prefer-destructuringconst arr = [1, 2, 3, 4] // bad const first = arr[0] const second = arr[1] // good const [first, second] = arr函数需要回传多个值时,请使用对象的解构,而不是数组的解构原因:可以非破坏性地随时增加或者改变属性顺序// bad function doSomething () { return [top, right, bottom, left] } // 如果是数组解构,那么在调用时就需要考虑数据的顺序 const [top, xx, xxx, left] = doSomething() // good function doSomething () { return { top, right, bottom, left } } // 此时不需要考虑数据的顺序 const { top, left } = doSomething()字符串字符串统一使用单引号的形式 '',eslint: quotes// bad const department = "JDC" // good const department = 'JDC'字符串太长的时候,请不要使用字符串连接符换行 \,而是使用 +const str = '凹凸实验室 凹凸实验室 凹凸实验室' + '凹凸实验室 凹凸实验室 凹凸实验室' + '凹凸实验室 凹凸实验室'程序化生成字符串时,请使用模板字符串,eslint: prefer-template template-curly-spacingconst test = 'test' // bad const str = ['a', 'b', test].join() // bad const str = 'a' + 'b' + test // good const str = `ab${test}`不要对字符串使用eval(),会导致太多漏洞, eslint: no-eval不要在字符串中使用不必要的转义字符, eslint: no-useless-escape// bad const foo = '\'this\' \i\s \"quoted\"' // good const foo = '\'this\' is "quoted"' const foo = `my name is '${name}'`函数不要使用Function构造函数创建函数, eslint: no-new-func原因:此方式创建函数和对字符串使用 eval() 一样会产生漏洞// bad const add = new Function('a', 'b', 'return a + b') // still bad const subtract = Function('a', 'b', 'return a - b')在函数签名中使用空格,eslint: space-before-function-paren space-before-blocksconst f = function(){} const g = function (){} const h = function() {} // good const x = function b () {} const y = function a () {}使用具名函数表达式而非函数声明,eslint: func-style原因:这样做会导致函数声明被提升,这意味着很容易在文件中定义此函数之前引用它,不利于可读性和可维护性。如果你发现函数定义既庞大又复杂以至于不能理解文件的其他部分,或许你应该将它拆分成模块!别忘记要显式命名表达式,而不用管名字是否是从包含的变量(通常出现在现代浏览器中或者使用 Babel 编译器的时候)中推断的。这样会消除错误调用堆栈中的任何假设。 (讨论)// bad function foo () { // ... } // bad const foo = function () { // ... } // good // lexical name distinguished from the variable-referenced invocation(s) const short = function longUniqueMoreDescriptiveLexicalFoo () { // ... }用圆括号包裹自执行匿名函数,eslint:wrap-iife原因:一个立即执行匿名函数表达式是一个单一的单元,将其及其调用括号包装在括号中,能够清楚地表达这一点。注意,在到处都是模块的世界中几乎不需要 IIFE。// immediately-invoked function expression (IIFE) (function () { console.log('Welcome to the Internet. Please follow me.') }())不要在非函数代码块(if , while 等)中声明函数,eslint:no-loop-func// bad if (isUse) { function test () { // do something } } // good let test if (isUse) { test = () => { // do something } }不要将参数命名为 arguments,会导致该参数的优先级高于每个函数作用域内原先存在的 arguments 对象// bad function foo (name, options, arguments) { // ... } // good function foo (name, options, args) { // ... }不要使用 arguments,使用 剩余运算符 ...arguments 只是一个类数组,而 ... 是一个真正的数组// bad function test () { const args = Array.prototype.slice.call(arguments) return args.join('') } // good function test (...args) { return args.join('') }使用参数默认值语法而不是修改函数参数// really bad function handleThings (opts) { // No! We shouldn't mutate function arguments. // Double bad: if opts is falsy it'll be set to an object which may // be what you want but it can introduce subtle bugs. opts = opts || {} // ... } // still bad function handleThings (opts) { if (opts === void 0) { opts = {} } // ... } // good function handleThings (opts = { }) { // ... }避免参数默认值的副作用let b = 1 // bad function count (a = b++) { console.log(a) } count() // 1 count() // 2 count(3) // 3 count() // 3将参数默认值放在最后// bad function handleThings (opts = {}, name) { // ... } // good function handleThings (name, opts = {}) { // ... }不要更改参数,eslint: no-param-reassign原因:操作作为参数传入的对象可能在原始调用中造成意想不到的变量副作用// bad function f1 (obj) { obj.key = 1 } // good function f2 (obj) { const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1 }不要给参数重新赋值,eslint: no-param-reassign原因:参数重新赋值可能会导致无法预期的行为,尤其是当操作 arguments 对象时,也可能导致优化问题,尤其是在 V8 引擎中// bad function f1 (a) { a = 1 } function f2 (a) { if (!a) { a = 1 } } // good function f3 (a) { const b = a || 1 } function f4 (a = 1) { }调用可变参数函数时建议使用展开运算符 ...., eslint: prefer-spread原因:显然你无需使用上下文,很难结合 new 和 apply// bad const x = [1, 2, 3, 4, 5] console.log.apply(console, x) // good const x = [1, 2, 3, 4, 5] console.log(...x) // bad new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5])) // good new Date(...[2016, 8, 5])箭头函数当你必须使用函数表达式(传递匿名函数)时,使用箭头函数标记. eslint: prefer-arrow-callback, arrow-spacing原因:它将创建在 this 上下文中执行的函数版本,通常是您想要的,并且语法更简洁如果您有一个相当复杂的函数,则可以将该逻辑移到其自己的命名函数表达式中// bad [1, 2, 3].map(function (x) { const y = x + 1 return x * y }) // good [1, 2, 3].map((x) => { const y = x + 1 return x * y })如果函数体只包含一条没有副作用的返回表达式的语句,可以省略花括号并使用隐式的 return, 否则保留花括号并使用 return 语句,eslint: arrow-parens, arrow-body-style// bad [1, 2, 3].map(number => { const nextNumber = number + 1 `A string containing the ${nextNumber}.` }) // good [1, 2, 3].map(number => `A string containing the ${number}.`) // good [1, 2, 3].map((number) => { const nextNumber = number + 1 return `A string containing the ${nextNumber}.` }) // good [1, 2, 3].map((number, index) => ({ index: number })) // No implicit return with side effects function foo(callback) { const val = callback() if (val === true) { // Do something if callback returns true } } let bool = false // bad foo(() => bool = true) // good foo(() => { bool = true })一旦表达式跨多行,使用圆括号包裹以便更好阅读// bad ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ) // good ['get', 'post', 'put'].map(httpMethod => ( Object.prototype.hasOwnProperty.call( httpMagicObjectWithAVeryLongName, httpMethod ) ))函数如果只接收一个参数并且没使用用花括号,则省略圆括号,否则为了清晰明确则使用圆括号包裹参数,注意:总是使用圆括号也是可以接受的,eslint 中的 “always” 选项,eslint: arrow-parens// bad [1, 2, 3].map((x) => x * x) // good [1, 2, 3].map(x => x * x) // good [1, 2, 3].map(number => ( `A long string with the ${number}. It’s so long that we’ve broken it ` + 'over multiple lines!' )) // bad [1, 2, 3].map(x => { const y = x + 1 return x * y }) // good [1, 2, 3].map((x) => { const y = x + 1 return x * y })类&构造函数使用 class,避免直接操作 prototype// bad function Queue (contents = []) { this._queue = [..contents] } Queue.prototype.pop = function () { const value = this._queue[0] this._queue.splice(0, 1) return value } // good class Queue { constructor (contents = []) { this._queue = [...contents] } pop () { const value = this._queue[0] this._queue.splice(0, 1) return value } }使用 extends 来实现继承原因:这是一个不会破坏 instanceof 的内建实现原型式继承的方式// bad const inherits = require('inherits') function PeekableQueue(contents) { Queue.apply(this, contents) } inherits(PeekableQueue, Queue) PeekableQueue.prototype.peek = function () { return this.queue[0] } // good class PeekableQueue extends Queue { peek () { return this.queue[0] } }如果未声明构造函数,则类会有一个默认的构造函数,没必要用空的构造函数或者将其委托给父类,eslint: no-useless-constructor// bad class Jedi { constructor () {} getName() { return this.name } } // bad class Rey extends Jedi { constructor (...args) { super(...args) } } // good class Rey extends Jedi { constructor (...args) { super(...args) this.name = 'Rey' } }避免类成员重复,eslint: no-dupe-class-members原因:重复的类成员声明会默认使用最后声明的,通常会导致 bug// bad class Foo { bar () { return 1 } bar () { return 2 } } // good class Foo { bar () { return 1 } } // good class Foo { bar () { return 2 } }模块使用标准的 ES6 模块语法 import 和 export原因:模块是未来,让我们现在开始使用未来的特性// bad const util = require('./util') module.exports = util // good import Util from './util' export default Util // better import { Util } from './util' export default Util不要使用 import 的通配符 *,这样可以确保你只有一个默认的 export// bad import * as Util from './util' // good import Util from './util'同个文件每个模块只允许 import 一次,有多个 import 请书写在一起,eslint: no-duplicate-imports原因:这样可以让代码更易于维护// bad import foo from 'foo' // … some other imports … // import { named1, named2 } from 'foo' // good import foo, { named1, named2 } from 'foo' // good import foo, { named1, named2 } from 'foo'将所有 import 语句放在文件最前方,eslint: import/imports-first// bad import foo from 'foo' foo.init() import bar from 'bar' // good import foo from 'foo' import bar from 'bar' foo.init()多行导入应该像多行数组和对象文字一样缩进// bad import { longNameA, longNameB, longNameC, longNameD, longNameE } from 'path' // good import { longNameA, longNameB, longNameC, longNameD, longNameE } from 'path'在模块 import 声明中禁止使用 Webpack 的 loader 语法,eslint: import/no-webpack-loader-syntax// bad import fooSass from 'css!sass!foo.scss' import barCss from 'style!css!bar.css' // good import fooSass from 'foo.scss' import barCss from 'bar.css'迭代器不要使用 iterators,建议使用 JS 更高优先级的函数代替 for-in 或 for-of 循环,除非迫不得已,eslint: no-iterator no-restricted-syntaxconst numbers = [1, 2, 3, 4, 5] // bad let sum = 0 for (let num of numbers) { sum += num } // good let sum = 0 numbers.forEach(num => sum += num) // better const sum = numbers.reduce((total, num) => total + num, 0)生成器现阶段请不要使用生成器 generator原因:因为不能很好地翻译成 ES5 代码对象属性使用 . 来访问对象属性const joke = { name: 'haha', age: 28 } // bad const name = joke['name'] // good const name = joke.name当访问的属性是变量时使用 []const luke = { jedi: true, age: 28, } function getProp (prop) { return luke[prop] } const isJedi = getProp('jedi')变量声明声明变量时,请使用 const、let 关键字,如果没有写关键字,变量就会暴露在全局上下文中,这样很可能会和现有变量冲突,另外,也很难明确该变量的作用域是什么。这里推荐使用 const 来声明变量,我们需要避免全局命名空间的污染。eslint: no-undef prefer-const// bad demo = new Demo() // good const demo = new Demo()将所有的 const 和 let 分组// bad let a const b let c const d let e // good const b const d let a let c let e变量不要进行链式赋值原因:变量链式赋值会创建隐藏的全局变量// bad (function example() { // JavaScript interprets this as // let a = ( b = ( c = 1 ) ); // The let keyword only applies to variable a; variables b and c become // global variables. let a = b = c = 1 }()) console.log(a) // throws ReferenceError console.log(b) // 1 console.log(c) // 1 // good (function example() { let a = 1 let b = a let c = a }()) console.log(a) // throws ReferenceError console.log(b) // throws ReferenceError console.log(c) // throws ReferenceError // the same applies for `const`不允许出现未被使用的变量,eslint: no-unused-vars原因:声明但未被使用的变量通常是不完全重构犯下的错误.这种变量在代码里浪费空间并会给读者造成困扰// bad var some_unused_var = 42 // Write-only variables are not considered as used. var y = 10 y = 5 // A read for a modification of itself is not considered as used. var z = 0 z = z + 1 // Unused function arguments. function getX (x, y) { return x } // good function getXPlusY (x, y) { return x + y } const x = 1 const y = a + 2 alert(getXPlusY(x, y)) // 'type' is ignored even if unused because it has a rest property sibling. // This is a form of extracting an object that omits the specified keys. const { type, ...coords } = data // 'coords' is now the 'data' object without its 'type' property.Hoistingvar 存在变量提升的情况,即 var 声明会被提升至该作用域的顶部,但是他们的赋值并不会。而 const 和 let 并不存在这种情况,他们被赋予了 Temporal Dead Zones, TDZ, 了解 typeof 不再安全很重要function 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 }匿名函数的变量名会提升,但函数内容不会function example () { console.log(anonymous) // => undefined anonymous() var anonymous = function () { console.log('test') } }命名的函数表达式的变量名会被提升,但函数名和函数函数内容并不会function 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, 否则是trueif ([0] && []) { // true // 数组(即使是空数组)也是对象,对象等于true ### 分号我们遵循 Standard 的规范,不使用分号。关于应不应该使用分号的讨论有很多,本规范认为非必要的时候,应该不使用分号,好的 JS 程序员应该清楚场景下是一定要加分号的,相信你也是名好的开发者。// bad const test = 'good'; (function () { const str = 'hahaha'; })() // good const test = 'good' ;(() => { const str = 'hahaha' })();标准特性为了代码的可移植性和兼容性,我们应该最大化的使用标准方法,例如优先使用 string.charAt(3) 而不是 string[3]eval()由于 eval 方法比较 evil,所以我们约定禁止使用该方法with() {}由于 with 方法会产生神奇的作用域,所以我们也是禁止使用该方法的修改内置对象的原型不要修改内置对象,如 Object 和 Array编码规范统一团队的编码规范,有助于代码的维护。本章是传统意义上的 Style Guideline,目的是统一一些相对主观化的代码风格。单行代码块在单行代码块中使用空格不推荐function foo () {return true} if (foo) {bar = 0}推荐function foo () { return true } if (foo) { bar = 0 }大括号风格在编程过程中,大括号风格与缩进风格紧密联系,用来描述大括号相对代码块位置的方法有很多。在 JavaScript 中,主要有三种风格,如下:One True Brace Styleif (foo) { bar() } else { baz() }Stroustrupif (foo) { bar() } else { baz() }Allmanif (foo) { bar() } else { baz() }我们团队约定使用 One True Brace Style 风格变量命名当命名变量时,主流分为驼峰式命名(constiableName)和下划线命名(constiable_name)两大阵营。团队约定使用驼峰式命名拖尾逗号在 ECMAScript5 里面,对象字面量中的拖尾逗号是合法的,但在 IE8(非 IE8 文档模式)下,当出现拖尾逗号,则会抛出错误。拖尾逗号的例子:const foo = { name: 'foo', age: '22', }拖尾逗号的好处是,简化了对象和数组添加或删除元素,我们只需要修改新增的行即可,并不会增加差异化的代码行数。因为拖尾逗号有好也有不好,所以团队约定允许在最后一个元素或属性与闭括号 ] 或 } 在不同行时,可以(但不要求)使用拖尾逗号。当在同一行时,禁止使用拖尾逗号。逗号空格逗号前后的空格可以提高代码的可读性,团队约定在逗号后面使用空格,逗号前面不加空格。不推荐const foo = 1,bar = 2 const foo = 1 , bar = 2 const foo = 1 ,bar = 2推荐const foo = 1, bar = 2逗号风格逗号分隔列表时,在 JavaScript 中主要有两种逗号风格:标准风格,逗号放置在当前行的末尾逗号前置风格,逗号放置在下一行的开始位置团队约定使用标准风格不推荐const foo = 1 , bar = 2const foo = 1, bar = 2const foo = ['name' , 'age'] *推荐* const foo = 1,bar = 2 const foo = ['name', 'age'] ### 计算属性的空格 团队约定在对象的计算属性内,禁止使用空格 *不推荐* obj['foo' ]obj[ 'foo']obj[ 'foo' ] *推荐* obj['foo'] ### 拖尾换行 在非空文件中,存在拖尾换行是一个常见的 `UNIX` 风格,它的好处是可以方便在串联和追加文件时不会打断 `Shell` 的提示。在日常的项目中,保留拖尾换行的好处是,可以减少版本控制时的代码冲突。 *不推荐* function func () { // do something} *推荐* function func () { // do something} // 此处是新的一行 > 可以通过 .editorconfig 添加 EOL ### 函数调用 为了避免语法错误,团队约定在函数调用时,禁止使用空格 *不推荐* fn ()fn() *推荐* fn() ### 缩进 代码保持一致的缩进,是作为工程师的职业素养。但缩进用两个空格,还是四个空格,是用 `Tab` 还是空格呢?这样的争论太多了,也得不出答案。本规范结合了市面上优秀的开源项目,姑且约定使用 `空格` 来缩进,而且缩进使用两个空格。 那是不是不能使用 `Tab` 进行缩进了?我们可以通过配置 `.editorconfig` ,将 `Tab` 自动转换为空格。 ### 对象字面量的键值缩进 团队约定对象字面量的键和值之间不能存在空格,且要求对象字面量的冒号和值之间存在一个空格 *不推荐* const obj = { 'foo' : 'haha' } *推荐* const obj = { 'foo': 'haha' } ### 构造函数首字母大写 在 JavaScript 中 `new` 操作符用来创建某个特定类型的对象的一个实例,该类型的对象是由一个构造函数表示的。由于构造函数只是常规函数,唯一区别是使用 `new` 来调用。所以我们团队约定构造函数的首字母要大小,以此来区分构造函数和普通函数。 *不推荐* const fooItem = new foo() *推荐* const fooItem = new Foo() ### 构造函数的参数 在 JavaScript 中,通过 `new` 调用构造函数时,如果不带参数,可以省略后面的圆括号。但这样会造成与整体的代码风格不一致,所以团队约定使用圆括号 *不推荐* const person = new Person *推荐* const person = new Person() ### 链式调用 链式调用如果放在同一行,往往会造成代码的可读性差,但有些时候,短的链式调用并不会影响美观。所以本规范约定一行最多只能有四个链式调用,超过就要求换行。 ### 空行 空白行对于分离代码逻辑有帮助,但过多的空行会占据屏幕的空间,影响可读性。团队约定最大连续空行数为 2 *不推荐* const a = 1const b = 2 *推荐* const a = 1const b = 2 ### 链式赋值 链式赋值容易造成代码的可读性差,所以团队约定禁止使用链式赋值 *不推荐* const a = b = c = 1 *推荐* const a = 1const b = 1const c = 1 ### 变量声明 JavaScript 允许在一个声明中,声明多个变量。团队约定在声明变量时,一个声明只能有一个变量 *不推荐* const a, b, c *推荐* const aconst bconst c ### 分号 JavaScript 在所有类 C 语言中是比较独特的,它不需要在每个语句的末尾有分号。在很多情况下,JavaScript 引擎可以确定一个分号应该在什么位置然后自动添加它。此特征被称为 自动分号插入 (ASI),被认为是 JavaScript 中较为有争议的特征。 团队中对于是否应该使用分号,也有许多争论,本规范推荐不使用分号,因为我们认为好的工程师应该知道什么时候该加,什么时候不该加。 相关参考 :[semi](http://eslint.org/docs/rules/semi) ### 代码块空格 一致性是任何风格指南的重要组成部分。虽然在哪里放置块的开括号纯属个人偏好,但在整个项目中应该保持一致。不一致的风格将会分散读者阅读代码的注意力。 > 团队约定代码块前要添加空格 *不推荐* if (a){ b()}function a (){} *推荐* if (a) { b()}function a () {} ### 函数声明的空格 当格式化一个函数,函数名或 function 关键字与左括号之间允许有空白。命名函数要求函数名和 function 关键字之间有空格,但是匿名函数要求不加空格。 > 团队约定函数括号前要加空格 *不推荐* function func(x) { // ...} *推荐* function func (x) { // ...} ### 操作符的空格 团队约定操作符前后都需要添加空格 *不推荐* const sum = 1+2 *推荐* const sum = 1 + 2 ### BOM Unicode 字节顺序标记 (BOM) 用来指定代码单元是高字节序还是低字节序。也就是说,是高位在前还是低位在前。UTF-8 不需要 BOM 来表明字节顺序,因为单个字节并不影响字节顺序。 相信不少同学遇到过 BOM 的坑,这里不多说了,切记不要使用 windows 的记事本改代码! # React&JSX 书写规范 > 本规范基本基于标准的 JavaScript 语法规范 ### 基本规则 - 每个文件只包含一个 React 类组件 - 但是多个函数式组件可以放到一个文件中,eslint: [react/no-multi-comp](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless) - 一般使用 JSX 语法 - 除非是在非 JSX 文件中初始化应用,否则不要使用 `React.createElement` ### 命名规范 - 组件文件扩展名 如果使用 JavaScript,则文件扩展名为 `.js`;如果使用 `TypeScript`,则文件扩展名为 `.tsx` - 组件文件名 如果是组件文件,则使用 PascalCase,如 `MyComponent.js` 如果组件是一个目录,则组件主入口命名为 `index`,如 `index.js` - 引用命名 React 组件使用 PascalCase,组件实例使用 CamelCase,eslint: [react/jsx-pascal-case](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-pascal-case.md) // badimport reservationCard from './ReservationCard'// goodimport ReservationCard from './ReservationCard'// badconst ReservationItem = // goodconst reservationItem = - 组件命名 使用文件名作为组件名字,例如, `ReservationCard.js` 应该包含名为 `ReservationCard` 的引用,然而对于文件夹中的根组件, 使用 `index.js` 作为文件名,使用文件夹的名字作为组件的名字 // badimport Footer from './Footer/Footer'// badimport Footer from './Footer/index'// goodimport Footer from './Footer' - 组件属性名 React DOM 使用小驼峰式命名法来定义属性的名称,而不使用 HTML 属性名称的命名约定,例如 ``` ### Class Component VS Functional Component 只允许使用 `Class Component` 和 `Functional Component` 两种形态来书写组件,建议尽量使用函数式组件配合 Hooks 来进行开发 ### 对齐 遵循以下JSX语法的对齐风格,eslint: [react/jsx-closing-bracket-location](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) ```react // bad // good // if props fit in one line then keep it on the same line // children get indented normally // bad {showButton && } // bad { showButton && } // good {showButton && ( )} // good {showButton && ``` ### 空格 - 自闭合的标签前要加一个空格,eslint: [no-multi-spaces](https://eslint.org/docs/rules/no-multi-spaces), [react/jsx-tag-spacing](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md) ```react // bad // very bad // bad // good ``` - 不要在 JSX 的花括号里边加空格,eslint: [react/jsx-curly-spacing](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md) ```react // bad // good ``` ### 引号 JSX 属性要使用单引号,与其他普通 JS 保持一致 ```react // bad // good // bad // good ``` ### 属性 - 属性名使用 CamelCase ```react // bad // good ``` - 当属性值为true时可以省略, eslint: [react/jsx-boolean-value](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md) ``` // bad // good // good ``` - 避免使用数组的索引作为 key 属性值, 建议使用稳定的ID,eslint: [react/no-array-index-key](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-array-index-key.md) > 原因:不使用稳定的 ID 会对性能产生副作用并且组件状态会出问题,是一种[反模式](https://medium.com/@robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318) ```react // bad {todos.map((todo, index) => )} // good {todos.map(todo => ( ))} ``` - 为所有的非必需属性定义使用 defaultProps 明确的默认值 ``` // bad function SFC ({ foo, bar, children }) { return {foo}{bar}{children}}SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node}// goodfunction SFC ({ foo, bar, children }) { return {foo}{bar}{children}}SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node}SFC.defaultProps = { bar: '', children: null} ### Refs 避免使用字符串引用,请使用回调函数作为引用,eslint: [react/no-string-refs](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-string-refs.md) // bad<Foo ref='myRef'/>// good<Foo ref={ref => { this.myRef = ref }}/> ### 圆括号 当 JSX 标签超过一行时使用圆括号包裹, eslint: [react/wrap-multilines](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/wrap-multilines.md) // badrender () { return <MyChild /> </MyComponent>}// goodrender () { return (<MyComponent className='long body' foo='bar'> <MyChild /> </MyComponent>)}// good, when single linerender () { const body = hello return {body}} ### 标签 - 没有子元素的标签请自闭合,eslint: [react/self-closing-comp](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/self-closing-comp.md) // bad// good - 如果组件包含多行属性,在新的一行闭合标签,eslint: [react/jsx-closing-bracket-location](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) // bad<Foo bar='bar' baz='baz' />// good<Foo bar='bar' baz='baz'/> ### 方法 - 使用箭头函数包裹本地变量 function ItemList (props) { return (<ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={() => doSomethingWith(item.name, index)} /> ))} </ul>)} - 类组件的内部方法不要使用下划线前缀 // badclass extends React.Component { _onClickSubmit () {// do stuff}// other stuff}// goodclass extends React.Component { onClickSubmit () {// do stuff}// other stuff} - 确保在 render 方法中存在返回值,eslint: [require-render-return](https://github.com/yannickcr/eslint-plugin-react/pull/502) // badrender () { ()}// goodrender () { return ()} ### Hooks 书写规范 - Hooks 只能应用于函数式组件中 - 只在 React 函数最顶层使用 Hooks > 不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们 // badfunction a () { const [count, setCount] = useState(0) useEffect(function persistForm() {localStorage.setItem('formData', accountName)}) const x = function () {} const [timer, setTimer] = useState(0)// main logic}// badfunction a () { const [count, setCount] = useState(0) useEffect(function persistForm() {localStorage.setItem('formData', accountName)}) const [timer, setTimer] = useState(0) const x = function () {} // main logic} # VUE风格指南 ### 介绍 在参与团队VUE开发中,请遵守约定的单文件组件风格指南,指南内容节选自 [Vue 官方风格指南](https://v3.cn.vuejs.org/style-guide/)。 ### 组件数据 组件的 data 必须是一个函数。 // badexport default { data: {foo: 'bar',},};// goodexport default { data() {return { foo: 'bar', };},}; ### 单文件组件文件名称 单文件组件的文件名应该要么始终是单词大写开头 (PascalCase),要么始终是横线连接 (kebab-case)。 // badmycomponent.vuemyComponent.vue// goodmy-component.vueMyComponent.vue ### 紧密耦合的组件名 和父组件紧密耦合的子组件应该以父组件名作为前缀命名。 // badcomponents/|- TodoList.vue|- TodoItem.vue└─ TodoButton.vue// goodcomponents/|- TodoList.vue|- TodoListItem.vue└─ TodoListItemButton.vue ### 自闭合组件 在单文件组件中没有内容的组件应该是自闭合的。 ### Prop 名大小写 在声明 prop 的时候,其命名应该始终使用 camelCase,而在模板中应该始终使用 kebab-case。 // badexport default { props: {'greeting-text': String,},};// goodexport default { props: {greetingText: String,},}; ### 指令缩写 指令缩写,用 `:` 表示 `v-bind:` ,用 `@` 表示 `v-on:` ### Props 顺序 标签的 Props 应该有统一的顺序,依次为指令、属性和事件。 <my-component v-if="if" v-show="show" v-model="value" ref="ref" :key="key" :text="text" @input="onInput" @change="onChange"/> ### 组件选项的顺序 组件选项应该有统一的顺序。 export default { name: '',mixins: [],components: {},props: {},data() {},computed: {},watch: {},created() {},mounted() {},destroyed() {},methods: {},}; ### 组件选项中的空行 组件选项较多时,建议在属性之间添加空行。 export default { computed: {formattedValue() { // ... }, styles() { // ... },},methods: {onInput() { // ... }, onChange() { // ... },},}; ### 单文件组件顶级标签的顺序 单文件组件应该总是让顶级标签的顺序保持一致,且标签之间留有空行。 ... /* ... */ / ... / # 团队约定(NAP) ## 静态资源的使用 项目当中不在允许存放asssets静态资源,简而言之,图片等资源不再允许将流量打到NGINX上 ## JS开发约定 1. v-if的判断条件不允许超过2个,超出请用computed代理判断逻辑 2. if-else超过3行用策略模式改写 3. 不再允许魔法字符串 4. 严格按照eslint设置
2022年07月21日
172 阅读
0 评论
0 点赞
1
2