2011 年10月15日,我參加了北京地區騰訊校招Web 前端的筆試,關於前端的題只用兩道題,其他爲基礎題,可就是這兩道題就足足花了我將近兩個小時,以致最終其他基礎題目我一道未答,雖然題目並不是很難,但確實其中有一道題的確令人懷念,究其原因,就是自己學藝不精,雖然筆試結束後我把這道題完成了,但裏面的陷阱之多非筆試時所能想到。現在騰訊的校招基本業已結束,這道題也可大膽的公佈在日誌中了,另外本人技術有限,希望各位JS高手多多指教。(因爲只有ie6 ,所以兼容性沒有測試)
題目如下:
1. 雙擊學號*, 高數*, 英語*可按照相應列進行正序排序,再次雙擊進行逆序排序;
2. 單擊任意數據行改變背景色爲灰色,再次單擊同一行回覆原來背景色白色;
3. 在選中某一數據行爲灰色情況下,敲擊鍵盤A鍵使得數據行下滑一行,同時背景下調;
4. 在選中某一數據行爲灰色情況下,敲擊鍵盤Z鍵使得數據行上升一行,同時背景上升;
筆試的時候,剛看了一問,以爲很簡單,就直接下手開寫,誰成想接下的幾問越寫越複雜,只能將前問構架推翻重寫,基本上是寫了又劃,劃了又寫,代價慘痛不已。本人自問歷經多場筆試,早已成竹於胸,亦未出現如此狼狽。真應該審題仔細後再下筆。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>表格排序</title>
<style type="text/css">
table th, table tr
{
cursor: pointer;
}
.currentStyle
{
background: #ccc;
}
</style>
</head>
<body>
<table border="1" cellspacing="0">
<tr>
<th>姓名</th>
<th class="sortedTable_th">學號 * </th>
<th class="sortedTable_th">高數 * </th>
<th class="sortedTable_th">英語 * </th>
</tr>
<tr class="sortedTable_tr">
<td>張三</td>
<td>20091234</td>
<td>88</td>
<td>99</td>
</tr>
<tr class="sortedTable_tr">
<td>李四</td>
<td>20092345</td>
<td>85</td>
<td>92</td>
</tr>
<tr class="sortedTable_tr">
<td>王二</td>
<td>20094567</td>
<td>79</td>
<td>100</td>
</tr>
</table>
<script type="text/javascript">
// 組件方法
var GLOBAL = {};
GLOBAL.DOM = {};
// 1. getElementsByClassName
GLOBAL.DOM.getElementsByClassName = function(str, root, tag){
root = root || document;
tag = tag || "*";
var results =[];
var elements = root.getElementsByTagName(tag);
for(var i = 0, len = elements.length; i < len; i++)
{
for(var j = 0, classNames = elements[i].className.split(" "), len2 = classNames.length; j < len2; j++)
{
if(str == classNames[j])
{
results.push(elements[i]);
break;
}
}
}
return results;
}
// 2. addClass
GLOBAL.DOM.addClass = function(node, str)
{
var temp = node.className;
if(!new RegExp("(\\s)*" + str).test(temp))
{
node.className = temp + " " + str;
}
}
// 3. removeClass
GLOBAL.DOM.removeClass =function(node, str)
{
node.className = node.className.replace(new RegExp("(\\s)*" + str),"");
}
function SortedTable()
{
// 類sortedTable 的私有數據
var sortedTable_ths = GLOBAL.DOM.getElementsByClassName("sortedTable_th");
var sortedTable_trs =GLOBAL.DOM.getElementsByClassName("sortedTable_tr");
var results = [];
// 類sortedTable 的內部類,用於表示表格數據項
function Data(name,stuNo,math,english)
{
this.name = name;
this.stuNo = stuNo;
this.math = math;
this.english = english;
this.getPropertyNameByIndex = function(i)
{
var propertyName = null;
switch(i)
{
case 1 : propertyName = "stuNo"; break;
case 2 : propertyName = "math"; break;
case 3 : propertyName = "english"; break;
}
return propertyName;
}
}
// 表格數據項的排序方法
function compare(propertyName, flag)
{
return function(obj1, obj2)
{
var value1 = obj1[propertyName];
var value2 = obj2[propertyName];
// 正序
if(flag == 1)
return value1 - value2;
// 逆序
else if(flag == 2)
return value2 - value1;
}
}
// 排序或滑動後重置表格數據
function setTableContent(results)
{
var sortedTable_tds = null;
for(var i=0,len=results.length; i < len; i++)
{
sortedTable_tds = sortedTable_trs[i].cells;
sortedTable_tds[0].innerHTML = results[i].name;
sortedTable_tds[1].innerHTML = results[i].stuNo;
sortedTable_tds[2].innerHTML = results[i].math;
sortedTable_tds[3].innerHTML = results[i].english;
}
}
// 公共方法 1 填充數據
this.setData = function()
{
var tempArr = [];
for(var i = 0, len = sortedTable_trs.length; i < len; i++)
{
for(var j = 0, sortedTable_tds = sortedTable_trs[i].getElementsByTagName("td"), len2 = sortedTable_tds.length; j < len2; j++)
{
tempArr.push(j == 0 ? sortedTable_tds[j].innerHTML : parseInt(sortedTable_tds[j].innerHTML));
}
results.push(new Data(tempArr[0],tempArr[1],tempArr[2],tempArr[3]));
tempArr.length = 0;
}
}
// 公共方法2 設定排序
this.setSorted = function()
{
var tempArr = [];
for(var i = 0, len = sortedTable_ths.length; i<len; i++)
{
// 避免閉包所帶來的問題
(function(_i)
{
// 正序逆序標誌
var flag = 1;
var data = new Data();
sortedTable_ths[_i].ondblclick = function(event)
{
event = event || window.event;
var target = event.target || event.srcElement;
// index 從1 開始,因爲姓名項不可排序
results.sort(compare(data.getPropertyNameByIndex(_i + 1),flag));
if(flag == 1)
{
flag = 2;
} else if(flag == 2)
{
flag = 1;
}
setTableContent(results);
// 重置背景顏色
var currentTrs = GLOBAL.DOM.getElementsByClassName("currentStyle");
if(currentTrs.length != 0)
GLOBAL.DOM.removeClass(currentTrs[0], "currentStyle");
}
})(i);
}
}
//公共方法3 更改表格顏色及觸發鍵盤事件
this.toggleTableColorAndLocation = function()
{
for(var i =0, len = sortedTable_trs.length; i < len ; i++)
{
(function(_i)
{
sortedTable_trs[_i].onclick = function()
{
var currentTrs = GLOBAL.DOM.getElementsByClassName("currentStyle");
if(currentTrs.length == 0)
{
GLOBAL.DOM.addClass(this,"currentStyle");
// 只有在選中的情況下才可能觸發移動
moveTable(this, _i);
} else if(currentTrs[0] != this)
{
GLOBAL.DOM.removeClass(currentTrs[0],"currentStyle");
GLOBAL.DOM.addClass(this,"currentStyle");
// 只有在選中的情況下才可能觸發移動
moveTable(this, _i);
} else
{
GLOBAL.DOM.removeClass(this, "currentStyle");
}
}
})(i);
}
}
// 移動表格的私有方法,通過單擊事件進行觸發;
function moveTable(tr, index)
{
// 採用事件委託機制,因爲ff 不支持 tr 下的onkeydown 事件
document.onkeydown = function(event)
{
var currentTrs = GLOBAL.DOM.getElementsByClassName("currentStyle");
if(currentTrs.length != 0)
{
event = event || window.event;
var item = null,
len = sortedTable_trs.length,
code = event.keyCode || event.which || event.charCode;
if(code == 65)
{
item = results.pop();
results.unshift(item);
(index + 1) % len == 0 ? index = 0 : index ++;
} else if(code == 90)
{
item = results.shift();
results.push(item);
(index - 1 < 0) ? index = len -1 : index --;
}
setTableContent(results);
GLOBAL.DOM.removeClass(currentTrs[0],"currentStyle");
GLOBAL.DOM.addClass(sortedTable_trs[index],"currentStyle");
}
}
}
}
window.onload = function()
{
var table = new SortedTable();
// 1. 填充數據
// 2. 綁定排序事件
// 3. 綁定更改顏色及鍵盤事件
table.setData();
table.setSorted();
table.toggleTableColorAndLocation();
}
</script>
</body>
</html>