前端開發規范
1.HTML規范
1.1.使用正確的HTML5文檔類型
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="renderer" content="webkit"> <!-- 360使用極速模式渲染 -->
<title>Document</title>
</head>
<body>
</body>
</html>
1.2 兼容的meta屬性
<meta name="renderer" content="webkit"> <!-- 360使用極速模式渲染 -->
1.3 統一使用4空格的tab縮進
1.4.避免不規范的元素嵌套
錯誤示例:
<ul>
<div>導航欄標題</div>
<li>子項1</li>
<li>子項2</li>
<ul>
正確示例:
<div>導航欄標題</div>
<ul>
<li>子項1</li>
<li>子項2</li>
<ul>
ul
標簽只允許存在li
作為其直接子標簽。錯誤示例中的代碼雖然可以正常渲染,但是由于不同瀏覽器容錯機制不一致,錯誤的示例代碼可能會導致額外的hack。
1.5.自定義屬性采用data-*
格式
錯誤示例:
<div ng-click="click()">
正確示例:
<div data-ng-click="click()">
data-*
是HTML5的標準規范,如不采用data-*
格式,IDE會顯示警告信息,避免警告信息影響正常的debug,建議采用data-*
格式自定義屬性。
1.6.布爾類型的屬性,建議不添加屬性值
錯誤示例:
<input type="checkbox" checked="true">
<input type="checkbox" checked="flase">
<input type="checkbox" checked="checked">
正確示例:
<input type="checkbox" checked>
獲取選擇選中狀態,使用dom節點對象的checked屬性,或者jQuery的is方法,不要使用attr('checked')進行判斷。
錯誤做法:
var $checkbox = $('input[checkbox]');
$checkbox.attr("checked"); // 不準確,甚至會取得非預期值
正確做法:
$checkbox.is(':checked');
$checkbox.check = true;
$checkbox.check;
2.CSS規范
2.1.確定全局唯一的元素,可以使用id,否則使用class
否則會導致后期維護成本過大。
2.2.選擇器應盡量避免嵌套,最多不過3級別
不好的做法:
body #container .head .title {
// code here
}
推薦做法:
.h-title {
// code here
}
嵌套過多,會導致css權重過大,子class跟父class緊耦合,后期維護成本大。
3.JavaScript規范
3.1.字符串統一使用單引號包含
不好的示例:
var msg = "Hello JavaScript!";
正確示例:
var msg = 'Hello JavaScript!';
使用單引號的最主要原因是,避免額外的單引號\雙引號轉義。
var dom = “<div data-ng-click=\"click();\">雙引號\"\"不建議</div>”;
vs
var dom = '<div data-ng-click="click();">雙引號""不建議</div>';
兩種寫法對比,優劣一目了然。
3.2.避免使用JavaScript拼接HTML
使用JavaScript拼接HTML,會有以下問題:
- 極容易產生XSS漏洞;
- 關注點不分離,升級維護極其困難;
- 開發效率低下,代碼不健壯,非常容易產生bug;
- Debug變的異常艱難;
不好的示例:
var names = ['tiger','apple', '<script>alert("xss");</script>'];
var dom = '<ul>';
names.forEach(function(name,index){
dom += '<li>' + name + '</li>';
})
dom += '</ul>';
$('body').html(dom);
上面的代碼會導致一下問題:
- names[2]插入頁面后,
<script>alert("xss");<script>
會被當成腳本執行,容易被用戶利用,入侵系統; - 代碼升級維護困難,如果要修改樣式,或者渲染的對象更加復雜(多層嵌套),維護這樣的代碼不僅效率低下,容易出錯,簡直就是噩夢;
- 產生bug的情況下,調試異常復雜;
正確示例:
AngularJS寫法:
<ul>
<li data-ng-repeat="name in names">{{ name }}</li>
</ul>
如果使用jQuery情況下,可以使用前端模板引擎,例如doT.js、jQuery Template等。
3.3 JavaScript語法技巧
使用這些小技巧,可以讓代碼更加簡潔、容易理解。
3.3.1 默認參數賦值
冗長寫法:
function fun(param) {
if(param == null) {
param = {name:'tiger'};
}
}
簡潔寫法:
function fun(param) {
param = param || {name:'tiger'};
}
3.3.2 判空執行
冗長寫法:
function fun() {
if(flag) {
callback();
}
}
簡潔寫法:
function fun() {
flag && callback();
}
3.3.3 自調用函數
冗長寫法:
function fun(){
// code here
}
fun();
簡潔寫法:
(function(){
// code here
})();
3.3.4 數組迭代
冗長寫法:for
簡潔寫法:filter、some、every、forEach、map
3.3.4.2 filter:對數組進行過濾,并返回新的數組
var s = [1,2,3,4,5];
var ns = s.filter(function(item,index) {
return item > 3;
})
console.log(ns); // [4,5]
3.3.4.3 some:判斷數組中是否有符合條件的元素
var s = [1,2,3,4,5];
var b = s.some(function(item,index) {
return item > 3;
})
console.log(b); // true
3.3.4.4 every:判斷數組中所有元素是否都符合條件
var s = [1,2,3,4,5];
var b = s.every(function(item,index) {
return item > 3;
})
console.log(b); // false
3.3.4.5 map:對數組中的元素進行處理,并返回新的數組
var s = [1,2,3,4,5];
var ns = s.map(function(item,index) {
return item * 2;
})
console.log(ns); // [2,4,6,8,10]
3.3.4.6 forEach:迭代數組元素
var s = [1,2,3,4,5];
var ns = s.map(function(item,index) {
console.log(item); // 依次打印1,2,3,4,5
})
3.4. 前端開發的JavaScript技巧
3.4.1 使用Angular時,ajax請求請使用ng自帶的$http,避免使用jQuery的ajax
$http的ajax回調會自動更新DOM節點,而jQuery的回調沒有這個特征,需要手動apply。
<div>{{ user.username }}</div>
正確的jQuery寫法:
$.post('/login',{username:'tiger',passwd='123456'},function(rs){
$scope.user = rs.user;
$scope.$apply();
})
正確的AngularJS寫法:
var params = {username:'tiger',passwd='123456'}
$http({method : 'POST',url : '/login', data: $.param(params)
}).then(function(rs) {
$scope.user = rs.data.user;
});
如果是GET請求,data則改成params,同時不需要$.param序列化,params的參數放url上,而data是放request body中。
var params = {username:'tiger',passwd='123456'}
$http({method : 'GET',url : '/login', params: params
}).then(function(rs) {
$scope.user = rs.data.user;
});
3.4.2 HTTP請求中,獲取使用GET,提交、修改和刪除使用POST
這樣更加符合REST的語義,如果POST使用GET代替,在開發階段就難以調試,而且無法使用GET的特性進行一系列調優,例如緩存等。
HTTP中,GET/POST/DEL等的區別:http://www.cnblogs.com/zhangpengshou/archive/2012/07/09/2583096.html
3.4.3 獲取ajax的表單參數,jQuery可以將form表單序列化,Angualr可以綁定對象
推薦的jQuery寫法:
<form id="loginFrom">
<input name="username" type="text" />
<input name="password" type="passwrod"/>
</form>
<script>
var params = $('#loginForm').serialize();
$.post('/login',params,function(rs){
// callback
});
</script>
推薦的AngularJS寫法:
<form>
<input type="text" data-ng-model="loginForm.username" />
<input type="passwrod" data-ng-model="loginForm.password"/>
</form>
<script>
$http({
method : 'POST',
url : '/login',
data: $.param($scope.loginForm)
}).then(function(rs) {
// callback說
});
</script>
3.4.4 jQuey調用AngularJS的方法
思路:取得AngularJS作用域下的節點找到scope,通過scope調用方法:
var container = $('#container'); // #containe要在data-ng-app的子節點下
angular.element(container).scope().fun(); // 調用AngularJS下面的fun方法;
強烈推薦使用Angular開發,jQuery的功能基本95%以上都可以用Angular代替,代碼量更少,更容易維護。
JavaScript的String添加了個encodeHTML方法,可以對HTML的特殊字符進行轉義,實現如下:
String.prototype.encodeHTML = function () {
var div = document.createElement('div');
div.appendChild(document.createTextNode(this));
return div.innerHTML;
}
如果輸出到頁面的內容由HTML拼接完成,且內容存在用戶輸入的部分,則拼接過程中,對應字段需要經過HTML轉義,用法如下:
function format(name){
return '<div>' + name.encodeHTML() + '</div>';
}
腳本實現在eompBase.js中,導入該腳本的頁面,都可以按照上面的寫法進行轉義。