使用小写属性名
HTML5 属性名允许使用大写和小写字母,但我们要求使用小写字母属性名:
同时使用大小写是非常不好的习惯。
开发人员通常使用小写 (类似 XHTML)。
小写风格看起来更加清爽。
小写字母容易编写。
属性值
HTML5 属性值可以不用引号,但是我们要求必须使用引号:
如果属性值含有空格需要使用引号。
混合风格不推荐的,建议统一风格。
属性值使用引号易于阅读。
图片属性
图片通常使用 alt
属性。 在图片不能显示时,它能替代图片显示。
定义好图片的尺寸,在加载时可以预留指定空间,减少闪烁。
空格和等号
等号前后必须使用空格
< link rel = " stylesheet" href = " styles.css" />
< link rel\ = \ "stylesheet" href\ = \ "styles.css" />
空行和缩进
为每个逻辑功能块添加空行,这样更易于阅读。
缩进使用两个空格,不建议使用 TAB。
比较短的代码间不要使用不必要的空行和缩进。
样式表
样式表使用简洁的语法格式 ( type 属性不是必须的)
< link rel = " stylesheet" href = " styles.css" />
内嵌样式规则:
将左花括号与选择器放在同一行。
左花括号与选择器间添加一个空格。
使用两个空格来缩进。
冒号与属性值之间添加一个空格。
逗号和符号之后使用一个空格。
每个属性与值结尾都要使用分号。
只有属性值包含空格时才使用引号。
右花括号放在新的一行。
p.into {
font-family : Verdana;
font-size : 16em;
}
在 HTML 中的 script 标签
标签的 type 属性不是必须的
请加上 defer 属性
省略外链资源 URL 协议部分
省略外链资源(图片及其它媒体资源)URL 中的 http / https 协议,使 URL 成为相对地址,避免 Mixed Content 问题,减小文件字节数。
其它协议(ftp 等)的 URL 不省略。
CSS 书写规范
代码组织
以组件为单位组织代码段;
制定一致的注释规范;
组件块和子组件块以及声明块之间使用一空行分隔,子组件块之间三空行分隔;
如果使用了多个 CSS 文件,将其按照组件而非页面的形式分拆,因为页面会被重组,而组件只会被移动;
良好的注释是非常重要的。请留出时间来描述组件(component)的工作方式、局限性和构建它们的方法。不要让你的团队其它成员 来猜测一段不通用或不明显的代码的目的。
Class 和 ID
使用语义化、通用的命名方式;
使用连字符 - 作为 ID、Class 名称界定符,不要驼峰命名法和下划线;
避免选择器嵌套层级过多,尽量少于 3 级;
避免选择器和 Class、ID 叠加使用;
出于性能考量,在没有必要的情况下避免元素选择器叠加 Class、ID 使用。
元素选择器和 ID、Class 混合使用也违反关注分离原则。如果 HTML 标签修改了,就要再去修改 CSS 代码,不利于后期维护。
类选择器口诀
样式点定义,结构类(class)调用,一个或多个,开发最常用
类选择器使用"."进行标识,后面紧跟类名(自定义);
可以理解为给这个标签起一个名字;
长名称或者词组可以使用中横线来为选择器命名;
不要使用纯数字、中文等命名,尽量使用英文字母来表示;
命名要有意义,尽量使别人一眼就知道这个类名的目的;
声明顺序
相关属性应为一组,推荐的样式编写顺序,保证更好的可读性和可扫描重要
Positioning
Box model
Typographic
Visual
由于定位(positioning)可以从正常的文档流中移除元素,并且还能覆盖盒模型(box model)相关的样式,因此排在首位。盒模型决定了组件的尺寸和位置,因此排在第二位。 其他属性只是影响组件的内部(inside)或者是不影响前两组属性,因此排在后面。 作为最佳实践,我们应该遵循以下顺序(应该按照下表的顺序):
结构性属性:
display
position, left, top, right
overflow, float, clear
margin, padding
表现性属性:
background, border
font, text
引号使用
url() 、属性选择符、属性值使用双引号。
媒体查询(Media query)的位置
将媒体查询放在尽可能相关规则的附近。不要将他们打包放在一个单一样式文件中或者放在文档底部。如果你把他们分开了,将来只会被大家遗忘。
不要使用 @import
与 相比,@import 要慢很多,不光增加额外的请求数,还会导致不可预料的问题。
替代办法:
使用多个 元素;
通过 Sass 或 Less 类似的 CSS 预处理器将多个 CSS 文件编译为一个文件;
其他 CSS 文件合并工具;
链接的样式顺序:
a:link -> a:visited -> a:hover -> a:active(LoVeHAte)
选择字体
在 Web 上应用字体,是一门技术,同时也是一门艺术. 由于计算机历史发展的原因,西文有大量优秀的字体可供选择,可对于中文来说就是一项挑战. 主流操作系统提供的本地中文字体极少,另一方面中文字体组成的特殊性,其体积过于庞大,无法良好地使用 webfont. 所以编写健壮的 font-family 是一件需要深思熟虑的事情.
使用 vw 作为单位时的简便计算
以 iphone6 为标准的 750*1334px 的设计稿为例,在 scss 中使用如下方法,可以直接使用设计稿上面的标志,快速编写 css,免于转换计算
@function vw ( $px) {
@return ( $px / 750) * 100vw;
}
div {
width : vw ( 101) ;
}
JavaScript 书写规范
命名
采用小写驼峰命名 lowerCamelCase,代码中的命名均不能以下划线,也不能以下划线或美元符号结束。
Bad: _name | name_ | name$
;
方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从驼峰形式。
Good: localValue | getHttpMessage() | inputUserId
常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
例子: Good: MAX_STOCK_COUNT; Bad: MAX_COUNT
!> 其中 method 方法命名强调 动词 或者 动词+名词 形式
附: 函数方法常用的动词(点击展开):
块级作用域
let
取代 var
,在 let
和 const
之间,建议优先使用 const
,尤其是在全局环境,不应该设置变量,只应设置常量。
强类型检查
=== 代替 ==
0 == false ;
0 === false ;
2 == '2' ;
2 === '2' ;
const value = '500' ;
if ( value === 500 ) {
console. log ( value) ;
}
if ( value === '500' ) {
console. log ( value) ;
}
变量
1、给变量命名时,应该要使变量名具有代表意图的象征,使人易于搜索并且容易理解。
Bad:
let daysSLV = 10 ;
let y = new Date ( ) . getFullYear ( ) ;
let ok;
if ( user. age > 30 ) {
ok = true ;
}
Good:
const MAX_AGE = 30 ;
let daysSinceLastVisit = 10 ;
let currentYear = new Date ( ) . getFullYear ( ) ;
...
const isUserOlderThanAllowed = user. age > MAX_AGE ;
2、不要在变量名中增加没必要额外的单词
Bad:
let nameValue;
let theProduct;
Good:
let name;
let product;
3、不要强制记忆变量名的上下文
Bad:
const users = [ 'John' , 'Marco' , 'Peter' ] ;
users. forEach ( ( u ) => {
doSomething ( ) ;
doSomethingElse ( ) ;
register ( u) ;
} ) ;
Good:
const users = [ 'John' , 'Marco' , 'Peter' ] ;
users. forEach ( ( user ) => {
doSomething ( ) ;
doSomethingElse ( ) ;
register ( user) ;
} ) ;
4、变量名不要加上下文重复的单词
Bad:
const user = {
userName : "John" ,
userSurname : "Doe" ,
userAge : "28"
} ;
...
user. userName;
Good:
const user = {
name : "John" ,
surname : "Doe" ,
age : "28"
} ;
...
user. name;
函数
1、函数名应该是动词或者短语,代表某种行为,描述它们在做什么
Bad:
function notif ( user ) {
}
Good:
function notifyUser ( emailAddress ) {
}
2、避免使用大量的参数,理想的情况就是用两个或者更少的参数。参数越少,测试就越容易
Bad:
function getUsers ( fields, fromDate, toDate ) {
}
Good:
function getUsers ( { fields, fromDate, toDate } ) {
}
getUsers ( {
fields : [ 'name' , 'surname' , 'email' ] ,
fromDate : '2019-01-01' ,
toDate : '2019-01-18'
} ) ;
3、一个函数应该做一件事,避免在一个函数中执行多个操作。
Bad:
function notifyUsers ( users ) {
users. forEach ( ( user ) => {
const userRecord = database. lookup ( user) ;
if ( userRecord. isVerified ( ) ) {
notify ( user) ;
}
} ) ;
}
Good:
function notifyVerifiedUsers ( users ) {
users. filter ( isUserVerified) . forEach ( notify) ;
}
function isUserVerified ( user ) {
const userRecord = database. lookup ( user) ;
return userRecord. isVerified ( ) ;
}
4、使用 Object.assign
设置默认对象。
Bad:
const shapeConfig = {
type : 'cube' ,
width : 200 ,
height : null
} ;
function createShape ( config ) {
config. type = config. type || 'cube' ;
config. width = config. width || 250 ;
}
createShape ( shapeConfig) ;
Good:
const shapeConfig = {
type : 'cube' ,
width : 200
} ;
function createShape ( config ) {
config = Object. assign (
{
type : 'cube' ,
width : 250
} ,
config
) ;
}
createShape ( shapeConfig) ;
5、不要使用标志记作为参数,因为它们告诉你该函数正在做的比它应该做的更多。
Bad:
function createFile ( name, isPublic ) {
if ( isPublic) {
fs. create ( ` ./public/ ${ name} ` ) ;
} else {
fs. create ( name) ;
}
}
Good:
function createFile ( name ) {
fs. create ( name) ;
}
function createPublicFile ( name ) {
createFile ( ` ./public/ ${ name} ` ) ;
}
6、不要污染全局变量。如果需要扩展现有对象,请使用 ES6 类和继承,而不是在现有对象的原型链上创建函数
Bad:
Array . prototype. myFunc = function myFunc ( ) {
} ;
Good:
class SuperArray extends Array {
myFunc ( ) {
}
}
7、重要函数或者类等都要添加头描述
条件语句
1、使用条件语句尽量短点。这可能是微不足道的,但值得一提。此方法仅用于布尔值,并且如果您确定该值不是未定义的或为 null
。
Bad:
if ( isValid === true ) {
}
if ( isValid === false ) {
}
Good:
if ( isValid) {
}
if ( ! isValid) {
}
2、尽可能避免 switch 分支,请改用多态和继承。
字符串
1、应使用数组保存字符串片段,使用时调用 join
方法。避免使用+或+=的方式拼接较长的字符串,每个字符串都会使用一个小的内存片段,过多的内存片段会影响性能
2、静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。
解构赋值
1、使用数组成员对变量赋值时,优先使用解构赋值。
Bad:
const arr = [ 1 , 2 , 3 , 4 ] ;
const first = arr[ 0 ] ;
const second = arr[ 1 ] ;
Good:
const [ first, second] = arr;
2、函数的参数如果明确是对象的成员,优先使用解构赋值。
3、如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
4、不要在函数体内使用 arguments
变量,使用扩展运算符(...)
代替。
数组
1、使用扩展运算符(...)
拷贝数组。使用Array.from
方法,将类似数组的对象转为数组。
const a1 = [ 1 , 2 , 3 ] ;
const b1 = [ ... a1] ;
const h3List = Array. from ( document. querySelectorAll ( 'h3' ) ) ;
2、如果单纯判断每个数组元素存在。使用Array.includes
方法。
const a1 = [ 1 , 2 , 3 ] ;
const b1 = [ ... a1] ;
const h3List = Array. from ( document. querySelectorAll ( 'h3' ) ) ;
对象
1、尽量不要使用 new
命令,改用 Object.create()
或者对象字面量
const lang = { name : 'Javascript' } ;
const lang = Object. create ( { name : 'JavaScript' } ) ;
Vue 开发相关规范
vue 项目规范以 Vue 官方规范 (https://cn.vuejs.org/v2/style-guide/) 中的 A 规范为基础,在其上面进行项目开发,故所有代码均遵守该规范。
!> 请仔细阅读 Vue 官方规范,切记,此为第一步。
组件规范
1、组件名为多个单词
Good:
export default {
name : 'TodoItem'
} ;
Bad:
export default {
name : 'Todo' ,
}
export default {
name : 'todo-item' ,
}
2、组件文件名为 pascal-case 格式
Good:
components/
| - my- component. vue
Bad:
components/
| - myComponent. vue
| - MyComponent. vue
3、基础组件文件名为 base 开头,使用完整单词而不是缩写
Good:
components/
| - base- button. vue
Bad:
components/
| - MyButton. vue
4、和父组件紧密耦合的子组件应该以父组件名作为前缀命名
Good:
components/
| - todo- list. vue
| - todo- list- item. vue
| - todo- list- item- button. vue
| - user- profile- options. vue (完整单词)
Bad:
components/
| - TodoList. vue
| - TodoItem. vue
| - TodoButton. vue
| - UProfOpts. vue (使用了缩写)
5、在 Template 模版中使用组件,应使用 PascalCase 模式,并且使用自闭合组件
Good:
< ! -- 在单文件组件、字符串模板和 JSX 中 -- >
< MyComponent / >
< Row> < table : column= "data" / > < / Row>
Bad:
< my- component / > < row> < table : column= "data" / > < / row>
6、组件的 data 必须是一个函数
当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。 因为如果直接是一个对象的话,子组件之间的属性值会互相影响。
7、Prop 定义应该尽量详细
必须使用 camelCase 驼峰命名
必须指定类型
必须加上注释,表明其含义
必须加上 required 或者 default,两者二选其一
如果有业务需要,必须加上 validator 验证
Good:
props : {
status : {
type : String,
required : true ,
validator : function ( value ) {
return [
'succ' ,
'info' ,
'error'
] . indexOf ( value) !== - 1
}
} ,
userLevel:{
type : String,
required : true
}
}
8、为组件样式设置作用域(使用 scoped
属性)
9、如果特性元素较多,应该主动换行
Good:
< MyComponent
foo= 'a'
bar= 'b'
baz= 'c'
foo= 'a'
bar= 'b'
baz= 'c'
foo= 'a'
bar= 'b'
baz= 'c'
/ >
指令都使用缩写形式
指令推荐都使用缩写形式,(用 : 表示 v-bind: 、用 @ 表示 v-on: 和用 # 表示 v-slot:) Good:
< input
@input= "onInput"
@focus= "onFocus"
>
Bad:
< input
v- on: input= "onInput"
@focus= "onFocus"
>
标签顺序保持一致
< template> ... < / template>
< script> ... < / script>
< style> ... < / style>
必须为 v-for 设置键值 key
v-show 与 v-if 选择
如果运行时,需要非常频繁地切换,使用 v-show ;如果在运行时,条件很少改变,使用 v-if。
Vue Router 规范
1、页面跳转数据传递使用路由参数
页面跳转,例如 A 页面跳转到 B 页面,需要将 A 页面的数据传递到 B 页面,推荐使用 路由参数进行传参,而不是将需要传递的数据保存 vuex,然后在 B 页面取出 vuex 的数据,因为如果在 B 页面刷新会导致 vuex 数据丢失,导致 B 页面无法正常显示数据。
let id = '123' ;
this . $router. push ( { name : 'userCenter' , query : { id } } ) ;
2、使用路由懒加载(延迟加载)机制
3、router 中的命名规范
path
、childrenPoints
命名规范采用 kebab-case 命名规范(尽量 vue 文件的目录结构保持一致,因为目录、文件名都是 kebab-case,这样很方便找到对应的文件)
name
命名规范采用 KebabCase 命名规范且和 component 组件名保持一致!(因为要保持keep-alive
特性,keep-alive
按照 component 的name
进行缓存,所以两者必须高度保持一致)
{
path : '/n/task-calling' ,
component : _import ( 'tasks/calling/index' ) ,
name : 'taskCalling' ,
desc : '外呼下单' ,
} ,
4、router 中的 path 命名规范
path 除了采用 kebab-case 命名规范以外,必须以 / 开头,即使是 children 里的 path 也要以 / 开头
目的:经常有这样的场景:某个页面有问题,要立刻找到这个 vue 文件,如果不用以/开头,path 为 parent 和 children 组成的,可能经常需要在 router 文件里搜索多次才能找到,而如果以/开头,则能立刻搜索到对应的组件
5、router 规范
router 目录应根据项目进行业务分层,进行模块拆分,并尽量与 views 模块保持一致。
import Router from 'vue-router' ;
import tasks from './modules/tasks' ;
import sys from './modules/sys' ;
import business from './modules/business' ;
import workbench from './modules/workbench' ;
const router = new Router ( {
mode : 'hash' ,
routes : [
{
path : '/404' ,
component : _import ( 'error/404' ) ,
name : '404' ,
desc : '404未找到' ,
} ,
{
path : '/login' ,
component : _import ( 'login/index' ) ,
name : 'login' ,
desc : '登录' ,
} ,
{
path : '/' ,
component : _import ( 'home/index' ) ,
name : 'home' ,
} ,
... sys,
... business,
... workbench,
... tasks,
]
} ;
service 目录规范
service 目录存放与后端接口相关的模块,包括接口路径定义,请求相关设置。接口定义必须按照后端结构进行定义。
export const common = {
captcha : 'captcha.jpg' ,
login : 'sys/login' ,
logout : 'sys/logout'
} ;
export const sys = {
user : {
list : 'sys/user/list' ,
info : 'sys/user/info' ,
updatePassword : 'sys/user/password' ,
add : 'sys/user/save' ,
update : 'sys/user/update' ,
del : 'sys/user/delete' ,
getUserInfo : 'sys/user/getUserInfo'
} ,
menu : {
nav : 'sys/menu/nav' ,
select : 'sys/menu/select' ,
list : 'sys/menu/list' ,
info : 'sys/menu/info' ,
add : 'sys/menu/save' ,
update : 'sys/menu/update' ,
del : 'sys/menu/delete'
}
} ;
其他
1、尽量不要手动操作 DOM
2、删除无用代码(因使用了 Git/SVN 版本管理,应及时一些调试代码及无用弃用的代码)