ajax标签导航实例详解教程(4)
作者:海啸 来源:无忧脚本 发布时间:2008-02-01 10:54:00
DOM技巧篇(DOM基础知识)
讲到这里,我们就要了解一下DOM的一些基础知识了。
DOM(Document Object Model 文档对象模型)是HTML和XML的应用程序接口(API)。DOM将把整个页面规划成有节点层级构成的文档。HTML或XML页面的每一个部分都是一个节点的衍生物。
光说可能还不怎么好理解,那么来看看我们ajax标签导航的DOM结构吧,如图五(截取的FIXFOX中的DOM图象):
DOM通过创建树来表示文档,从而使开发着对文档的内容和结构具有空前的控制力。用DOM API可以轻松地删除,添加和替换节点。
简单的了解了什么是DOM后(要想了解更多的Javascript DOM 编程知识,推荐大家看看《Javascript DOM 编程艺术》和《Javascript高级编程》这两本书,还有到作者的网站去看看,也可以直接到W3C去查询相关信息。),来看看我们这个程序里需要用到的DOM知识吧:document.getElementsByTagName()还有之前提到的$(i)函数,它们都是做什么用的呢?
<, P>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效果。


猜你喜欢
- 数据库计算机 databasecomputer 实现数据库的存储、管理和控制的一种专用计算机系统。它能十分快速而有效地完成各种数据库操作,并
- 本文实例总结了php随机取mysql记录方法。分享给大家供大家参考。具体分析如下:在php中要随机取mysql记录我们可以直接使用mysql
- 很多人在学习了基本的Python语言知识后,就转入应用阶段了,后期很少对语言本身的新变化、新内容进行跟踪学习和知识更新,甚至连已经发布了好几
- 基本思想:归并排序是一种典型的分治思想,把一个无序列表一分为二,对每个子序列再一分为二,继续下去,直到无法再进行划分为止。然后,就开始合并的
- ISSET();——适合于检测是否存在这个参数。 定义和作用范围:用于测试一个变量是否具有值(包括0,FALSE,或者一个空字串,但不能是N
- 关系型数据库:关系型数据库的优势:保持数据的一致性(事务处理)由于以标准化为前提,数据更新的开销很小(相同的字段基本上都只有一处)可以进行J
- 问题描述:使用scn号恢复误删数据1.查询系统闪回的scn值以及当前日志的scn值,因为我这个是测试,创建的表是在在后边,所以scn值要大于
- 在使用Keras搭建验证码识别模型时,需要大量的验证码图片。在这里,使用captcha模块生成验证码图片,验证码图片名称为验证码上显示的字符
- 方法一(只有mdf没有日志文件的可以恢复) 证明有效 1.新建同名数据库。 2.把该数据库设置为脱机。 3.删除其日志文件(.LDF),不删
- 如果仅仅是定义表格的边框为1(border="1")和边框颜色值(如borderC
- 我搜集了国内10几个电影网站的数据,里面近几十W条记录,用文本没法存,mongodb学习成本非常低,安装、下载、运行起来不会花你5分钟时间。
- 如下所示:a = int(input("请输入菱形行数:"))m = a #空格d = a #倒三角for i in r
- 在Python探索之SocketServer详解中我们介绍了Python标准库中的SocketServer模块,了解了要实现网络通信服务,就
- Mysql的分页的两个参数select * from user limit 1,21表示从第几条数据开始查(默认索引是0,如果写1,从第二条
- 误区 #30:有关备份的30个误区全是错的在开始有关备份的误区之前,如果你对备份的基础没有了解,请看之前我在TechNet Magazine
- 如下所示:list=[1,2,3,4,5,6,7,8,9,0,11,0,13,14,15,16,17,18,19,20]#把list分为长度
- vue+element表格实现多层数据嵌套今天用element的表格渲染了商城的购物车列表,element的表格之前也用到过,它把所有的东西
- Inotify地址:访问# -*- coding:utf-8 -*-import osimport pyinotifyfrom functi
- 本文讨论的是如果开发一个符合w3c标准的web站点,重点探讨在新的设计与开发模式下,web项目组中的美工/页面制作人员/后台程序员三者之间如
- 我就废话不多说了,大家还是直接看代码吧~b = torch.zeros((3, 2, 6, 6))a = torch.zeros((3, 2