基于阿里巴巴JAVA开发规范整理
=============
【强制】类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:DO / BO / DTO / VO / AO
正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion
反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
【强制】方法名、参数名、成员变量、局部变量都统一使用 lowerCamelCase 风格,必须遵从 驼峰形式。
正例: localValue / getHttpMessage() / inputUserId
【强制】常量命名全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长。
正例:MAX_STOCK_COUNT 反例:MAX_COUNT
【强制】抽象类命名使用 Abstract 或 Base 开头;异常类命名使用 Exception 结尾;测试类命名以它要测试的类的名称开始,以 Test 结尾。
【强制】Model 类中布尔类型的变量,都不要加 is,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 Boolean isDeleted;的属性,它的方法也是 isDeleted(),RPC框架在反向解析的时候,“以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。
【强制】对于 Service 和 DAO 类,基于 SOA 的理念,暴露出来的服务一定是接口,内部的实现类用 Impl 的后缀与接口区别。 正例:CacheManagerImpl 实现 CacheManager 接口。
【推荐】为了达到代码自解释的目标,任何自定义编程元素在命名时,使用尽量完整的单词组合来表达其意。
正例:从远程仓库拉取代码的类命名为PullCodeFromRemoteRepository
反例:变量int a;的随意命名方式。
【推荐】接口类中的方法和属性不要加任何修饰符号(public 也不要加),保持代码的简洁 性,并加上有效 的Javadoc 注释。尽量不要在接口里定义变量,如果一定要定义变量,肯定是 与接口方法相关,并且是整个应用的基础常量。
正例:接口方法签名:void f(); 接口基础常量表示:String COMPANY = “alibaba”;
反例:接口方法定义:public abstract void f();
说明:JDK8 中接口允许有默认实现,那么这个default方法,是对所有实现类都有价值的默 认实现。
【参考】枚举类名建议带上 Enum 后缀,枚举成员名称需要全大写,单词间用下划线隔开。
说明:枚举其实就是特殊的常量类,且构造方法被默认强制是私有。
正例:枚举名字为 ProcessStatusEnum 的成员名称:SUCCESS / UNKOWN_REASON。
【参考】各层命名规约:
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 做前缀。
2) 获取多个对象的方法用 list 做前缀。
3) 获取统计值的方法用 count 做前缀。
4) 插入的方法用 save/insert 做前缀。
5) 删除的方法用 remove/delete 做前缀。
6) 修改的方法用 update 做前缀。
【推荐】不要使用一个常量类维护所有常量,按常量功能进行归类,分开维护。 说明:大而全的常量类,非得使用查找功能才能定位到修改的常量,不利于理解和维护。
正例:缓存相关常量放在类 CacheConsts 下;系统配置相关常量放在类 ConfigConsts 下。
【强制】大括号的使用约定。如果是大括号内为空,则简洁地写成{}即可,不需要换行;如果 是非空代码块则:
1) 左大括号前不换行。
2) 左大括号后换行。
3) 右大括号前换行。
4) 右大括号后还有 else 等代码则不换行 表示终止的右大括号后必须换行。
【强制】 左小括号和字符之间不出现空格;同样,右小括号和字符之间也不出现空格。
反例:if (空格a == b空格)
【强制】if/for/while/switch/do 等保留字与括号之间都必须加空格。
【强制】任何二目、三目运算符的左右两边都需要加一个空格。
说明:运算符包括赋值运算符=、逻辑运算符&&、加减乘除符号等。
【强制】采用 4 个空格缩进,禁止使用 tab 字符。
说明:Vue工程采用2个空格缩进
【强制】注释的双斜线与注释内容之间有且仅有一个空格。
正例:// 注释内容,注意在//和注释内容之间有一个空格。
【强制】方法参数在定义和传入时,多个参数逗号后边必须加空格。
正例:下例中实参的”a”,后边必须要有一个空格。method(“a”, “b”, “c”);
【强制】IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式,不要使用 Windows 格式。
【推荐】方法体内的执行语句组、变量的定义语句组、不同的业务逻辑之间或者不同的语义之间插入一个空行。相同业务逻辑和语义之间不需要插入空行。
说明:没有必要插入多个空行进行隔开。
【强制】所有的覆写方法,必须加@Override 注解。
【强制】不能使用过时的类或方法。
【强制】Object 的 equals 方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
正例:”test”.equals(object);
反例:object.equals(“test”);
【强制】所有的相同类型的包装类对象之间值的比较,全部使用 equals 方法比较。
说明:对于 Integer var = ? 在-128 至 127 范围内的赋值,Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑, 推荐使用 equals 方法进行判断。
【强制】RPC 方法的返回值和参数必须使用包装数据类型。
【强制】构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在 init 方法中。
【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起, 便于阅读。
【推荐】循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。 说明:反编译出的字节码文件显示每次循环都会 new 出一个 StringBuilder 对象,然后进行 append 操作,最后通过 toString 方法返回 String 对象,造成内存资源浪费。
反例:
1 | String str = "start"; |
【推荐】慎用 Object 的 clone 方法来拷贝对象。 说明:对象的 clone 方法默认是浅拷贝,若想实现深拷贝需要重写 clone 方法实现属性对象 的拷贝。
1 | List<String> list = new ArrayList<String>(2); |
反例:1
2
3
4
5
6
7
8List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
for (String item : list) {
if ("1".equals(item)) {
list.remove(item);
}
}
【强制】在一个 switch 块内,每个 case 要么通过 break/return 等来终止,要么注释说明程序将继续执行到哪一个 case 为止;在一个 switch 块内,都必须包含一个 default 语句并且 放在最后,即使它什么代码也没有。
【强制】在 if/else/for/while/do 语句中必须使用大括号。即使只有一行代码,避 单行的编码方式:if (condition) statements;
【推荐】除常用方法(如 getXxx/isXxx)等外,不要在条件判断中执行其它复杂的语句,将复 杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性。 说明:很多 if 语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么 样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢?
正例:
// 伪代码如下
1 | final boolean existed = (file.open(fileName, "w") != null) && (...) || (...); |
反例:1
2
3if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
}
【强制】类、类属性、类方法的注释必须使用 Javadoc 规范,使用/**内容*/ 格式,不得使用 // xxx 方式。
【强制】所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、 异常说明外,还必须指出该方法做什么事情,实现什么功能。 说明:对子类的实现要求,或者调用注意事项,请一并说明。
【强制】所有的类都必须添加创建者和创建日期。
【强制】方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释 使用/ \/注释,注意与代码对齐。
【强制】所有的枚举类型字段必须要有注释,说明每个数据项的用途。
【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻辑 等的修改。 说明:代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后, 就失去了导航的意义。
【参考】谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
【参考】对于注释的要求:第一、能够准确反应设计思想和代码逻辑;第二、能够描述业务含 义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者形同 天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继任者看 的,使其能够快速接替自己的工作。
【参考】好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的 一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。
【参考】特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描, 经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
1) 待办事宜(TODO):( 标记人,标记时间,[预计处理时间]) 表示需要实现,但目前还未实现的功能。这实际上是一个 Javadoc 的标签,目前的 Javadoc 还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。
2) 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间]) 在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。
【强制】在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。 说明:不要在方法体内定义:Pattern pattern = Pattern.compile(规则);
【强制】注意 Math.random() 这个方法返回是 double 类型,注意取值的范围 0≤x<1(能够 取到零值,注意除零异常),如果想获取整数类型的随机数,不要将 x 放大 10 的若干倍然后 取整,直接使用 Random 对象的 nextInt 或者 nextLong 方法。
【强制】获取当前毫秒数 System.currentTimeMillis(); 而不是 new Date().getTime();
【推荐】任何数据结构的构造或初始化,都应指定大小,避免数据结构无限增长吃光内存。
【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只 出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库
名、表名、字段名,都不允许出现任何大写字母,避免节外生枝。
正例:aliyun_admin,rdc_config,level3_name 反例:AliyunAdmin,rdcConfig,level_3_name
【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。
【强制】主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。 说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称。
【强制】小数类型为 decimal,禁止使用 float 和 double。
【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text。
【强制】表必备三个字段:id,create_time, update_time, delete_flag
【强制】对于Boolean型的字段,采用decimal类型
【强制】表和字段都需要添加注释信息。
【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检 索速度。
【强制】业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
说明:不要以为唯一索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明 显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必 然有脏数据产生。
【强制】超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;多表关联查询时, 保证被关联的字段需要有索引。
说明:即使双表 join 也要注意表索引、SQL 性能。
【强制】在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据 实际文本区分度决定索引长度即可。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型数据,长度为 20 的索引,区分度会高达 90%以上,可以使用 count(distinct left(列名, 索引长度))/count(*)的区分度 来确定。
【参考】创建索引时避免有如下极端误解:
1)宁滥勿缺。认为一个查询就需要建一个索引。
2)宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。
3)抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。
【强制】不要使用 count(列名)或 count(常量)来替代 count(*),count(*)是 SQL92 定义的
标准统计行数的语法,跟数据库无关,跟 NULL 和非 NULL 无关。
说明:count(*)会统计值为 NULL 的行,而 count(列名)不会统计此列为 NULL 值的行。
【强制】count(distinct col) 计算该列除 NULL 之外的不重复行数,注意 count(di col1, col2) 如果其中一列全为 NULL,那么即使另一列有不同的值,也返回为 0。
【强制】当某一列的值全是 NULL 时,count(col)的返回结果为 0,但 sum(col)的返回结果为NULL.
【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
【强制】禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。
【推荐】in 操作能避免则避免,若实在避免不了,需要仔细评估 in 后边的集合元素数量,控 制在 1000 个之内。
【参考】如果有全球化需要,所有的字符存储与表示,均以 utf-8 编码,注意字符 的区别。
说明: SELECT LENGTH(“轻松工作”); 返回为 12 SELECT CHARACTER_LENGTH(“轻松工作”); 返回为 4 如果需要存储表情,那么选择 utfmb4 来进行存储,注意它与 -8 编码的区别。
【强制】更新数据表记录时,必须同时更新记录对应的 update_time 字段值为当前时间。
【参考】@Transactional 事务不要滥用。事务会影响数据库的 QPS,另外使用事务的地方需 要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。
基于Vue官方风格指南整理
=============
组件名应该始终是多个单词的,根组件 App 除外。
正例:1
2
3
4export default {
name: 'TodoItem',
// ...
}
反例:1
2
3
4export default {
name: 'Todo',
// ...
}
组件的 data 必须是一个函数。
当在组件中使用 data 属性的时候 (除了 new Vue 外的任何地方),它的值必须是返回一个对象的函数。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// In a .vue file
export default {
data () {
return {
foo: 'bar'
}
}
}
// 在一个 Vue 的根实例上直接使用对象是可以的,
// 因为只存在一个这样的实例。
new Vue({
data: {
foo: 'bar'
}
})
反例:1
2
3
4
5export default {
data: {
foo: 'bar'
}
}
Prop 定义应该尽量详细。
在你提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18props: {
status: String
}
// 更好的做法!
props: {
status: {
type: String,
required: true,
validator: function (value) {
return [
'syncing',
'synced',
'version-conflict',
'error'
].indexOf(value) !== -1
}
}
}
反例:1
2// 这样做只有开发原型系统时可以接受
props: ['status']
总是用 key 配合 v-for。
在组件上_总是_必须用 key 配合 v-for,以便维护内部组件及其子树的状态。甚至在元素上维护可预测的行为,比如动画中的对象固化 (object constancy),也是一种好的做法。
正例:1
2
3
4
5
6
7
8<ul>
<li
v-for="todo in todos"
:key="todo.id"
>
{{ todo.text }}
</li>
</ul>
反例:1
2
3
4
5<ul>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ul>
永远不要把 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
2
3
4
5
6
7
8<ul v-if="shouldShowUsers">
<li
v-for="user in users"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
反例:1
2
3
4
5
6
7
8
9<ul>
<li
v-for="user in users"
v-if="shouldShowUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
对于应用来说,顶级 App 组件和布局组件中的样式可以是全局的,但是其它所有组件都应该是有作用域的。
这条规则只和单文件组件有关。你不一定要使用 scoped 特性。设置作用域也可以通过 CSS Modules,那是一个基于 class 的类似 BEM 的策略,当然你也可以使用其它的库或约定。不管怎样,对于组件库,我们应该更倾向于选用基于 class 的策略而不是 scoped 特性。
这让覆写内部样式更容易:使用了常人可理解的 class 名称且没有太高的选择器优先级,而且不太会导致冲突。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<template>
<button class="c-Button c-Button--close">X</button>
</template>
<!-- 使用 BEM 约定 -->
<style>
.c-Button {
border: none;
border-radius: 2px;
}
.c-Button--close {
background-color: red;
}
</style>
反例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25<template>
<button class="btn btn-close">X</button>
</template>
<style>
.btn-close {
background-color: red;
}
</style>
<template>
<button class="button button-close">X</button>
</template>
<!-- 使用 `scoped` 特性 -->
<style scoped>
.button {
border: none;
border-radius: 2px;
}
.button-close {
background-color: red;
}
</style>
只要有能够拼接文件的构建系统,就把每个组件单独分成文件。
当你需要编辑一个组件或查阅一个组件的用法时,可以更快速的找到它。
正例:1
2
3components/
|- TodoList.vue
|- TodoItem.vue
反例:1
2
3
4
5
6
7Vue.component('TodoList', {
// ...
})
Vue.component('TodoItem', {
// ...
})
单文件组件的文件名应该要么始终是单词大写开头 (PascalCase)
正例:1
2components/
|- MyComponent.vue
反例:1
2
3components/
|- myComponent.vue
|- mycomponent.vue
应用特定样式和约定的基础组件 (也就是展示类的、无逻辑的或无状态的组件) 应该全部以一个特定的前缀开头,比如 Base、App 或 V。
正例:1
2
3
4components/
|- BaseButton.vue
|- BaseTable.vue
|- BaseIcon.vue
反例:1
2
3
4components/
|- MyButton.vue
|- VueTable.vue
|- Icon.vue
只应该拥有单个活跃实例的组件应该以 The 前缀命名,以示其唯一性。
这不意味着组件只可用于一个单页面,而是每个页面只使用一次。这些组件永远不接受任何 prop,因为它们是为你的应用定制的,而不是它们在你的应用中的上下文。如果你发现有必要添加 prop,那就表明这实际上是一个可复用的组件,只是目前在每个页面里只使用一次。
正例:1
2
3components/
|- TheHeading.vue
|- TheSidebar.vue
反例:1
2
3components/
|- Heading.vue
|- MySidebar.vue
和父组件紧密耦合的子组件应该以父组件名作为前缀命名。
如果一个组件只在某个父组件的场景下有意义,这层关系应该体现在其名字上。因为编辑器通常会按字母顺序组织文件,所以这样做可以把相关联的文件排在一起。
正例:1
2
3
4
5
6
7components/
|- TodoList.vue
|- TodoListItem.vue
|- TodoListItemButton.vue
components/
|- SearchSidebar.vue
|- SearchSidebarNavigation.vue
反例:1
2
3components/
|- SearchSidebar.vue
|- NavigationForSearchSidebar.vue
组件名应该以高级别的 (通常是一般化描述的) 单词开头,以描述性的修饰词结尾。
正例:1
2
3
4
5
6
7components/
|- SearchButtonClear.vue
|- SearchButtonRun.vue
|- SearchInputQuery.vue
|- SearchInputExcludeGlob.vue
|- SettingsCheckboxTerms.vue
|- SettingsCheckboxLaunchOnStartup.vue
反例:1
2
3
4
5
6
7components/
|- ClearSearchButton.vue
|- ExcludeFromSearchInput.vue
|- LaunchOnStartupCheckbox.vue
|- RunSearchButton.vue
|- SearchInput.vue
|- TermsCheckbox.vue
总是 PascalCase 的
正例:1
2<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
反例:1
2
3
4<!-- 在单文件组件和字符串模板中 -->
<mycomponent/>
<!-- 在单文件组件和字符串模板中 -->
<myComponent/>
组件名应该倾向于完整单词而不是缩写。
正例:1
2
3components/
|- StudentDashboardSettings.vue
|- UserProfileOptions.vue
反例:1
2
3components/
|- SdSettings.vue
|- UProfOpts.vue
多个特性的元素应该分多行撰写,每个特性一行。
正例:1
2
3
4
5
6
7
8
9<img
src="https://vuejs.org/images/logo.png"
alt="Vue Logo"
>
<MyComponent
foo="a"
bar="b"
baz="c"
/>
反例:1
2<img src="https://vuejs.org/images/logo.png" alt="Vue Logo">
<MyComponent foo="a" bar="b" baz="c"/>
组件模板应该只包含简单的表达式,复杂的表达式则应该重构为计算属性或方法。
复杂表达式会让你的模板变得不那么声明式。我们应该尽量描述应该出现的是什么,而非如何计算那个值。而且计算属性和方法使得代码可以重用。
正例:1
2
3
4
5
6
7
8
9
10<!-- 在模板中 -->
{{ normalizedFullName }}
// 复杂表达式已经移入一个计算属性
computed: {
normalizedFullName: function () {
return this.fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}
}
反例:1
2
3
4
5{{
fullName.split(' ').map(function (word) {
return word[0].toUpperCase() + word.slice(1)
}).join(' ')
}}
正例:1
2
3
4
5
6
7
8
9
10
11computed: {
basePrice: function () {
return this.manufactureCost / (1 - this.profitMargin)
},
discount: function () {
return this.basePrice * (this.discountPercent || 0)
},
finalPrice: function () {
return this.basePrice - this.discount
}
}
反例:1
2
3
4
5
6
7
8
9computed: {
price: function () {
var basePrice = this.manufactureCost / (1 - this.profitMargin)
return (
basePrice -
basePrice * (this.discountPercent || 0)
)
}
}
非空 HTML 特性值应该始终带引号 (单引号或双引号,选你 JS 里不用的那个)。
在 HTML 中不带空格的特性值是可以没有引号的,但这样做常常导致带空格的特征值被回避,导致其可读性变差。
正例:1
<AppSidebar :style="{ width: sidebarWidth + 'px' }">
反例:1
<AppSidebar :style={width:sidebarWidth+'px'}>
都用指令缩写 (用 : 表示 v-bind: 和用 @ 表示 v-on:)
正例:1
2
3
4<input
@input="onInput"
@focus="onFocus"
>
反例:1
2
3
4<input
v-bind:value="newTodoText"
:placeholder="newTodoInstructions"
>
单文件组件应该总是让<script>、<template> 和 <style> 标签的顺序保持一致。且 <style> 要放在最后,因为另外两个标签至少要有一个。
正例:1
2
3
4<!-- ComponentA.vue -->
<template>...</template>
<script>/* ... */</script>
<style>/* ... */</style>
如果一组 v-if + v-else 的元素类型相同,最好使用 key (比如两个 <div> 元素)。
正例:1
2
3
4
5
6
7
8
9
10
11
12<div
v-if="error"
key="search-status"
>
错误:{{ error }}
</div>
<div
v-else
key="search-results"
>
{{ results }}
</div>
反例:1
2
3
4
5
6<div v-if="error">
错误:{{ error }}
</div>
<div v-else>
{{ results }}
</div>
元素选择器应该避免在 scoped 中出现。
在 scoped 样式中,类选择器比元素选择器更好,因为大量使用元素选择器是很慢的。
正例:1
2
3
4
5
6
7
8
9<template>
<button class="btn btn-close">X</button>
</template>
<style scoped>
.btn-close {
background-color: red;
}
</style>
反例:1
2
3
4
5
6
7
8
9<template>
<button>X</button>
</template>
<style scoped>
button {
background-color: red;
}
</style>
应该优先通过 prop 和事件进行父子组件之间的通信,而不是 this.$parent 或改变 prop。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
template: `
<input
:value="todo.text"
@input="$emit('input', $event.target.value)"
>
`
})
反例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24Vue.component('TodoItem', {
props: {
todo: {
type: Object,
required: true
}
},
methods: {
removeTodo () {
var vm = this
vm.$parent.todos = vm.$parent.todos.filter(function (todo) {
return todo.id !== vm.todo.id
})
}
},
template: `
<span>
{{ todo.text }}
<button @click="removeTodo">
X
</button>
</span>
`
})
应该优先通过 Vuex 管理全局状态,而不是通过 this.$root 或一个全局事件总线。
正例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39// store/modules/todos.js
export default {
state: {
list: []
},
mutations: {
REMOVE_TODO (state, todoId) {
state.list = state.list.filter(todo => todo.id !== todoId)
}
},
actions: {
removeTodo ({ commit, state }, todo) {
commit('REMOVE_TODO', todo.id)
}
}
}
<!-- TodoItem.vue -->
<template>
<span>
{{ todo.text }}
<button @click="removeTodo(todo)">
X
</button>
</span>
</template>
<script>
import { mapActions } from 'vuex'
export default {
props: {
todo: {
type: Object,
required: true
}
},
methods: mapActions(['removeTodo'])
}
</script>
反例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// main.js
new Vue({
data: {
todos: []
},
created: function () {
this.$on('remove-todo', this.removeTodo)
},
methods: {
removeTodo: function (todo) {
var todoIdToRemove = todo.id
this.todos = this.todos.filter(function (todo) {
return todo.id !== todoIdToRemove
})
}
}
})
vs code配置
1 | { |
vs code 插件
不知道大家有没有遇到过这样一种情况? vuex中的state会在某一个组建中使用,而这个状态的初始化是通过异步加载完成的。组件在渲染过程中,获取的state状态为空。也就是说组件在异步完成之前就已经完成渲染了,导致组件的数据没有来得及渲染。
举例说明如下:1
2
3
4
5
6
7
8
9
10
11
12
13// topo.vue
created() {
this.getUserAndSysIcons();
},
methods: {
getUserAndSysIcons() {
const self = this;
// 用户图标
iconApi.getUserIcons().then(response => {
self.$store.dispatch('setUserIcons', response.data);
});
}
}
在topo.vue中created或者mounted完成的时候调用 getUserAndSysIcons() 异步初始化userIcons,方便在其他组件中使用这个数据。
1 | // modifyhost.vue |
在modifyhost.vue中渲染数据是,需要使用userIcons。在modifyhost.vue组件mounted完成的时候,userIcons数据还没有被初始化。导致modifyhost.vue渲染为空。
想的是,当topo.vue中异步获取userIcons完成的时候,再去将modifyhost.vue组件中的userIcons初始化。这样就会自动改变完成渲染。那么怎么知道异步什么时候完成呢?
于是就想到了vue一个好东西watch监听,监听某一个数据的变化。我们都知道是,很容易监听组件中局部数据的变化。那么,这里怎么去监听state中的变化呢?于是有利用了computed计算属性。具体操作如下:
在computed中写一个计算属性getUserIcons,返回状态管理中的userIcons。然后在watch中监听这个计算属性的变化,对modifyhost.vue中的userIcons重新赋值。
1 | computed: { |
作为一名前端工程师,一个好的编辑器可以在编码期间,事半功倍。这里我分享一下vs code和atom这两种现今非常流行的编辑器,各有各的优缺点,看大家的喜好。我比较倾向于vs code,顺便也把插件整理了一下,给大家分享。
vs code是微软公司出的,之前我一直以为vs code像visual studio一样,非常大,而且每次启动非常慢。但是一用就错了,启动秒级速度,这次微软也算是对得起业界的良心。但是从美观角度来说,它没有atom漂亮,但是vs code可以更改主题(见下面分享的几个主题),我相信一个非常棒的前端工程师,一定对颜值有很高的要求。从插件角度来说,两个都非常支持的非常棒。
超级实用且初级的 H5代码片段以及提示
让 html 标签上写class 智能提示当前项目所支持的样式
适用于非css项目,例如vue2/angular2+。
与上个插件类似,区别是class的提示来至于scss文件,可以直接从html-class跳转到scss文件,需要手动配置global文件地址
让 vscode 映射 chrome 的 debug功能,静态页面都可以用 vscode 来打断点调试,真666~ 配置稍微复杂一些
jquery 重度患者必须品。
让 vscode 资源树目录加上图标,必备良品!
自动路劲补全
require 时的包提示(最新版的vscode已经集成此功能)
js 的注释模板 (注意:最新版的vscode已经原生支持)
ESlint 接管原生 js 提示,可以自定制提示规则。
html代码检测
在多个项目之前快速切换的工具
格式化代码的工具
修改 html 标签,自动帮你完成尾部闭合标签的同步修改
丰富的git日志插件
顶部注释模板,可定义作者、时间等信息,并会自动更新最后修改时间
让括号拥有独立的颜色,易于区分。可以配合任意主题使用。
语法高亮、智能感知、Emmet等
目前我觉得是vscode上最漂亮的主题,vscode 1.11+允许自定义statusBar等全局ui后,该主题也跟进改了很多小细节,良心!~
源于Atom,老版本的Atom One Dark主题可以扔了.
Atom是最大的开源网站github出的,可以说是后起之秀,之前说界面可以说是非常美观。但是缺点就是插件安装多了,启动就非常慢,而且会出现卡顿的现象。对一个程序员来说,最不能忍受的就是在编码期间,出现卡顿。用了很长一段时间Atom之后,决定其它而去。索性就改了vs code。在这里我也期待Atom的性能优化。不管怎样,也分享一下一些特别好用的插件。
本人比较喜欢markdown,现在也是用atom写markdown,markdown的插件有几个说明一下:
markdown-table-editor: 表格编辑器
tortoise-svn: svn工具
最近想对自己的博客增加评论系统,让大家在浏览文章的同时,可以发表自己的一些看法,这样方便一起交流。对比了一下hexo博客所支持的评论系统,网易云跟帖和畅言。畅言比云跟帖好一点就是支持微信登陆,直接发表评论,而云跟帖没有微信支持。鉴于这个特点,果断选择了畅言。
下面给大家说一下怎么在自己的博客里面配置畅言。
可以直接通过微信注册
注意:注册是需要填写ICP备案号,要符合国家规定,这个我也不知道怎么去申请,索性随便写了一个,看了一篇文章说github pages不需要备案号,也不知道是不是真的,不管了,等15天审核后,再看。除了备案号,还需要填写一个域名白名单,也就是你的hexo博客的域名,多个域名用逗号隔开
拷贝上面获取的id和key1
2
3
4changyan:
enable: true
appid:
appkey:
经过两个多星期的开发与整理,继我的第一篇原创博客《从C/C++到前端转型之路》后,终于推出了Eagles项目,为什么取名为Eagles呢?Eagles表示雄鹰,就像神雕侠侣中雕兄展翅战胜蟒蛇一样。本项目采用vue+axios+elementui技术,集成了vuex状态管理,vue-awesome字体图标库,vue-i18n国际化,mockjs模拟api数据提交,支持sass样式编译。开发了非常适合项目的低耦合组件,如:树表、拓扑图、表格、图表等,还附加菜单管理、角色权限管理、用户管理等通用项目模块。
后台技术栈暂时采用mockjs模拟Ajax数据提交,后面会用spring boot+mybatis技术给大家娓娓道来。最近也在研究spring cloud与docker微服务架构实战,后面也会有相应文章给大家分享,共同进步!
方便大家交流,已开QQ群,613176270,欢迎大家畅所欲言,温馨提示:群里有妹子哟!
1 | # 克隆项目 |
1 | |-- build # 编译目录 |
在package.json中加入jquery1
"jquery": "^1.11.1"
在webpack.base.conf.js后加入如下代码,在之前要引入webpack1
2
3
4
5
6
7
8
9var webpack = require("webpack")
plugins: [
new webpack.optimize.CommonsChunkPlugin('common.js'),
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery"
})
]
在main.js中引入jquery1
import $ from 'jquery'
国际化采用vue-i18n,但是只能使用5.x版本,使用6.x版本会发生和element兼容性问题,导致原声的element无法翻译
和Element兼容国际化引入1
2
3
4
5
6
7
8import enUS from './en-US.json'
import zhCN from './zh-CN.json'
import enLocale from 'element-ui/lib/locale/lang/en'
import zhLocale from 'element-ui/lib/locale/lang/zh-CN'
export const LANGS = {
'en-US': $.extend(enUS, enLocale),
'zh-CN': $.extend(zhCN, zhLocale)
}
vue路由热加载组件,会导致部署到Nginx后,组件无法切换的问题(切换失败)
所以如果部署到Nginx,在路由中,只能使用import加载组件
部署到Nginx后,所有静态资源访问出现404(访问失败)
原因:vue中src目录下所有的资源文件都要进行编译转码,原先用引用的静态文件将会出错,如img标签引用的静态图片文件
解决办法:将静态资源放入到和src同级的static目录,并引用此目录下文件,但是重要的一点是:开发模式和生产模式引用的static路径会有不同,于是在配置文件中加入如下代码,来区分开发模式和生产模式:1
export const STATIC_IMAGEPATH = (process.env.NODE_ENV === 'production') ? "./static/img/": "/static/img/";
另外, config/index.js下,assetsPublicPath也是不同1
assetsPublicPath: './', //生产环境assetsPublicPath: '/'
在config/index.js中配置proxyTable1
2
3
4
5
6
7
8
9
10
11
12proxyTable: {
'/ajax': {
target: 'http://127.0.0.1:8080',
// target: 'http://127.0.0.1:8081',
changeOrigin: true,
pathRewrite: {
'^/ajax': '/dirms-service'
},
onProxyReq (proxyReq, req, res) {
}
}
},
在config中加入如下,其中eagles-service为生产模式下的后台服务访问标识1
export const API_BASEURL = (process.env.NODE_ENV === 'production')? "/eagles-service":"/ajax";
QQ群:613176270
]]>纵横江湖三十余载,杀尽仇寇,败尽英雄,天下更无敌手,无可柰何,惟隐居深谷,以雕为友。呜呼,生平求一敌手而不可得,诚寂寥难堪也。剑魔独孤求败既无敌于天下,乃埋剑于斯。呜呼!群雄束手,长剑空利,不亦悲夫!
第一柄剑长四尺,锋利无比,剑下石片下写着:「凌厉刚猛,无坚不摧,弱冠前以之与河朔群雄争锋。」
第二片石片上没有剑,下面写着:「紫薇软剑,三十岁前所用,误伤义士不祥,悔恨无已,乃弃之深谷。」
剑魔独孤求败的第三把武器:「重剑无锋,大巧不工。四十岁前恃之横行天下。」外表黑黝,剑身深黑之中隐隐透出红光,三尺多长,共重八八六十四斤,两边剑锋都是钝口,剑尖圆圆的似是个半球。
第四个阶段才是渐入化境,第四柄木剑,石片上文字道:「四十岁之后不滞于物,草木竹石均可为剑。自此精进,渐入无剑胜有剑之境。」 —————《神雕侠侣》
我很欣赏《神雕侠侣》中断臂的杨过爬上华山,看到了孤独求败一生的情景。碑刻上描述了孤独求败不同时期使用的四柄剑,其中不乏深刻的人生哲理。我很佩服金庸先生,能把武侠融汇到生活中。作为现时代的我们何尝不是在追求人生的这四柄剑?
从事程序员工作三年的我,经历了很多,跳过很多家公司。先是在科大讯飞做自然语言理解,后去德拓信息做分布式存储,后又到大学教书,最后在创立做web开发。从底层C/C++、Linux跨域到web前端。虽然做过这么多,但是自己还是没达到凌厉刚猛,无坚不摧的境界,也不能说自己真正达到全栈,因为计算机技术不断的更新,也行今天你在用Vue2.0,明天也许就已经到Vue3.0,版本总是在不停地迭代。
有人问我你工作才不到3年,为什么总是喜欢跳槽?我想说的是忧患。你真正想要什么?不好说,今天也许你觉得做这个是你想做的,可是明天还能坚持吗?
最近喜欢看掘金,我觉得这个平台做的不错,对于我这个技术宅来说,很存粹。没有其他很杂很乱的东西,你在上面了解很多你未知的东西。最近一段时间,公司工作不是太忙,有点空闲时间,也想在掘金上面发表自己的文章。称不上很高端的东西,都是平常工作中使用的技术,解决的问题,和各位博友分享一下。也为开源做点自己的一份绵薄之力。如果有不对的地方,欢迎大家多多指正。
当初进公司是Java面试进来的,自学了三个月Java,面试的时候还闹了一个笑话,刚进来面试看见笔试题大部分不会做,好多JavaScript的东西。于是拿着笔试题走了,后来HR打电话说没关系,进来聊聊。就这样进了公司。刚开始嘛,就在Spring Boot+Mybatis搭的平台上面做新功能,修bug。从今年2月份开始,公司要新开发一个项目——网络设备监控,这也不是什么很新的东西,市面上有很多这样的产品。但是我们有一点不一样的东西是,我们这个要和电网资源结合起来。
公司现在项目前端的架构都是easyui做的,easyui我也做了很长一段时间,这个说实话组件特别强。基本能满足所有功能的开发,但是有一点是原生的Ui很丑,而且没有模板功能。用在设备监控系统上,就感觉很鸡肋。写了很长一段时间代码,实在是写不下去了。于是打算换前端架构。
当时也在博客上看了很多关于前端架构的东西,出现了很火的三个ReactJs,AngularJs,VueJs,可以说最近半年好多前端都是围绕这三个再转。于是我就调研了一下这三个架构,其实各有优点,综合了一下学习成本,就选择了Vue。
从今年2月份开始真正接触前端架构,去年9月到年底写过JQuery。刚接触Vue,就在github上面看了很多开源代码,学到了很多从未接触过的东西,这里非常感谢致力于开源贡献的同志们。从搭建开发框架开始,使用Vue2.0全家桶,添加JQuery,支持字体图标,Sass编译,解决跨域,开发,部署等问题,结合Ht for web加入Topo图框架,开发TreeTable组件、结合echars开发图形设计器,支持国际化等等。不知道碰到了多少坑。
不说这么多,先上一波图。
先从搭建Vue开发环境开始。后面我会把功能重构一下。《vue2全家桶+axios+element-ui系列(1)——搭建Vue开发环境》
]]>windows下安装git bash, 下载地址:https://git-for-windows.github.io/
下载地址:http://nodejs.cn/
下载对应系统最新版本,解压到某一个目录即可
配置环境变量Path
更改NPM源为国内淘宝源 npm config set registry https://registry.npm.taobao.org
npm install -g vue-cli
vue init webpack eagles
1 | npm install |
1 | . |