#2
yaohaixiao2008-01-30 22:01
大结局(XMLHttpRequest对象)
好了,到了ajax关键时刻了。
程序代码: /* =========================================================== * 函数名称:ajaxUpdater(tarObj,sMethod,URL,parameters) * 参数说明:tarObj - 异步获取信息希望显示的目标节点ID * sMethod - 数据提交方法,两个可选值get,post * URL - 提交的目标URL地址 * parameters - URL后面接(传递)的参数 * 函数功能:将异步传递的目标URL地址返回的信息,无刷新的写到目标 * 节点(tarObj)中 * 返 回 值:new Error() - 运行错误时返回一个报错信息 * 使用方法:var myAjax = ajaxUpdater(msgBox,"get",URL,para); ============================================================ */ function ajaxUpdater(tarObj,sMethod,URL,parameters){ var oXmlHttp = createXMLHTTPRequest(); oXmlHttp.open(sMethod, URL+parameters, true); oXmlHttp.onreadystatechange = function () { if (oXmlHttp.readyState == 4) { if (oXmlHttp.status == 200) { if($(tarObj)){ $(tarObj).innerHTML = oXmlHttp.responseText; } else{ return false; } } else { throw new Error("有一个错误产生!"); } } } oXmlHttp.send(null); } 绕了这么多圈,又回到我们文章开始提到的,现在要开始运用[url=http://www.]XMLHttpRequest对象[/url]的相关知识了。 var oXmlHttp = createXMLHTTPRequest();首先是创建XMLHttpRequest对象,我们使用的是createXMLHTTPRequest(): /* =========================================================== * 函数名称:createXMLHTTPRequest() * 参数说明:无参数 * 函数功能:创建XMLHttpRequest对象 * 返 回 值:XMLHTTPRequest对象 * 使用方法:var oXmlHttp = createXMLHTTPRequest(); ============================================================ */ function createXMLHTTPRequest(){ // 非IE浏览器(Firefox,Opera),XMLHttpRequest对象是浏览器内置的一个对象 if (useXmlHttp){ return new XMLHttpRequest(); } else if (useActiveX) { //在IE(IE< 7.0 = use ActiveX)浏览器中,XMLHttpRequest对象是以ActiveX控件的形式存在的 if (!XMLHTTP_VER) { for (var i=0; i < ARR_XMLHTTP_VERS.length; i++){ try { new ActiveXObject(ARR_XMLHTTP_VERS[i]); XMLHTTP_VER = ARR_XMLHTTP_VERS[i]; // 获取本地IE浏览器相应的XMLHttpRequest对象版本 break; } catch (oError) {} } } if (XMLHTTP_VER) { return new ActiveXObject(XMLHTTP_VER); } else { throw new Error("无法创建XMLHttpRequest对象!"); } } else { throw new Error("您的浏览器不支持XMLHttpRequest对象!"); } } 不同的浏览器XMLHttpRequest对象存在的形式不同,还有版本问题,哎,多写点代码来兼容吧。 程序代码: // 方法:open // 创建一个新的http请求,并指定此请求的方法、URL以及验证信息 // 语法:oXMLHttpRequest.open(bstrMethod, bstrUrl, varAsync, bstrUser, bstrPassword); // 参数 // bstrMethod // http方法,例如:POST、GET、PUT及PROPFIND。大小写不敏感。 // bstrUrl // 请求的URL地址,可以为绝对地址也可以为相对地址。 // varAsync[可选] // 布尔型,指定此请求是否为异步方式,默认为true。如果为真,当状态改变时会调用onreadystatechange属性指定的回调函数。 // bstrUser[可选] // 如果服务器需要验证,此处指定用户名,如果未指定,当服务器需要验证时,会弹出验证窗口。 // bstrPassword[可选] // 验证信息中的密码部分,如果用户名为空,则此值将被忽略。 // 备注:调用此方法后,可以调用send方法向服务器发送数据。 xmlhttp.Open("get", "http://localhost/example.htm", false); // var book = xmlhttp.responseXML.selectSingleNode("//book[@id='bk101']"); // alert(book.xml); oXmlHttp.open(sMethod, URL+parameters, true); 这里就是我们常说的异步提交,一般常用的也就是我这里用的3个参数提交方法(get和post两个值),URL地址(URL+parameters,例子里的完整地址就是tarObj + "/" + tarObj + objId + ".htm?d=" + Math.random();),第三个(true,false)指定此请求是否为异步方式,默认为true。如果为真,当状态改变时会调用onreadystatechange属性指定的回调函数。 程序代码: oXmlHttp.onreadystatechange = function () { // 属性:readyState // 返回XMLHTTP请求的当前状态 // 语法:lValue = oXMLHttpRequest.readyState; // 备注:变量,此属性只读,状态用长度为4的整型表示.定义如下: // 0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法) // 1 (初始化) 对象已建立,尚未调用send方法 // 2 (发送数据) send方法已调用,但是当前的状态及http头未知 // 3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误, // 4 (完成) 数据接收完毕,此时可以通过通过responseBody和responseText获取完整的回应数据 if (oXmlHttp.readyState == 4) { // 属性:status // 返回当前请求的http状态码 // 语法:lValue = oXMLHttpRequest.status; // 返回值:长整形标准http状态码,定义如下: // Number:Description // 100:Continue // 101:Switching protocols // 200:OK // 201:Created // 202:Accepted // 203:Non-Authoritative Information // 204:No Content // 205:Reset Content // 206:Partial Content // 300:Multiple Choices // 301:Moved Permanently // 302:Found // 303:See Other // 304:Not Modified // 305:Use Proxy // 307:Temporary Redirect // 400:Bad Request // 401:Unauthorized // 402:Payment Required // 403:Forbidden // 404:Not Found // 405:Method Not Allowed // 406:Not Acceptable // 407:Proxy Authentication Required // 408:Request Timeout // 409:Conflict // 410:Gone // 411:Length Required // 412:Precondition Failed // 413:Request Entity Too Large // 414:Request-URI Too Long // 415:Unsupported Media Type // 416:Requested Range Not Suitable // 417:Expectation Failed // 500:Internal Server Error // 501:Not Implemented // 502:Bad Gateway // 503:Service Unavailable // 504:Gateway Timeout // 505:HTTP Version Not Supported // 备注:长整形,此属性只读,返回当前请求的http状态码,此属性仅当数据发送并接收完毕后才可获取。 if (oXmlHttp.status == 200) { // 属性:responseBody // 返回某一格式的服务器响应数据 // 语法:strValue = oXMLHttpRequest.responseBody; // 备注:变量,此属性只读,以unsigned array格式表示直接从服务器返回的未经解码的二进制数据。 alert(xmlhttp.responseBody); // 属性:responseStream // 以Ado Stream对象的形式返回响应信息 // 语法:strValue = oXMLHttpRequest.responseStream; // 备注:变量,此属性只读,以Ado Stream对象的形式返回响应信息。 alert(xmlhttp.responseStream); // 属性:responseText // 将响应信息作为字符串返回 // 语法:strValue = oXMLHttpRequest.responseText; // 备注:变量,此属性只读,将响应信息作为字符串返回。XMLHTTP尝试将响应信息解码为Unicode字符串, // XMLHTTP默认将响应数据的编码定为UTF-8,如果服务器返回的数据带BOM(byte-order mark),XMLHTTP可 // 以解码任何UCS-2 (big or little endian)或者UCS-4 数据。注意,如果服务器返回的是xml文档,此属 // 性并不处理xml文档中的编码声明。你需要使用responseXML来处理。 alert(xmlhttp.responseText); // 属性:responseXML // 将响应信息格式化为Xml Document对象并返回 // 语法:var objDispatch = oXMLHttpRequest.responseXML; // 备注:变量,此属性只读,将响应信息格式化为Xml Document对象并返回。如果响应数据不是有效的XML文档, // 此属性本身不返回XMLDOMParseError,可以通过处理过的DOMDocument对象获取错误信息。 $(tarObj).innerHTML = oXmlHttp.responseText; } } } 本来想偷个懒,让大家看我上边说的那篇文章,想想也就是Ctrl+C&Ctrl+V,都贴出来吧!呵呵!!! 不过还没有完,最后要说的就是innerHTML这个特性,这里我们还要感谢微软啊,innerHTML就是它的专利,我们就是用它来改变指定DOM内的HTML字符串的,而不用刷新页面。详细的信息大家还是google一下吧,我也要休息下啊!!喝口茶先!!^-^! 以上讲了这么多,我们最后来看看,我们这个ajax标签导航都用到了那些技术吧: 1.xhtml 2.CSS 3.Javascript 4.DOM 5.XMLHttpRequest对象 6.innerHTML 还有XML,我们这个例子没有涉及到。东西虽小,包含的(web前端开发)知识可是都用到了啊,我把我会的点东西都端出来了(要失业了),呵呵! 当然我很喜欢跟大家多交流,以后有时间,我们在来谈谈CSS的HACKS技巧,Javascript DOM编程等等的,今天就收工了,谢谢捧场先!!! |
演示地址:[url=http://www.]http://www.[/url]
效果大家看到了,核心功能有:
1.将当前选中标签以特殊的样式显示
2.将异步加载的页面信息显示到指定的DOM节点中
我们来看看处理脚本的代码吧:
ajaxtab.js
程序代码:
<!--
// 判断是否支持ActiveX
var useActiveX=function(){return (typeof ActiveXObject != "undefined");}
// 判断是否支持DOM
var useDom=function(){return document.implementation && document.implementation.createDocument;}
// 判断是否支持XMLHttpRequest对象
var useXmlHttp=function(){return (typeof XMLHttpRequest != "undefined");}
// XMLHttpRequest对象版本
var ARR_XMLHTTP_VERS = ["MSXML2.XmlHttp.6.0","MSXML2.XmlHttp.3.0"];
// DOM对象版本
var ARR_DOM_VERS = ["MSXML2.DOMDocument.6.0","MSXML2.DOMDocument.3.0"];
/* ===========================================================
* 函数名称:$(i)
* 参数说明:i - 目标节点名称
* 函数功能:获取指定的目标DOM节点
* 返 回 值:返回要搜索的目标DOM节点
* 使用方法:$("frmSearch")
============================================================ */
function $(i){
if(!document.getElementById)return false;
if(typeof i==="string"){
if(document.getElementById && document.getElementById(i)) {
// W3C DOM
return document.getElementById(i);
}
else if (document.all && document.all(i)) {
// MSIE 4 DOM
return document.all(i);
}
else if (document.layers && document.layers[i]) {
// NN 4 DOM.. note: this won't find nested layers
return document.layers[i];
}
else {
return false;
}
}
else{return i;}
}
/* ===========================================================
* 函数名称:createXMLHTTPRequest()
* 参数说明:无参数
* 函数功能:创建XMLHttpRequest对象
* 返 回 值:XMLHTTPRequest对象
* 使用方法:var oXmlHttp = createXMLHTTPRequest();
============================================================ */
function createXMLHTTPRequest(){
// 非IE浏览器(Firefox,Opera),XMLHttpRequest对象是浏览器内置的一个对象
if (useXmlHttp){
return new XMLHttpRequest();
}
else if (useActiveX) { //在IE(IE< 7.0 = use ActiveX)浏览器中,XMLHttpRequest对象是以ActiveX控件的形式存在的
if (!XMLHTTP_VER) {
for (var i=0; i < ARR_XMLHTTP_VERS.length; i++){
try {
new ActiveXObject(ARR_XMLHTTP_VERS[i]);
XMLHTTP_VER = ARR_XMLHTTP_VERS[i]; // 获取本地IE浏览器相应的XMLHttpRequest对象版本
break;
} catch (oError) {}
}
}
if (XMLHTTP_VER) {
return new ActiveXObject(XMLHTTP_VER);
}
else {
throw new Error("无法创建XMLHttpRequest对象!");
}
}
else {
throw new Error("您的浏览器不支持XMLHttpRequest对象!");
}
}
/* ===========================================================
* 函数名称:ajaxUpdater(tarObj,sMethod,URL,parameters)
* 参数说明:tarObj - 异步获取信息希望显示的目标节点ID
* sMethod - 数据提交方法,两个可选值get,post
* URL - 提交的目标URL地址
* parameters - URL后面接(传递)的参数
* 函数功能:将异步传递的目标URL地址返回的信息,无刷新的写到目标
* 节点(tarObj)中
* 返 回 值:new Error() - 运行错误时返回一个报错信息
* 使用方法:var myAjax = ajaxUpdater(msgBox,"get",URL,para);
============================================================ */
function ajaxUpdater(tarObj,sMethod,URL,parameters){
var oXmlHttp = createXMLHTTPRequest();
oXmlHttp.open(sMethod, URL+parameters, true);
oXmlHttp.onreadystatechange = function () {
if (oXmlHttp.readyState == 4) {
if (oXmlHttp.status == 200) {
if($(tarObj)){
$(tarObj).innerHTML = oXmlHttp.responseText;
}
else{
return false;
}
}
else {
throw new Error("有一个错误产生!");
}
}
}
oXmlHttp.send(null);
}
/* ===========================================================
* 函数名称:ajaxRequest(sMethod,URL,parameters,func)
* 参数说明:sMethod - 数据提交方法,两个可选值get,post
* URL - 提交的目标URL地址
* parameters - URL后面接(传递)的参数
* func - 页面成功加载后的处理函数(指针)
* 函数功能:当异步传递的目标URL地址成功加载时,指定相应的处理函数
* 返 回 值:func(oXmlHttp) - 返回处理函数
* new Error() - 运行错误时返回一个报错信息
* 使用方法:var myAjax = ajaxUpdater("get",URL,para,showMsg);
============================================================ */
function ajaxRequest(sMethod,URL,parameters,func){
var oXmlHttp = createXMLHTTPRequest();
oXmlHttp.open(sMethod, URL+parameters, true);
oXmlHttp.onreadystatechange = function() {
if (oXmlHttp.readyState == 4) {
if (oXmlHttp.status == 200) {
return func(oXmlHttp);
}
else {
throw new Error("有一个错误产生!");
}
}
}
oXmlHttp.send(null);
}
/* ===========================================================
* 函数名称:tabsEvent()
* 参数说明:要设置事件的DOM节点ID
* 函数功能:为导航TAB菜单(li)设置onclick处理方法(函数),
* 屏蔽掉a标签默认的处理(打开新链接)事件
* 返 回 值:false - 屏蔽掉a标签默认的处理(打开新链接)事件
* 使用方法:tabsEvent("news","sports");
============================================================ */
function tabsEvent(){
for(var i=0;i<arguments.length;i++){
var tabs = $(arguments[i]);
// DOM节点(tabs)不存在或者浏览器不支持getElementsByTagName()方法
// 函数不执行
if(!tabs || !document.getElementsByTagName) return false;
var theList = tabs.getElementsByTagName("li"); // 搜寻导航标签(ID为tabs)里的所有li标签
var theLink = tabs.getElementsByTagName("a"); // 搜寻导航标签(ID为tabs)里的所有a标签
for(var j=0;j<theList.length;j++){
var theTab = theList[j];
if(theTab.parentNode!=tabs) continue;
var theA = theLink[j];
// 屏蔽掉a标签默认的处理(打开新链接)事件
theA.onclick = function(){
return false;
}
// 为导航TAB菜单(li)设置onclick处理方法(函数)
theTab.onclick = function(){
var theClass = this.className;
if(theClass!="current" && theClass!="first"){
var objId = this.getAttribute("id").split("-")[1]; // 当前选中标签(li)在菜单(ul)中的索引值
var tarObj = this.getAttribute("id").split("-")[0]; // 要显示信息的目标DOM节点ID值
var theURL = tarObj + "/" + tarObj + objId + ".htm"; // 要异步加载的URL地址
ajaxInject($(tarObj),objId,tarObj,theURL);
return false;
}
}
}
}
}
/* ===========================================================
* 函数名称:ajaxInject(ListName,tabId,tarObj,URL)
* 参数说明:ListName - 标签菜单DOM节点ID
* tabId - 选中的标签(在ListName中的)索引值
* tarObj - 要显示返回信息的目标DOM节点ID值
* URL - 要异步处理的URL地址
* 函数功能:设置当前选中标签(li)的样式,
* 将返回信息写到指定DOM节点中。
* 返 回 值:无
* 使用方法:tabsEvent("news","sports");
============================================================ */
function ajaxInject(ListName,tabId,tarObj,URL){
if(!ListName || !document.getElementsByTagName) return false;
var Tabs = ListName;
var theLi = Tabs.getElementsByTagName("li");
for(var i=0;i<theLi.length;i++){
// 设置当前选中标签的样式
if(i==tabId){
if(i==0){
theLi[tabId].className = "first"; // 当选中第一项的样式
}
else{//
theLi[tabId].className = "current"; // 选中其他项的样式
}
var msgBox = tarObj+"Cnt";
var loadstatustext="<div class='loading'><img src='img/loading.gif' alt='正在加载内容, 请稍候...' />正在加载内容, 请稍候...</div>";
$(msgBox).innerHTML = loadstatustext; // 加载信息时的提示信息
var para = "?d=" + Math.random(); // URL后的参数,接Math.random()(一个随机数),目的是处理ajax的缓存问题
var myAjax = ajaxUpdater(msgBox,"get",URL,para);
}
else{// 设置其他标签的样式
theLi[i].className = "";
if(tabId!=0){
theLi[tabId-1].className = "off"; // 当不是第一项时,隐藏选中项的前一项的分隔标签
}
}
}
}
//-->
inde.htm
程序代码:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. xmlns="http://www. http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>AjaxTab导航</title>
<link href="css/ajaxtab.css" rel="stylesheet" type="text/css" />
<script language="javascript" type="text/javascript" src="js/ajaxtab.js"></script>
</head>
<body>
<div class="clearfix cotainer">
<ul class="tabs" id="news">
<li class="first" id="news-0"><a href="news/news0.htm">网站重构</a><span></span></li>
<li id="news-1"><a href="news/news1.htm">CSS布局实录</a><span></span></li>
<li id="news-2"><a href="news/news2.htm">海啸的地盘</a><span></span></li>
<li id="news-3"><a href="news/news3.htm">Ajax高级编程</a><span></span></li>
</ul><br class="clear" />
<div class="clearfix cnt" id="newsCnt">
<img src="img/girl-1.jpg" alt="林志琳" />
<ul>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
</ul>
</div>
</div>
<div class="clearfix cotainer">
<ul class="tabs" id="sports">
<li class="first" id="sports-0"><a href="sports/sports0.htm">网站重构</a><span></span></li>
<li id="sports-1"><a href="sports/sports1.htm">CSS布局实录</a><span></span></li>
<li id="sports-2"><a href="sports/sports2.htm">海啸的地盘</a><span></span></li>
<li id="sports-3"><a href="sports/sports3.htm">Ajax高级编程</a><span></span></li>
</ul><br class="clear" />
<div class="clearfix cnt" id="sportsCnt">
<img src="img/girl-5.jpg" alt="林志琳" />
<ul>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
</ul>
</div>
</div>
<script language="javascript" type="text/javascript">
<!--
tabsEvent("news","sports");
//-->
</script>
</body>
</html>
ajaxtab.css
程序代码:
<!--
*{
margin:0;
padding:0;
}
body{
text-align:center;
background-color:#FFF;
color:#18397C;
font:normal 12px "宋体", Arial, sans-serif;
}
img{border:0;}
ul,li{list-style-type:none;}
a:link,
a:visited{
color:#18397C;
text-decoration:none;
}
a:hover{
color:#F00;
text-decoration:underline;
}
div,span,p,li,ul,h1,h2,h3,h4,h5,h6{text-align:left;}
/*clear both*/
.clearfix:after {
content: ".";
display:block;
height:0;
clear: both;
visibility: hidden;
}
.clearfix {display: inline-block;}
/* Hides from IE-mac \*/
* html .clearfix {height: 1%;}
*+html .clearfix {height: 1%;}
.clearfix {display: block;}
/* End hide from IE-mac */
.clear{
clear: both;
font-size:1px;
width:1px;
height:1px;
visibility: hidden;
}
.cotainer{
margin:0 auto;
margin-top:10px;
width:506px;
height:auto;
border:solid #B0BEC7;
border-width:0 1px 1px 1px;
}
.tabs{
float:left;
width:506px;
height:22px;
background-image:url(../img/tab_bg.gif);
}
.tabs li{
float:left;
display:inline;
text-align:center;
width:120px;
height:12px;
padding:4px 0 6px 0;
overflow:hidden;
letter-spacing:1px;
position:relative;
}
.tabs li.first{
background-image:url(../img/tab_active1.gif);
}
.tabs li.current{
background-image:url(../img/tab_active2.gif);
}
.tabs li.current,
.tabs li.first{
font-weight:bold;
}
.tabs li.current a,
.tabs li.first a{
color:#D45417;
}
.tabs li span{
position:absolute;
right:0;
top:3px;
width:2px;
height:16px;
overflow:hidden;
font-size:1px;
background-image:url(../img/tab_sline.gif);
}
.tabs li.first span,
.tabs li.current span,
.tabs li.off span{
display:none;
}
.cnt{
margin:0 auto;
width:496px;
padding:5px;
height:auto;
}
.cnt img{
float:left;
width:154px;
height:115px;
border:1px solid #B0BEC7;
margin-right:5px;
display:inline;
}
.cnt ul{
float:right;
width:335px;
height:117px;
}
.cnt ul li{
float:left;
width:335px;
height:12px;
overflow:hidden;
color:#999;
padding:5px 0 2px 0;
}
.loading{
margin:0 auto;
width:506px;
height:16px;
padding:51px 0 50px 0;
overflow:hidden;
text-align:center;
}
.loading img{
width:16px;
height:16px;
border:0;
float:none;
vertical-align:middle;
}
-->
CSS技巧篇(position属性的运用技巧)
下面开始我们的分析了,先来看看这段XHTML代码:
程序代码:
<ul class="tabs" id="news">
<li class="first" id="news-0"><a href="news/news0.htm">网站重构</a><span></span></li>
<li id="news-1"><a href="news/news1.htm">CSS布局实录</a><span></span></li>
<li id="news-2"><a href="news/news2.htm">海啸的地盘</a><span></span></li>
<li id="news-3"><a href="news/news3.htm">Ajax高级编程</a><span></span></li>
</ul>
<div class="clearfix cnt" id="newsCnt">
<img src="img/girl-1.jpg" alt="林志琳" />
<ul>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
<li><a href="#">PRG全棉短袖衬衣最后的抢购机抢购机</a> 2006-08-15</li>
</ul>
</div>
id="news" - news就是我们的导航标签的ID;
id="newsCnt" - newsCnt就是我们要写入信息的目标DOM节点;
class="first" - first当前(第一个)标签的样式;
id="news-0" - news-0 通过”-“分开,我们就分别可以得到news(导航标签ID),0(标签[li]在导航标签中的索引值)
<a href="news/news0.htm">网站重构</a> - 超链接
<span></span> - 标签间的分割线
我罗列的这些东西,相信大家开始看出了些头绪了,呵呵,不过别急!在我们看处理的脚本之前,先让我们来看看导航标签的样式,主要是看看我们对分割线的处理(一点CSS处理的技巧)。
程序代码:
/* 导航标签的样式 */
.tabs li{
float:left;
display:inline;
text-align:center;
width:120px;
height:12px;
padding:4px 0 6px 0;
overflow:hidden;
letter-spacing:1px;
position:relative;
}
/* 标签分割线的样式 */
.tabs li span{
position:absolute;
right:0;
top:3px;
width:2px;
height:16px;
overflow:hidden;
font-size:1px;
background-image:url(../img/tab_sline.gif);
}
技巧就是.tab li中的”position:relative;“和.tabs li span中”position:absolute;“结合使用的技巧(呵呵,其实我也是看了YAHOO的标签后才这么用的)。现在我们就来了解下position属性吧(CSS讲座开始,不过是好东西哦,呵呵!):
position:绝对定位,指本体对上级的定位(本人理解的说法),有3个可选值static(静态定位-默认值)、relative(绝对相对定位)、absolute(绝对定位)。
relative:他是参照父级的原始点为原始点,无父级则以BODY的原始点为原始点,配合top、right、bottom、left进行定位,当父级内有padding等CSS属性时,当前级的原始点则参照父级内容区的原始点进行定位。如下图一:
" border="0" />
absolute:他的意思是绝对定位,他是参照浏览器的左上角,配合TOP、RIGHT、BOTTOM、LEFT(下面简称TRBL)进行定位,在没有设定TRBL,默认依据父级的做标原始点为原始点。如果设定TRBL并且父级没有设定position属性,那么当前的absolute则以浏览器左上角为原始点进行定位,位置将由TRBL决定。如下图二:
" border="0" />
不知道你看出些其他的什么特性出来了没有?我们仔细看下图二,你发现没有,在用absolute定位的时候,它可以覆盖在与其相邻的节点上(不是因为它设置了z-index属性),而是它的一个特性--不占布局或者说不影响邻居节点的布局。而relative则不一样,它会影响邻居节点的布局。我们通过图一还看不出来,来看图三:
" border="0" />
大家注意到图片中的灰色部分没有?这个就是我要说的,这块灰色的部分的大小就是#relative的大小,这个说明了什么?表明它会影响邻居节点的布局,而且邻居节点接下来的位置就是#relative使用一般margin定位的末端。讲详细点,就是说虽然#relative显示的在屏幕的位置是红色块的地方,但是实际仍然要占据它起始位置所在的布局(它的宽和高)的大小。这里#relative的起点是body,那么它站的布局就是从body起点开始width:250px;height:250px;(加padding:5px)的布局(大小),也就是我们看到图中灰色部分。呵呵,好绕是吗?仔细看看,多用下就明白了。
好了,现在就我们ajax标签导航中使用的是relative+absolute的结合,当一个absolute的节点包含在一个relative的节点中时,它的”原始点“就是relative节点了,而不是“参照浏览器的左上角-body”了,而它又不影响其邻居节点的布局,所以它就不会影响<li></li>中间文字(文本节点)的布局了(这里li的空间够大)。这样以来,就得到了我们标签中,每个标签后有一个分隔线的样式了。如图四:
" border="0" />
OK,我们对position属性和它的值的使用搞清楚了。接下来就来看看是怎么来更改当前选中标签(li)的样式吧:
程序代码:
.tabs li{
float:left;
display:inline;
text-align:center;
width:120px;
height:12px;
padding:4px 0 6px 0;
overflow:hidden;
letter-spacing:1px;
position:relative;
}
/* 第一项被选中的样式 */
.tabs li.first{
background-image:url(../img/tab_active1.gif);
}
/* 其他项被选中的样式 */
.tabs li.current{
background-image:url(../img/tab_active2.gif);
}
/* 被选中项的字体样式 */
.tabs li.current,
.tabs li.first{
font-weight:bold;
}
/* 被选中项的链接颜色样式 */
.tabs li.current a,
.tabs li.first a{
color:#D45417;
}
.tabs li span{
position:absolute;
right:0;
top:3px;
width:2px;
height:16px;
overflow:hidden;
font-size:1px;
background-image:url(../img/tab_sline.gif);
}
/* 选中项和选中项前一项的样式 */
.tabs li.first span,
.tabs li.current span,
.tabs li.off span{/* 选中项前一项 */
display:none;
}
这里要简单说的就是样式表CSS继承(层叠)的顺序,一定要是先写标签(li)标签默认(背景)样式再写选中时的(背景)样式,然后是默认分隔线(span)-> 选中时 -> 失去焦点时这样一个顺序。至于CSS的继承顺序的具体只是,大家可以google一下。
Javascript技巧篇(arguments对象的运用技巧)
好了,我们现在已经把CSS样式写好了,现在就开始用脚本来控制了。通过刚才讲解标签样式的时候,其实我们也基本把脚本控制的逻辑流程分析了下:
1. 选中当前标签的背景要区别显示;
2. 选中标签和其前一个标签的分隔线要隐藏;
不过在改变标签样式这个步骤开始之前我们要给我们的标签菜单(ul)来设置onclick事件(功能函数),从而触发改变当前选中项的样式的事件。到我们的主题了,呵呵!快来看看代码吧:
程序代码:
/* ===========================================================
* 函数名称:tabsEvent()
* 参数说明:要设置事件的DOM节点ID
* 函数功能:为导航TAB菜单(li)设置onclick处理方法(函数),
* 屏蔽掉a标签默认的处理(打开新链接)事件
* 返 回 值:false - 屏蔽掉a标签默认的处理(打开新链接)事件
* 使用方法:tabsEvent("news","sports");
============================================================ */
function tabsEvent(){
for(var i=0;i<arguments.length;i++){
var tabs = $(arguments[i]);
// DOM节点(tabs)不存在或者浏览器不支持getElementsByTagName()方法
// 函数不执行
if(!tabs || !document.getElementsByTagName) return false;
var theList = tabs.getElementsByTagName("li"); // 搜寻导航标签(ID为tabs)里的所有li标签
var theLink = tabs.getElementsByTagName("a"); // 搜寻导航标签(ID为tabs)里的所有a标签
for(var j=0;j<theList.length;j++){
var theTab = theList[j];
if(theTab.parentNode!=tabs) continue;
var theA = theLink[j];
// 屏蔽掉a标签默认的处理(打开新链接)事件
theA.onclick = function(){
return false;
}
// 为导航TAB菜单(li)设置onclick处理方法(函数)
theTab.onclick = function(){
var theClass = this.className;
if(theClass!="current" && theClass!="first"){
var objId = this.getAttribute("id").split("-")[1]; // 当前选中标签(li)在菜单(ul)中的索引值
var tarObj = this.getAttribute("id").split("-")[0]; // 要显示信息的目标DOM节点ID值
var theURL = tarObj + "/" + tarObj + objId + ".htm"; // 要异步加载的URL地址
ajaxInject($(tarObj),objId,tarObj,theURL);
return false;
}
}
}
}
}
上面这段脚本,我们使用了$(i)函数获取DOM节点,方法就是$("DOMId"),这里就不多说了。这里要花些时间讲的是arguments对象,恩,...,恩,开始讲arguments对象了,注意听讲(不是在卖弄哦,这个我们经常要用到的,也很重要的一个知识点):
Arguments是进行函数调用时,除了指定的参数外,还另外创建的一个隐藏对象。Arguments是一个类似数组但不是数组的对象,说它类似数组是因为其具有数组一样的访问性质及方式,可以由arguments[n]来访问对应的单个参数的值,并拥有数组长度属性length。还有就是arguments对象存储的是实际传递给函数的参数,而不局限于函数声明所定义的参数列表,而且不能显式创建 arguments 对象。arguments 对象只有函数开始时才可用。
”隐藏对象“,怎么个隐藏法呢?看看我们函数的写法吧:
程序代码:
function tabsEvent(){
...
}
而我在调用这个函数是确是这么写的:
程序代码:
<script language="javascript" type="text/javascript">
<!--
tabsEvent("news","sports");
//-->
</script>
“tabsEvent("news","sports");”, 我使用了参数,而我定义tabsEvent时,却没有使用形参(形参个数为零),就是这么个隐藏法。
它像数组,而又不是数组,怎么解释了?还是看个说明arguments不是数组(Array类)的代码:
程序代码:
Array.prototype.selfvalue = 1;
alert(new Array().selfvalue);
function testAguments(){
alert(arguments.selfvalue);
}
运行代码你会发现第一个alert显示1,这表示数组对象拥有selfvalue属性,值为1。而当你调用函数testAguments时,你会发现显示的是“undefined”,说明了selfvalue不是arguments的属性,即arguments并不是一个数组对象。
呵呵,又说了这么多,要将就讲彻底些:caller、callee、apply、call都讲讲吧,^-^!
caller - 返回一个对函数的引用,该函数调用了当前函数。
对于函数来说,caller 属性只有在函数执行时才有定义。如果函数是由顶层调用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 属性,那么结果和 functionName.toString 一样,也就是说,显示的是函数的反编译文本。 下面的例子说明了 caller 属性的用法:
程序代码:
function callerDemo() {
if (callerDemo.caller) {
var a = callerDemo.caller.toString();
alert(a);
}
else {
alert("this is a top function");
}
}
function handleCaller() {
callerDemo();
}
handleCaller();
callerDemo();
我们通过handleCaller();调用执行callerDemo();时callerDemo.caller才定义,可以看到一个警告框,显示的反编译的handleCaller()的文本。而直接使用callerDemo();时,我们callerDemo函数的caller是没有定义的,所以你会看到”this is a top function“提示字符。
callee - 返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文。 用法[function.]arguments.callee,可选项 function 参数是当前正在执行的 Function 对象的名称。
callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用,这有利于匿名函数的递归或者保证函数的封装性,例如下边示例的递归计算1到n的自然数之和。而该属性仅当相关函数正在执行时才可用。还有需要注意的是callee拥有length属性,这个属性有时候用于验证还是比较好的。arguments.length是实参长度,arguments.callee.length是形参长度,由此可以判断调用时形参长度是否和实参长度一致。
程序代码:
//callee可以打印其本身
function calleeDemo() {
alert(arguments.callee);
}
//用于验证参数
function calleeLengthDemo(arg1, arg2) {
if (arguments.length==arguments.callee.length) {
alert("验证形参和实参长度一致!");
return;
}
else {
alert("实参长度:" +arguments.length);
alert("形参长度: " +arguments.callee.length);
}
}
//递归计算
var sum = function(n){
if (n <= 0) {
return 1;
}
else{
return n + arguments.callee(n - 1);
}
}
调用alert(sum(9));时,其中函数内部包含了对sum自身的引用,函数名仅仅是一个变量名,在函数内部调用sum即相当于调用一个全局变量,不能很好的体现出是调用自身,这时使用callee会是一个比较好的方法。
apply 和 call 它们的作用都是将函数绑定到另外一个对象上去运行,两者仅在定义参数方式时有所区别:
程序代码:
apply(thisArg,argArray);
call(thisArg[,arg1,arg2…] ]);
即所有函数内部的this指针都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的
apply的说明:如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。如果没有提供 argArray 和 thisArg 任何一个参数,那么 Global 对象将被用作 thisArg,并且无法被传递任何参数。
call的说明:call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisArg 指定的新对象。 如果没有提供 thisArg 参数,那么 Global 对象被用作 thisArg。
应用call和apply还有一个技巧在里面,就是用call和apply应用另一个函数(类)以后,当前的函数(类)就具备了另一个函数(类)的方法或者是属性,这也可以称之为“继承”。看下面示例:
程序代码:
// 继承的演示
function base() {
this.member = "dnnsun_Member";
this.method = function() {
alert(this.member);
}
}
function extend() {
base.call(this);
alert(member);
alert(this.method);
}
上面的例子可以看出,通过call之后,extend可以继承到base的方法和属性。
呵呵,你可能发现了,在javascript框架prototype里就使用apply来创建一个定义类的模式,其实现代码如下:
程序代码:
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
从代码看,该对象仅包含一个方法:Create,其返回一个函数,即类。但这也同时是类的构造函数,其中调用initialize,而这个方法是在类创建时定义的初始化函数。通过如此途径,就可以实现prototype中的类创建模式,示例代码:
程序代码:
var vehicle=Class.create();
vehicle.prototype={
initialize:function(type){
this.type=type;
}
showSelf:function(){
alert("this vehicle is "+ this.type);
}
}
var moto=new vehicle("Moto");
moto.showSelf();
呵呵,越扯越多了,现在清楚了arguments对象的用法了吧!哈哈,还是有些收获的吧?^-^!!! 不过该回到我们的主题了,怎么实现点击标签(li)触发更改样式的事件。还是接着看我们的ajaxtab.js的代码吧:
程序代码:
for(var i=0;i<arguments.length;i++){
var tabs = $(arguments[i]);
}
看看上面讲的arguments的用法,呵呵,这里我们就获取了全部的标签导航菜单了。arguments.length = ?等于2,arguments[i]是什么,就是我们传的参数本身(tabsEvent("news","sports");),那么$(arguments[i])就是我们的标签菜单,具体点就是$("news")和$("sports")了。
DOM技巧篇(DOM基础知识)
讲到这里,我们就要了解一下DOM的一些基础知识了。
DOM(Document Object Model 文档对象模型)是HTML和XML的应用程序接口(API)。DOM将把整个页面规划成有节点层级构成的文档。HTML或XML页面的每一个部分都是一个节点的衍生物。
光说可能还不怎么好理解,那么来看看我们ajax标签导航的DOM结构吧,如图五(截取的FIXFOX中的DOM图象):
" border="0" />
DOM通过创建树来表示文档,从而使开发着对文档的内容和结构具有空前的控制力。用DOM API可以轻松地删除,添加和替换节点。
简单的了解了什么是DOM后(要想了解更多的Javascript DOM 编程知识,推荐大家看看《Javascript DOM 编程艺术》和《Javascript高级编程》这两本书,还有到作者的网站去看看,也可以直接到W3C去查询相关信息。),来看看我们这个程序里需要用到的DOM知识吧:document.getElementsByTagName()还有之前提到的$(i)函数,它们都是做什么用的呢?
document.getElementById("DOMId"):它返回的是以ID为表示的节点,而大家都知道id在页面中是唯一的,所以getElementById是在页面中搜索DOM节点最直接的方法,很常用。不过它只能查寻单个的DOM节点,我们要查询一组怎么办呢? 我们可以使用getElementsByTagName和getElementsByName。
从方法名字中的“Elements”我们也可以知道,这两个方法返回的是一组元素(数组)
getElementsByTagName:(核心[XML]DOM)用来返回一个包含所有tagName(标签名)特性等于某个指定值的元素的NodeList。
getElementsByName:(HTML DOM)用来获取所有name特性等于指定值的元素。但是这个方法在IE6和opera7.5中支持不是很好,会有错误产生,所以(个人)建议一般不要用。
OK,在对使用DOM来查寻节点的知识有了了解后,我们再来看这段代码:
程序代码:
/* ===========================================================
* 函数名称:$(i)
* 参数说明:i - 目标节点名称
* 函数功能:获取指定的目标DOM节点
* 返 回 值:返回要搜索的目标DOM节点
* 使用方法:$("frmSearch")
============================================================ */
function $(i){
if(!document.getElementById)return false;
if(typeof i==="string"){
if(document.getElementById && document.getElementById(i)) {
// W3C DOM
return document.getElementById(i);
}
else if (document.all && document.all(i)) {
// MSIE 4 DOM
return document.all(i);
}
else if (document.layers && document.layers[i]) {
// NN 4 DOM.. note: this won't find nested layers
return document.layers[i];
}
else {
return false;
}
}
else{return i;}
}
这个函数主要是来查找指定的DOM节点的,主要是通过document.getElementById()方法,但是我们又看到了document.all()和document.layers[]方法,这个就是浏览器大战时期(各个浏览器对DOM标准支持不程度不同),各大浏览器提供商制定的各自的DOM支持规范而造成的,我们的CSS HACKS其实也是由于这个原因才会出现的。扯远了,document.all()是IE浏览器(IE5以上版本)中特有的查询节点的方法,而document.layers[i]则是其他浏览器(主要是NetScape的)的浏览器特有的。我们通过$(i)函数来统一调用,从而解决了浏览器兼容的问题。
而下面这里的代码:
// DOM节点(tabs)不存在或者浏览器不支持getElementsByTagName()函数不执行
if(!tabs || !document.getElementsByTagName) return false;
这里if(!tabs || !document.getElementsByTagName) return false;这么写是很有必要的,这里是一种预留退路的思想(在《Javascript DOM 编程艺术》一书一直灌输的思想),这么写在不支持getElementsByTagName()方法时我们的函数就不会执行,在不tabs($("news")和$("sports")),不存在的时候(可能是我们把参数名写错了),函数也不执行了,从而避免了弹出或显示脚本错误的信息。下面我们还将看到这一思想的体现,不过我们还是先来看看紧接的代码:
var theList = tabs.getElementsByTagName("li"); // 搜寻导航标签(ID为tabs)里的所有li标签
var theLink = tabs.getElementsByTagName("a"); // 搜寻导航标签(ID为tabs)里的所有a标签
为什么要找出所有的li和a标签呢?呵呵,这个是由于我这里采取的设置样式的结构决定的(其实我也老是觉得不怎么好,不过这个思维个人比较好理解--头疼医头,脚疼医脚的方法)。看看我们上边的CSS样式,大家看到了,我们是用改变标签菜单(li)的样式来实现特别显示当前标签的。那么我这里就自然要获取所有的li标签,然后给他添加onclick来调用ajaxInject(ListName,tabId,tarObj,URL),从而改变标签的样式。看看我来实现这个功能的代码吧:
程序代码:
for(var j=0;j<theList.length;j++){
var theTab = theList[j];
if(theTab.parentNode!=tabs) continue;
var theA = theLink[j];
// 屏蔽掉a标签默认的处理(打开新链接)事件
theA.onclick = function(){
return false;
}
// 为导航TAB菜单(li)设置onclick处理方法(函数)
theTab.onclick = function(){
var theClass = this.className;
if(theClass!="current" && theClass!="first"){
var objId = this.getAttribute("id").split("-")[1]; // 当前选中标签(li)在菜单(ul)中的索引值
var tarObj = this.getAttribute("id").split("-")[0]; // 要显示信息的目标DOM节点ID值
var theURL = tarObj + "/" + tarObj + objId + ".htm"; // 要异步加载的URL地址
ajaxInject($(tarObj),objId,tarObj,theURL);
return false;
}
}
}
我们通过使用一个for循环来遍历所有的li和a标签(由于它们个数相同,所以索引的值相同),然后分别为它们设置onclick事件。先看我们给a标签添加的事件的代码:
程序代码:
var theA = theLink[j];
// 屏蔽掉a标签默认的处理(打开新链接)事件
theA.onclick = function(){
return false;
}
一个简单的return false,可别小看它哦,有几个作用哦,首先a标签是嵌套在li标签里的,我们点li时就一定会出发a标签的默认行为,打开链接的页面。而我们ajax标签导航就是希望不刷(打开)新页面,在指定的DOM节点显示信息。当然就不能让a标签的默认行为启动了,而简单的一个return false;就解决了这个问题。哦,这里还有个问题就是DOM事件的冒泡的顺序,详细的介绍大家可以在《Javascript高级编程》一书中查到。
那有些朋友会问,为什么要在里面加个a标签呢?反正你是改变的是li的样式,点了li,改变li的样式,然后刷新指定DOM节点的信息不就完成了ajax标签导航的功能(效果)了吗?
是啊,不过我在这里要提的就是刚才提到的一个预留退路的思想,如果想上面说的那样做了,当然是没有什么问题,但前提是用户的浏览器支持javascript脚本,或者说用户打开了执行脚本的权限。一旦用户的浏览器不支持javascript或者出于安全原因关闭了脚本执行功能。这个时候,当用户点li时是没有任何反映的。而我这里的处理就考虑到了当javascript执行不了的情况,这时候,用户点链接就可以打开我们原本要用ajax加载的内容了。
其实这里还有各个比较简单的方法来达成我提到的相同的效果,就是对li使用onmouseover事件,想想为什么?因为只要鼠标划过时,就触发了ajaxInject($(tarObj),objId,tarObj,theURL);改变了标签的样式,刷新了内容。当点击链接时,就可以弹出页面了。现在网易和雅虎中国就是这么处理的。其实我这么做主要是处于个人习惯,比较喜欢用onclick,还有就是这里有个分隔线的效果,看上去比网易的只用一个背景图片酷,当然我的效果是学的雅虎(不是雅虎中国)的。不过雅虎的标签样式的处理方式要比我现在的更巧妙,下次有时间再跟大家分析下雅虎的标签导航效果。
又扯远了,OK,接下来我们就是要改变样式和ajax刷新内容了。不过在这个之前,看看我做了什么准备。
程序代码:
<ul class="tabs" id="news">
<li class="first" id="news-0"><a href="news/news0.htm">网站重构</a><span></span></li>
<li id="news-1"><a href="news/news1.htm">CSS布局实录</a><span></span></li>
<li id="news-2"><a href="news/news2.htm">海啸的地盘</a><span></span></li>
<li id="news-3"><a href="news/news3.htm">Ajax高级编程</a><span></span></li>
</ul>
var objId = this.getAttribute("id").split("-")[1]; // 当前选中标签(li)在菜单(ul)中的索引值
var tarObj = this.getAttribute("id").split("-")[0]; // 要显示信息的目标DOM节点ID值
var theURL = tarObj + "/" + tarObj + objId + ".htm"; // 要异步加载的URL地址
看看我文章前面部分罗列的东西,现在就在这里有了回应了
id="news" - news就是我们的导航标签的ID;
id="news-0" - news-0 通过”-“分开,我们就分别可以得到news(导航标签ID),0(标签[li]在导航标签中的索引值)
好现在就要改变标签的样式了
程序代码:
/* ===========================================================
* 函数名称:ajaxInject(ListName,tabId,tarObj,URL)
* 参数说明:ListName - 标签菜单DOM节点ID
* tabId - 选中的标签(在ListName中的)索引值
* tarObj - 要显示返回信息的目标DOM节点ID值
* URL - 要异步处理的URL地址
* 函数功能:设置当前选中标签(li)的样式,
* 将返回信息写到指定DOM节点中。
* 返 回 值:无
* 使用方法:ajaxInject($(tarObj),objId,tarObj,theURL);
============================================================ */
function ajaxInject(ListName,tabId,tarObj,URL){
if(!ListName || !document.getElementsByTagName) return false;
var Tabs = ListName;
var theLi = Tabs.getElementsByTagName("li");
for(var i=0;i<theLi.length;i++){
// 设置当前选中标签的样式
if(i==tabId){
if(i==0){
theLi[tabId].className = "first"; // 当选中第一项的样式
}
else{//
theLi[tabId].className = "current"; // 选中其他项的样式
}
var msgBox = tarObj+"Cnt";
var loadstatustext="<div class='loading'><img src='img/loading.gif' alt='正在加载内容, 请稍候...' />正在加载内容, 请稍候...</div>";
$(msgBox).innerHTML = loadstatustext; // 加载信息时的提示信息
var para = "?d=" + Math.random(); // URL后的参数,接Math.random()(一个随机数),目的是处理ajax的缓存问题
var myAjax = ajaxUpdater(msgBox,"get",URL,para);
}
else{// 设置其他标签的样式
theLi[i].className = "";
if(tabId!=0){
theLi[tabId-1].className = "off"; // 当不是第一项时,隐藏选中项的前一项的分隔标签
}
}
}
}
这里又跟前面的
id="newsCnt" - newsCnt就是我们要写入信息的目标DOM节点;
class="first" - first当前(第一个)标签的样式;
对应起来了。
程序代码:
for(var i=0;i<theLi.length;i++){
// 设置当前选中标签的样式
if(i==tabId){
if(i==0){
theLi[tabId].className = "first"; // 当选中第一项的样式
}
else{
theLi[tabId].className = "current"; // 选中其他项的样式
}
}
else{// 设置其他标签的样式
theLi[i].className = "";
if(tabId!=0){
theLi[tabId-1].className = "off"; // 当不是第一项时,隐藏选中项的前一项的分隔标签
}
}
}
上面这段代码就是具体改变样式的,i==tabId比较当前标签的索引值(作用就是确认是否是选中的标签),相等了就给标签设置样式了。i==0表明第一项被选种(由于我的第一项的背景特殊的)给它加上“first”样式,其余项被选中则加上“current”样式。
接这就是处理分隔钱的样式了,跟设置背景大同小意,这里要说的是我们在写CSS的时候要把li(选中和失去焦点)的样式设置好。还是我之前提到的,YAHOO的做得很好,我记得网上也有关于滑动门技术CSS写法的介绍,大家可以看看是怎么来设置样式的,还有这里给大家推荐个小软件《CSS Tab Designer 2》。
恩,现在要刷新指定DOM节点的内容了,用一个简单的var myAjax = ajaxUpdater(msgBox,"get",URL,para);就解决问题了。不过我们看看在把信息写到指定DOM节点前,我做了什么:
程序代码:
var msgBox = tarObj+"Cnt";
var loadstatustext="<div class='loading'><img src='img/loading.gif' alt='正在加载内容, 请稍候...' />正在加载内容, 请稍候...</div>";
$(msgBox).innerHTML = loadstatustext; // 加载信息时的提示信息
这里做了一个提示的处理,因为ajax是异步的加载,在获取很长(信息量很大)的内容时,会有一个延时,如果在这个期间不给任何提示信息的话,我们要刷新的DOM节点会出现白白的一片,这个当然是不美观的。所以在这之前,我们给用户一个提示信息,说明正在加载信息会显得更人性化些。当然,大家知道的网易的处理会更好些,做一个延迟的window.setTimeout效果。