KiMoGiGi 技术文集

不在乎选择什么,而在乎坚持多久……

IT博客 首页 联系 聚合 管理
  185 Posts :: 14 Stories :: 48 Comments :: 0 Trackbacks

链接
http://hr.tencent.com/pages/position/morelist.shtml?location=sz&sort=tec

主要JS:
http://hr.tencent.com/scripts/hr.js
http://hr.tencent.com/scripts/xmlparser.js

页面场景:


其中右下角的分页是无须刷新页面的,怎么实现的呢?

分析代码:

1、初始化启动

先看页面的源代码,只有一句js。

$(function(){
    HRWriter.renderjoblist.render($(
"#listcontainer"));
});
Jquery式的代码,下一步看看HRWriter.renderjoblist.render有什么东东?打开“hr.js”。

2、HRWriter

先找到HRWriter这个Function,900多行!,原来不只是renderjoblist,还有renderhotlist、renderlive等等。

这些renderxxx虽然内容不同,但都有类似的结构,他们都拥有render、rendercontent两个方法。

render是根据当前URL的链接字符串获取查询条件,然后使用Ajax请求服务器获取数据,最后调用rendercontent把从Ajax获取的XML数据转化为html,呈现于页面的某个容器标记。

3、renderjoblist

重点看看HRWriter.renderjoblist。

先看看render方法,接受一个参数,这个就是要呈现数据的html一个容器,传入的是$("#listcontainer")。

//初始化呈现列表
        render:function(container)
        {
            
//获取查询字符串的值
            var sort = querystring("sort");
            
var location = querystring("location");
            
//设置Banner高亮度
            setnav("#nav"+location);
            
//设置“当前所在位置”的显示内容与样式
            setlocation(location,false);
            
//设置“当前所在位置”当前分类链接
            setsort(location, sort, true);
            
//初始化请求Ajax的链接
            //解析出的URL类似“/data/sz_tec_list.xml?time=1206545022953”
            var xmlurl = "/data/"+location+"_"+sort+"_list.xml?time="+(new Date().getTime());

            $.ajax({dataType:
"xml",type:"get",url:xmlurl,success:function(xmlDoc){
                
//分析XML,把结果存于HRWriter.renderjoblist.positions
                //其中HRWriter.renderjoblist.positions.type为类型
                //    HRWriter.renderjoblist.positions.list为工作列表
                HRWriter.renderjoblist.positions.type = XmlParser.GetNodeValue(xmlDoc.selectSingleNode("//type"));
                
var items = xmlDoc.selectNodes("//position");
                HRWriter.renderjoblist.positions.list 
= new Array();
                
for(var i=0;i<items.length;i++)
                {
                    
var position = new Object();
                    position.id 
= XmlParser.GetNodeValue(items[i].selectSingleNode("id"));
                    position.positionname 
= XmlParser.GetNodeValue(items[i].selectSingleNode("positionname"));
                    position.avaiablenum 
= XmlParser.GetNodeValue(items[i].selectSingleNode("avaiablenum"));
                    position.emergency 
= XmlParser.GetNodeValue(items[i].selectSingleNode("emergency"));     
                    HRWriter.renderjoblist.positions.list.push(position);
                }
                
//显示与html中
                //rendercontent把数据转化为html
                container.html(HRWriter.renderjoblist.rendercontent(HRWriter.renderjoblist.positions));
            }});
        },

我整理代码格式和添加了一些注释。

继续往下看到querystring方法。这是根据url获取查询字符串数据的方法。

function querystring(fieldName)
{  
  
var urlString = document.location.search;
  
if(urlString)
  {
    
var typeQu = fieldName+"=";
    
var urlEnd = urlString.indexOf(typeQu);
    
    
if(urlEnd != -1)
    {
        
var paramsUrl = urlString.substring(urlEnd+typeQu.length);
        
var isEnd =  paramsUrl.indexOf('&');
        
if(isEnd != -1)
        {
            
return paramsUrl.substring(0, isEnd);
        }
        
else
        {
            
return paramsUrl;
        }
    }
    
else 
        
return null;
    }
    
else
        
return null;
}

其中的算法很简单,先取得urlString(如?location=sz&sort=tec);
算计出(fieldName+'=')在查询字符串的索引,然后截取,(如sz&sort=tec);
在算计第一个&,做最后的截取。(如获取sz)。

回到renderjoblist.render,开始获取location和sort(地区和分类),即查询条件。然后用了3个setxxx的方法,作用是把导航栏部分,根据查询条件高亮度。

由左至右、上至下方向,分别起作用的函数为
setlocation(location,false);
setsort(location, sort, true);
setnav("#nav"+location);

4、Ajax

重点的Ajax请求,先利用查询条件,组合出需要请求的链接。
           
//初始化请求Ajax的链接
//
解析出的URL类似“/data/sz_tec_list.xml?time=1206545022953”
var xmlurl = "/data/"+location+"_"+sort+"_list.xml?time="+(new Date().getTime());

我们直接用浏览器来看看这个链接(http://hr.tencent.com/data/sz_tec_list.xml?time=1206545022953)返回的是什么东东?

原来用Ajax请求的xml数据是这些。主要的是positionlist,这些就是所有数据的集合。但需要注意的是,这里不止是“第一页”的数据,而是全部的数据。

$.ajax({dataType:"xml",type:"get",url:xmlurl,success:function(xmlDoc){
                
//分析XML,把结果存于HRWriter.renderjoblist.positions
                //其中HRWriter.renderjoblist.positions.type为类型
                //    HRWriter.renderjoblist.positions.list为工作列表
                HRWriter.renderjoblist.positions.type = XmlParser.GetNodeValue(xmlDoc.selectSingleNode("//type"));
                
var items = xmlDoc.selectNodes("//position");
                HRWriter.renderjoblist.positions.list 
= new Array();
                
for(var i=0;i<items.length;i++)
                {
                    
var position = new Object();
                    position.id 
= XmlParser.GetNodeValue(items[i].selectSingleNode("id"));
                    position.positionname 
= XmlParser.GetNodeValue(items[i].selectSingleNode("positionname"));
                    position.avaiablenum 
= XmlParser.GetNodeValue(items[i].selectSingleNode("avaiablenum"));
                    position.emergency 
= XmlParser.GetNodeValue(items[i].selectSingleNode("emergency"));     
                    HRWriter.renderjoblist.positions.list.push(position);
                }
                
//显示与html中
                //rendercontent把数据转化为html
                container.html(HRWriter.renderjoblist.rendercontent(HRWriter.renderjoblist.positions));
            }});

看看在最后请求成功后,success添加了一个回调函数,参数正是由Jquery解释XML的一个XMLDocument对象。
在Callback函数中,使用XmlParser获取节点的值(因为IE和FF获取xml的innerText值方式不同)。
解释XML数据把其存储在HRWriter.renderjoblist.positions,其中的list属性,是一个Array,存储xml各个position的内容。
最后使用HRWriter.renderjoblist.rendercontent把数据转换html呈现于container的html中。

5、rendercontent

rendercontent:function(positions)
        {
            
var content = "";
            
var pageSize = HRWriter.renderjoblist.pageSize;
        
            content 
+= "<div class=\"jobdetailtitle\">";
            content 
+="<h5>"+positions.type+"</h5>";
            content 
+="</div>";
            content 
+="<table class=\"joblist\">";
            content 
+="<thead>";
            content 
+="<tr>";
            content 
+="<th>职位名称</th>";
            content 
+="<th>招聘人数</th>";
            content 
+="<th>招聘类型</th>";
            content 
+="</tr>";
            content 
+="</thead>";
            content 
+="<tbody id=\"joblist\">";
            content 
+= HRWriter.renderjoblist.renderjoblist(0);            
            content 
+="</tbody>";
            content 
+="<tfoot>";
            content 
+="<tr>";
            content 
+="<td colspan=\"3\">";
            
            
var pagecount = Math.ceil(positions.list.length/pageSize);
            
//初始化“上一页”为隐藏
            content +="<a href=\"javascript:void(0)\" id=\"prepage\" style=\"display:none\" >上一页</a>";
            
//初始化“第一页”为当前页
            content +="<a href=\"javascript:void(0)\" class=\"curpage\" onclick=\"HRWriter.renderjoblist.pagechanged(0);\" id=\"pageindex0\">1</a>";
            
for(var k = 1; k < pagecount; k++)
            {
                content 
+="<a href=\"javascript:void(0)\" onclick=\"HRWriter.renderjoblist.pagechanged("+k+");\" id=\"pageindex"+k+"\">"+(k+1)+"</a>";
            }
            
//如果页数大于一页,则有“下一页”
            if(pagecount>1)//next page
            {
                content 
+="<a href=\"javascript:void(0)\" id=\"nextpage\" onclick=\"HRWriter.renderjoblist.pagechanged(1);\" >下一页</a>";
            }
            content 
+= "</td>";
            content 
+= "</tr>";
            content 
+= "</tfoot>";
            content 
+= "</table>";
            
return content;
        },

这里就把初始化“第一页”的数据转化成html。
至此,才完成了初始化的任务,还有分页呢?这里注意的是在tfoot中,对每一个页数添加onclick事件的函数 -- HRWriter.renderjoblist.pagechanged。

6、pagechanged

pagechanged:function(pageindex)
        {
            
//获取id为joblist的table
            var joblist = $('#joblist');
            
//获取页数需要的数据
            joblist.html(HRWriter.renderjoblist.renderjoblist(pageindex));
            
//取消旧的当前页数的样式
            $("a.curpage").removeClass("curpage");
            
//为当前页数添加样式
            $("#pageindex"+pageindex).addClass("curpage");
            
//计算页数
            var pagecount = Math.ceil(HRWriter.renderjoblist.positions.list.length/HRWriter.renderjoblist.pageSize);
            
            
if(pageindex < pagecount-1)
            {
                $(
"#nextpage").attr("onclick""");
                $(
"#nextpage").unbind("click");
                document.getElementById(
"nextpage").onclick = function(){HRWriter.renderjoblist.pagechanged(pageindex+1)};
                
//$("#nextpage").click(function(){alert('sd');HRWriter.renderjoblist.pagechanged(pageindex+1)});
                $("#nextpage").css("display","");
            }
            
//如果当前页数为最后一页,隐藏“下一页”
            else
            {
                $(
"#nextpage").css("display","none");
            }
            
            
if(pageindex>0)
            {
                $(
"#prepage").attr("onclick""");
                $(
"#prepage").unbind("click");
                document.getElementById(
"prepage").onclick = function(){HRWriter.renderjoblist.pagechanged(pageindex-1)};
                
//$("#prepage").click(function(){HRWriter.renderjoblist.pagechanged(pageindex-1)});
                $("#prepage").css("display","");                    
            }
            
//如果当前页数为第一页,隐藏“上一页”
            else
            {
                $(
"#prepage").css("display","none");
            }
        }
先忽略joblist.html(HRWriter.renderjoblist.renderjoblist(pageindex));
我们可以看到这个函数,没有获取数据的地方,主要是重组分页器的样式。
留意一下,刷新prepage(或nextpage)的click事件的方式。
为什么直接用unbind就不行了,一定要用document.getElementById("prepage").onclick = function(){...}
原来在rendercontent中,是在html为prepage的onclick赋值的,如<a id='prepage' onclick='xxxxx'>上一页</a>
正因为如此,jquery不能unbind在html写死的onclick函数,因此必须用document.getElementById("prepage").onclick = function(){...}方式重写。
至于,个人觉得
$("#prepage").attr("onclick", "");
$("#prepage").unbind("click");
document.getElementById("prepage").onclick = function(){HRWriter.renderjoblist.pagechanged(pageindex-1)};
3句有点多余,只有最后一句就可以了,或者要2、3就可以了。

7、renderjoblist

这是分页获取数据的方法。
renderjoblist:function(pageindex)
        {
            
var pageSize = HRWriter.renderjoblist.pageSize;
            
var startPos = pageindex*pageSize;
            
var tempContent = "";
            
//获取URL中的location信息
            var location = querystring("location");
            
//搜索内存中已有的数据HRWriter.renderjoblist.positions.list
            //从中获取当前页数需要的数据
            for(var j = startPos ; j < HRWriter.renderjoblist.positions.list.length && j<startPos+pageSize; j ++)
            {
                
with(HRWriter.renderjoblist.positions.list[j])
                {
                    
//组合table中每行的数据
                    tempContent +="<tr onmouseover=\"this.className='mouseover'\" onmouseout=\"this.className=''\">";
                    tempContent 
+="<td class=\"title\">";
                    tempContent 
+="<a href=\"detail.shtml?jobid="+id+ "&location=" + location +"\">"+positionname+"</a>";
                    tempContent 
+="</td>";
                    tempContent 
+="<td class=\"availnum\">"+avaiablenum+"</td>";
                    
if(emergency.indexOf(""> -1)
                        tempContent 
+="<td class=\"type\"><span class=\"urgency\">急聘</span></td>";
                    
else
                        tempContent 
+="<td class=\"type\"><span>-</span></td>";
                        
                    tempContent 
+="</tr>";
                }
            }
            
return tempContent;
        },

可以看到这里并没有地方用Ajax,因为在初始化第一次的时候,已经用Ajax把数据全部输出出来了,缓存于HRWriter.renderjoblist.positions.list变量中。
这里的工作只是遍历HRWriter.renderjoblist.positions.list,获取相应的数据组成html刷新container的html,就完成的分页的效果。

8、完整代码如下

renderjoblist:
    {
        positions:
new Object(),
        pageSize:
20,
        
//初始化呈现列表
        render:function(container)
        {
            
//获取查询字符串的值
            var sort = querystring("sort");
            
var location = querystring("location");
            
//设置Banner高亮度
            setnav("#nav"+location);
            
//设置“当前所在位置”的显示内容与样式
            setlocation(location,false);
            
//设置“当前所在位置”当前分类链接
            setsort(location, sort, true);
            
//初始化请求Ajax的链接
            //解析出的URL类似“/data/sz_tec_list.xml?time=1206545022953”
            var xmlurl = "/data/"+location+"_"+sort+"_list.xml?time="+(new Date().getTime());

            $.ajax({dataType:
"xml",type:"get",url:xmlurl,success:function(xmlDoc){
                
//分析XML,把结果存于HRWriter.renderjoblist.positions
                //其中HRWriter.renderjoblist.positions.type为类型
                //    HRWriter.renderjoblist.positions.list为工作列表
                HRWriter.renderjoblist.positions.type = XmlParser.GetNodeValue(xmlDoc.selectSingleNode("//type"));
                
var items = xmlDoc.selectNodes("//position");
                HRWriter.renderjoblist.positions.list 
= new Array();
                
for(var i=0;i<items.length;i++)
                {
                    
var position = new Object();
                    position.id 
= XmlParser.GetNodeValue(items[i].selectSingleNode("id"));
                    position.positionname 
= XmlParser.GetNodeValue(items[i].selectSingleNode("positionname"));
                    position.avaiablenum 
= XmlParser.GetNodeValue(items[i].selectSingleNode("avaiablenum"));
                    position.emergency 
= XmlParser.GetNodeValue(items[i].selectSingleNode("emergency"));     
                    HRWriter.renderjoblist.positions.list.push(position);
                }
                
//显示与html中
                //rendercontent把数据转化为html
                container.html(HRWriter.renderjoblist.rendercontent(HRWriter.renderjoblist.positions));
            }});
        },
        rendercontent:
function(positions)
        {
            
var content = "";
            
var pageSize = HRWriter.renderjoblist.pageSize;
        
            content 
+= "<div class=\"jobdetailtitle\">";
            content 
+="<h5>"+positions.type+"</h5>";
            content 
+="</div>";
            content 
+="<table class=\"joblist\">";
            content 
+="<thead>";
            content 
+="<tr>";
            content 
+="<th>职位名称</th>";
            content 
+="<th>招聘人数</th>";
            content 
+="<th>招聘类型</th>";
            content 
+="</tr>";
            content 
+="</thead>";
            content 
+="<tbody id=\"joblist\">";
            content 
+= HRWriter.renderjoblist.renderjoblist(0);            
            content 
+="</tbody>";
            content 
+="<tfoot>";
            content 
+="<tr>";
            content 
+="<td colspan=\"3\">";
            
            
var pagecount = Math.ceil(positions.list.length/pageSize);
            
//初始化“上一页”为隐藏
            content +="<a href=\"javascript:void(0)\" id=\"prepage\" style=\"display:none\" >上一页</a>";
            
//初始化“第一页”为当前页
            content +="<a href=\"javascript:void(0)\" class=\"curpage\" onclick=\"HRWriter.renderjoblist.pagechanged(0);\" id=\"pageindex0\">1</a>";
            
for(var k = 1; k < pagecount; k++)
            {
                content 
+="<a href=\"javascript:void(0)\" onclick=\"HRWriter.renderjoblist.pagechanged("+k+");\" id=\"pageindex"+k+"\">"+(k+1)+"</a>";
            }
            
//如果页数大于一页,则有“下一页”
            if(pagecount>1)//next page
            {
                content 
+="<a href=\"javascript:void(0)\" id=\"nextpage\" onclick=\"HRWriter.renderjoblist.pagechanged(1);\" >下一页</a>";
            }
            content 
+= "</td>";
            content 
+= "</tr>";
            content 
+= "</tfoot>";
            content 
+= "</table>";
            
return content;
        },
        renderjoblist:
function(pageindex)
        {
            
var pageSize = HRWriter.renderjoblist.pageSize;
            
var startPos = pageindex*pageSize;
            
var tempContent = "";
            
//获取URL中的location信息
            var location = querystring("location");
            
//搜索内存中已有的数据HRWriter.renderjoblist.positions.list
            //从中获取当前页数需要的数据
            for(var j = startPos ; j < HRWriter.renderjoblist.positions.list.length && j<startPos+pageSize; j ++)
            {
                
with(HRWriter.renderjoblist.positions.list[j])
                {
                    
//组合table中每行的数据
                    tempContent +="<tr onmouseover=\"this.className='mouseover'\" onmouseout=\"this.className=''\">";
                    tempContent 
+="<td class=\"title\">";
                    tempContent 
+="<a href=\"detail.shtml?jobid="+id+ "&location=" + location +"\">"+positionname+"</a>";
                    tempContent 
+="</td>";
                    tempContent 
+="<td class=\"availnum\">"+avaiablenum+"</td>";
                    
if(emergency.indexOf(""> -1)
                        tempContent 
+="<td class=\"type\"><span class=\"urgency\">急聘</span></td>";
                    
else
                        tempContent 
+="<td class=\"type\"><span>-</span></td>";
                        
                    tempContent 
+="</tr>";
                }
            }
            
return tempContent;
        },
        pagechanged:
function(pageindex)
        {
            
//获取id为joblist的table
            var joblist = $('#joblist');
            
//获取页数需要的数据
            joblist.html(HRWriter.renderjoblist.renderjoblist(pageindex));
            
//取消旧的当前页数的样式
            $("a.curpage").removeClass("curpage");
            
//为当前页数添加样式
            $("#pageindex"+pageindex).addClass("curpage");
            
//计算页数
            var pagecount = Math.ceil(HRWriter.renderjoblist.positions.list.length/HRWriter.renderjoblist.pageSize);
            
            
if(pageindex < pagecount-1)
            {
                $(
"#nextpage").attr("onclick""");
                $(
"#nextpage").unbind("click");
                document.getElementById(
"nextpage").onclick = function(){HRWriter.renderjoblist.pagechanged(pageindex+1)};
                
//$("#nextpage").click(function(){alert('sd');HRWriter.renderjoblist.pagechanged(pageindex+1)});
                $("#nextpage").css("display","");
            }
            
//如果当前页数为最后一页,隐藏“下一页”
            else
            {
                $(
"#nextpage").css("display","none");
            }
            
            
if(pageindex>0)
            {
                $(
"#prepage").attr("onclick""");
                $(
"#prepage").unbind("click");
                document.getElementById(
"prepage").onclick = function(){HRWriter.renderjoblist.pagechanged(pageindex-1)};
                
//$("#prepage").click(function(){HRWriter.renderjoblist.pagechanged(pageindex-1)});
                $("#prepage").css("display","");                    
            }
            
//如果当前页数为第一页,隐藏“上一页”
            else
            {
                $(
"#prepage").css("display","none");
            }
        }
    },


9、总结

这段脚本不复杂,特点是一次性获取数据到js的变量,然后分页时在变量中遍历需要的数据。

缺点显而易见,如果数据量太大的时候,第一次加载时间会很长;而且翻页的时候,对客户端配置剩余内存低的,显示会滞慢。

本人认为,可以改善地方:
1、在组织html,添加字符串时,不要使用“+=”,尝试使用数组Array把字符串push进去,最后用join把字符串连接起来,效率会高点。
2、Ajax返回的直接是json的话,可以减少解析XML的时间。
3、尽量不要使用html嵌入js的方式,为元素绑定click方法,尽量在js代码做。
posted on 2008-03-25 23:36 KiMoGiGi 阅读(646) 评论(0)  编辑 收藏 引用 所属分类: JavaScript
只有注册用户登录后才能发表评论。