随笔-67  评论-522  文章-0  trackbacks-0
    关于jQuery操作DOM的内容完了吗?不,还没有,还有更多!
    1、尽可能的用#id和属性选择器
    在选择DOM元素时,jQuery的选择器无疑提供了非常多的功能,除了特性选择器外,对文档元素的查找操作,我觉得还是#id[attribute]最为实用,当然这不是否定其它的选择器。我这样说是有原因的。
    在实际开发中,程序员一般是以模块为单位进行功能开发,那么从前台到后台都是一个人在做。而页面的美化工作可能会交给美工(也可能是前台开发人员)来完成,如果需要对DOM的结构进行调整或重新布局,这时,当脚本中使用了CSS选择器或位置选择器,这时,你能保证不会对功能有影响吗?难道还要和开发人员进行沟通,这里不能这样写,那里需要调整。可是一个系统中的页面会只有一两个吗?这样改下来,得要多少时间?这时有人会说了,你设计没做好,设计之初就应该考虑好,样式布局就应该做好。那么就不会出现这样的问题。是的,设计很重要,设计的好坏决定项目成败。但是,我要告诉你,世上没有绝对的事情,我们所做的一切都是以客户为出发点,客户不满意了,要你改,你能不改吗?
    使用ID的好处显而易见,给元素加上ID,通过ID获得该元素对象,然后进行相应操作,不管结构如何变化,代码不用修改。请一定注意,ID不能重复了。
    可是ID只能对单一元素进行操作(这是相对的,后面有讲到对ID也可以批量操作),如果有多个元素怎么办呢?这里就要用到属性选择器了。帮助文档里罗列了各种属性选择器,而且有说明和示例。不过例子太简单了,会让很多人没有感觉,对它没有引起足够的重视,在这里大象用几个实例来说明一下它们的用法。
    a)
$(function(){
    $(
"[name=ctrRadio]").each(function(){
        $(
this).click(
            
function(){
                
// click事件代码
            }
        );
    });
});
<input type="radio" name="ctrRadio" /> // 有很多个单选按钮,组成一个单选按钮组
    页面数据列表一般采取分页显示,每页10条、15条或更多,每一行都添加了一个单选按钮,在初始化时,我们给每个单选按钮绑定一个click事件,所以这里我们使用[attribute=value]形式的属性选择器来实现我们的需求。另外name值如果定义好了,我们也不会轻易再去改动它,调整单选按钮的位置也不会影响到代码。比如现在位于每行的第一列是单选按钮,后来客户要求,要将它放到最后一列去,或是将type改成button,这都不会影响原来实现的代码。除非你要把它改成checkbox,那么,这应该算是需求变更了吧?
    b)
$(function(){
    $(
"[name$='chk']").attr("checked","checked").click(
        
function(){
            
var chkbox = $(this); // this是当前的复选框对象,$(this)是获得该复选框的jQuery对象
            
if(chkbox.attr("checked")){
                alert(
"选择: "+chkbox.val());
            }
else{
                alert(
"取消: "+chkbox.val());
            }
        }
    );
});
<div><input type="checkbox" name="stationchk" value="a" />1</div>
<div><input type="checkbox" name="stationchk" value="b" />2</div>
<div><input type="checkbox" name="intervalchk" value="c" />3</div>
<div><input type="checkbox" name="intervalchk" value="d" />4</div>
<div><input type="checkbox" name="commonchk" value="e" />5</div>
<div><input type="checkbox" name="commonchk" value="f" />6</div>
    文档初始化时,通过属性选择器查找所有name名称以chk结尾的DOM元素,并将它设为选中状态,同时给它绑定click事件。这里可以在[name$='chk']前面加上input,缩小搜索范围。当然,你得确保以chk结尾的都是你想操作的checkbox,避免出现让自己困惑的BUG。因此在做之前,充分的思考很有必要,这会大大提高你的开发效率和减少出现错误的机率。虽然表面看起来多花了一点时间,但是你会觉得这是很值得的。
    [attribute^=value][attribute$=value]是相对的一组选择器,前者是匹配指定的属性以某些值开始的元素,后者刚好相反,匹配给定的属性是以某些值结尾的元素,请一定记住attribute是属性,比如上面的typenamevalue等等。在项目中大量的通过idname属性来批量的操作DOM元素。
    我说下怎么通过ID获得多个集合,其实很简单,在设置ID值的时候,给它定义一个字符串再加上其它的唯一标识就能够实现这一功能。

<c:forEach var="info" items="${infos}">
    
<input name="modinfo" id="modInfo_${info.parent_id}_${info.f_id}" type="checkbox" value="${info.f_id},${info.parent_id}" />
</c:forEach>
    在数据库中f_id是主键标识,因此它具有唯一性,parent_id是父ID,它们和modInfo_组合起来就可以成为id属性的唯一标识。forEach循环会产生多个checkbox,所以我们就使用$("[id^='modInfo_']")表达式来取得结果集。有人会问有name不就行了吗?为什么还要设置id?而且还要将两种ID值与字符串拼接成复选框的id属性值。这是由于功能需要,不光要用到name,还要用到id,而且checkbox上还绑定了click,事件处理中还会用到value中的值。有时我们的业务需求确实很复杂,这时我们就可以采取这种方式来区分彼此之间存在一些联系而又独立的DOM集合。
    在实际项目当中如何组合,还是得具体问题具体分析。另外,我们也不能忘掉那些特性选择器,它们同样很有用。

    c)
$(function(){
    $(
"[name^='station']:checkbox").attr("checked","checked").click(
        
function(){
            
if($(this).attr("checked")){
                alert(
"选择: "+$(this).val());
            }
else{
                alert(
"取消: "+$(this).val());
            }
        }
    );
});
<div><input type="checkbox" name="stationchk" value="a" />1</div>
<div><input type="checkbox" name="stationchk" value="b" />2</div>
<div><input type="checkbox" name="intervalchk" value="c" />3</div>
<div><input type="checkbox" name="intervalchk" value="d" />4</div>
<div><input type="checkbox" name="commonchk" value="e" />5</div>
<div><input type="checkbox" name="commonchk" value="f" />6</div>
<div><input type="radio" name="stationrad" value="g" />7</div>
<div><input type="radio" name="stationrad" value="h" />8</div>
    这个例子在b)的基础上作了一些修改,它表示在文档初始化时,通过属性选择器查找所有name名称以station开头并且typecheckboxDOM元素,同时绑定click事件。如果将:checkbox去掉会不会有变化呢?答案是肯定的,单选按钮组也被绑定了事件。再看几个例子
$("[name=ctrRadio]:checked").attr("checked",""); //取消已选中的单选框
$("[id^='modInfo_']").is(":hidden"); //如果表达式中的集合只要有一个不可见,就返回true
$("select[name='contract_kind'] option:eq(0)").attr("selected","selected"); //选中第一条记录
    2、jQuery属性——很好,很强大
    attraddClassremoveClasscsshtmltextvalheightwidth这些命令在实际应用中的使用频率非常高,应该把它们全部掌握。这些属性都有赋值与取值的方法,为我们操作DOM提供了很方便的支持。举几个例子说明一下
$(":button").addClass("button1"); //给所有的按钮添加样式
$("#ctr_info").attr("src","${ctx}/BaseAction.do?method=list"); //给id为ctr_info的iframe的src属性设置地址
$("#stationchk").attr("checked"); //获得复选框是否选中,选中为true,否则为false
$("#sum").css("ime-mode","disabled"); //屏蔽输入法
$("[name='stationchk']").parent().html("哈哈"); //返回包含匹配表达式的唯一父元素的元素集合
$("#ctr_info").load(function(){
    var ifr_height = $(this).contents().find("#ctr_other").height(); //通过ID重新计算iframe的高度
    ifr_height = ifr_height < 400 ? 350 : ifr_height;
    $(
this).height(ifr_height);
});
    这些属性的运用技巧需要多做才能加深理解,对于以前使用原生JavaScript来编写脚本的程序员而言,无疑是一件很幸福的事,极大的简化了代码,减少了很多的工作量。
    3、丰富的文档处理功能
    从帮助文档中,我们可以看到,jQuery提供了一套很完备的文档处理函数。基本上需要有的都包含了。大象目前也只是使用了其中一部分,当然这跟应用环境也有关。来看个例子
$(function(){
    $(
"#btn_add").click(
        
function(){
            $(
"<div name='_info'><input type='text' name='info'/>&nbsp;&nbsp;&nbsp;<input name='btndel' type='button' value='删除' /></div>").find(":button").click(
                
function(){
                    
var index = jQuery("[name='btndel']").index(this); //this是删除按钮这个对象,index是获得该按钮在这组集合中的索引值
                    $("[name='_info']:eq("+index+")").remove();
                }
            ).end().appendTo(
"#div_info");
        }
    );
});
<div><input id="btn_add" type="button" value="增加" /></div>
<div id="div_info"></div>
    这段很少的代码却帮我们做了相当多的事情,详细分析一下
    在文档初始化的时候,对增加按钮绑定事件,当点击增加时,我们创建一个文本框和一个删除按钮的div,然后使用查找功能(find)在刚创建的html中找到button按钮(:button),这时会返回<input name='btndel' type='button' value='删除' />这个DOM元素的jQuery对象,接着给这个按钮绑定事件,使之,当我们点击某个删除按钮时,删除对应的元素。随后我们退回(end)到创建的div。最后把这个新增的元素追加到div_info元素之后,运行这个示例看看效果。PS创建DOM时,如果比较复杂,可以用变量来拼接字符串,最后再放到$()里面。
    这个例子充分体现了jQuery链的强大,一条语句就完成了这么多的功能,请大家充分利用jQuery链。牢记jQuery对象与DOM对象的区别。
    在删除的时候使用的是remove()而没有使用empty(),这两个方法执行后都会返回jQuery集合,不同的是,remove()会将元素从页面DOM中删除,而empty()只是删除匹配集合中的子节点(包括文本),但仍保留其在DOM中所占的位置。示例

$(function(){
    $(
"#btn_del").click(
        
function(){
            $(
"p").empty();
            
//$("p").remove();
        }
    );
});
<input id="btn_del" type="button" value="删除" />
<p>hello</p>
jquery
<p>welcome</p>
    Firefox来运行示例,启动Firebug工具可以看到文档加载完成时的情况
                    
    当我们点击删除后,结果如下
            
    再看执行remove方法后的结果
            
    文档处理的方法还有很多,我只能就遇到及使用过的举些例子说明一下,其它的就需要在大家工作中去发现去总结,也请各位把自己的心得体会分享出来,让我们一起学习,共同提高。所有代码均在jquery-1.2.6版本下测试通过。
    本文为菠萝大象原创,如要转载请注明出处。
posted on 2010-02-24 21:46 菠萝大象 阅读(6473) 评论(22)  编辑  收藏 所属分类: jQuery

评论:
# re: jQuery学习总结(三) 2010-02-25 09:03 | HiMagic!
jquery-1.2.6? 这是什么时候写的?  回复  更多评论
  
# re: jQuery学习总结(三) 2010-02-25 10:13 | 菠萝大象
@HiMagic!
最近刚写的,我一直都用的是jquery-1.2.6,因为当时做的时候是2009年2月,1.3刚发布不久,为了稳妥起见,决定还是采用1.2.6。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 10:56 | 大灰狼
我的表单中有个submit按钮,如何用jquery来禁止回车提交呢
<form action="login.action" method="post">
<table cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td>
<img src="<%=path%>/login/pic/logo.jpg" width="609" height="205" align="middle">
</td>
</tr>
<tr class="login_field">
<td align="center" valign="middle" height="37">
<b>用户名</b><input id="username" name="username" class="text" type="text" size="10" maxlength="30" tabindex="1"></input>
<b>密码</b><input id="password" name="password" class="password" type="password" size="10" maxlength="30" tabindex="2"></input>
<b>验证码</b><input id="vercode" name="vercode" class="text" type="text" size="10" tabindex="3"></input>
<a href="#" ><img id="authImg" src="<%=path%>/login/authImg.jsp" name="d" border="0" align="middle" title="看不清?点击更换验证码!"/></a>
<input id="input" name="submit" type="submit" value="登 录" class="submit" tabindex="4"></input>
</td>
</tr>
</tbody>
</table>
</form>  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 10:57 | 大灰狼
只让回车时焦点移到下一个输入框中,不让提交,如何实现这 样的功能  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 11:20 | 菠萝大象
@大灰狼
你可以对这三个文本框设置事件,按回车时,如果有值就跳到下一个本文框,没有值就停留在当然前本文框中,当所有文本框都有值时,再点回车就提交表单,如果想做的更好点,可以加入AJAX验证,比如当然离开用户名文本框焦点时,到后台去验证有无此用户名,等等功能都能实现。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 12:59 | 大灰狼
ajax的验证用户名我已经做了就是当失去焦点时用ajax判断,用户名是不是存在,我的登录按钮的type改button后,这个表单无法提交了,如果改为submit按回车是要提交的,可是那样就失去了按回车移到一下个输入框的功能了。如果这样<input id="input" name="submit" type="button" value="登 录" class="submit" tabindex="4"></input> 在jquery中如何改动,才能点击登录按钮时的提交事件  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 14:58 | 菠萝大象
@大灰狼
看来大灰狼童鞋对jQuery的API还不熟悉,如果你没有api,可以在我写的第一篇下载chm文档。如果form设置了id,比如叫loginform,在jQuery中,有一个submit()方法,$("#loginform").submit();就是提交表单。同理,你设置文本框的焦点,同样可以用jQuery提供的focus()方法,而且它返回一个jQuery对象,请注意不是DOM对象,所以可以继续以链式语法在后面加东西。jQuery的功能非常强大,一定要先对API深入学习下,这样开发会事半功倍滴。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 16:00 | 大灰狼
谢谢你了,
还是不行下面 是我的form:
<form id="loginform" action="login.action" method="post">
<table cellspacing="0" cellpadding="0" align="center">
<tbody>
<tr>
<td>
<img src="<%=path%>/login/pic/logo.jpg" width="609" height="205" align="middle">
</td>
</tr>
<tr class="login_field">
<td align="center" valign="middle" height="37">
<b>用户名</b><input id="username" name="username" class="text" type="text" size="10" maxlength="30" tabindex="1"></input>
<b>密码</b><input id="password" name="password" class="password" type="password" size="10" maxlength="30" tabindex="2"></input>
<b>验证码</b><input id="vercode" name="vercode" class="text" type="text" size="10" tabindex="3"></input>
<a href="#" ><img id="authImg" src="<%=path%>/login/authImg.jsp" name="d" border="0" align="middle" title="看不清?点击更换验证码!"/></a>
<input id="input" name="submit" type="button" value="登 录" class="submit" tabindex="4"></input>
</td>
</tr>
</tbody>
</table>
</form>
下面是我的js,在一个单独的文件里:
$("#vercode").keypress(
function(e)
{
if (e.keyCode == 13)
{
if (($("vercode").attr("value"))!="" || ($("#vercode").attr("value"))!=null)
{
$("#loginform").submit();
}else
{
$("#vercode")[0].focus();
}
}
});
用这个为什么仍然不能提交呢?  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 16:15 | 大灰狼
$("#loginform").submit();也就是这句没有触发提交事件,但是在这句的上面加上alert的时候是执行了的,就是$("#loginform").submit();这句没有执行,是何原因  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 16:20 | 大灰狼
我在那个username的输入框中触发blur事件的时候已经用ajax提交了一次数据了,不会有影响吧  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 16:37 | 菠萝大象
@大灰狼
你的代码存在好几个问题
第一,if (($("vercode").attr("value"))!="" || ($("#vercode").attr("value"))!=null) 使用ID选择器,你没有加#号
第二,对于取值,jQuery有相当简洁的方法$("#vercode").val(),另外不用加多重括号,你这里没有进行多条件的组合判断。
第三,你这个条件不应该是||,而应该是&&
第四,$("#vercode")[0].focus(); 这就变成DOM方法了,而且是在函数内定义,可以直接写成$(this).focus();
第五,不能写成name="submit",把name属性去掉,对于按钮,没有必要去设置它的name属性,就算要设置,也不要设置成submit,造成脚本错误。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 17:12 | 大灰狼
刚刚我已经解决了,不过还没注意到你写的问题,谢谢你了。但是第五条跟我的做法是一样的,我把ID和name设置成一样的都是inpu,就没有错误了,谢谢您的指点。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 17:21 | 大灰狼
这几天看您的帖子受益非浅,能不能另开个帖子写一下,关于页面布局的问题,就是frameset与div的问题,我们原来的项目中大量的应用了frameset尤其是登录后的主页面。  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-26 20:37 | 菠萝大象
@大灰狼
页面布局这涉及到CSS,大象对这块不擅长,所以无能为力啦,不过目前好的页面设计全是div+css,而不会去用frameset这些东西,连table都不用,你注意看国外的网站,都是div+css风格  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-27 08:36 | 大灰狼
谢谢了,有机会共同学习  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-27 22:28 | 大灰狼
继续请教个问题,上来我做的那个单独的JS文件今天刚让我不心删除了,里面有一段是关于图形验证吗,也就是说用鼠标点击那个图形的时候重新生成一张新的。在没有用jquery前是这样写的<a href="#" onclick="refresh()"><img id="authImg" src="<%=path%>/login/authImg.jsp" border="0" align="middle" title="看不清?点击更换验证码!"/></a>
function refresh()
{
document.getElementById("authImg").src='/wscm/login/authImg.jsp?now='+new Date();

}
用jquery后<a href="#" ><img id="authImg" src="<%=path%>/login/authImg.jsp" border="0" align="middle" title="看不清?点击更换验证码!"/></a> 然后在那个单独的js文件中这样写的 $("#authImg").click(
function()
{
$(this).attr("src")="/wscm/login/authImg.jsp?now="+new Date();
});
为什么现在点击图片没有反应了呢?  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-27 22:29 | 大灰狼
不用jquery的时候是正常的,是不是我的jquery写错了呢
  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-28 08:46 | 菠萝大象
@大灰狼
童鞋,你的jQuery语法记错了,$(this).attr("src","/wscm/login/authImg.jsp?now="+new Date());  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-29 10:00 | 大灰狼
多谢你的指点,看来还是对jquery不熟悉。继续请教个问题:
就是我的登录后的主页面用了framset框架,如下所示:
<FRAMESET id="frame1" border=0 frameSpacing=0 rows=50,*,20 frameBorder=NO cols=*>
<FRAME id="top" src="<%=path%>/main/top.jsp" frameBorder=0 noResize scrolling=no />
<FRAMESET id="frame2" border=0 frameSpacing=0 rows=* frameBorder=NO cols=200,*>
<FRAME id="menu" src="<%=path%>/main/menu.jsp" frameBorder=0 noResize />
<FRAME id="table" src="<%=path%>/main/table.jsp" frameBorder=0 />
</FRAMESET>
<FRAME id="bottom" src="<%=path%>/main/bottom.jsp" frameBorder=0 noResize scrolling=no />
其中的四个页面处于同级目录下,我在main目录下有三个子目录:css,js,pic,我在top.jsp引用了main/js/下的那个top.js文件,里面全部采用jquery,如下:$(document).ready(function(){
alert("你好");}
);但是当我登录成功后并没有触发这个alert事件,我把鼠标指到顶部的位置刷新的时候,才能触发alert事件。这是为什么?
如果不采用引入的js文件,而是直接把jquery的代码写到top.jsp文件中就可以了,登录的时候直接弹出了alert事件,再用再单独的刷新它。为什么引入一个单独的js文件却不行呢,是不是因为采用了framset的原因呢?  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-30 10:56 | 菠萝大象
@大灰狼
这个问题我不好回答,视情况而定,只能建议你检查下这些文件的引用路径对不对,很多时候是路径问题。另外建议你使用标准的语法规则,所有属性都加双引号,每个标签都要有结束标签。  回复  更多评论
  
# re: jQuery学习总结(三)[未登录] 2010-05-31 17:31 | 大灰狼
请教个问题
如题,我登录后的页面应用了framset框架,左侧是一个导航菜单,想根据登录用户的权限不同而展示不同的菜单,表结构如下:CREATE TABLE [dbo].[menus](
[orderid] [nchar](10) NOT NULL,
[menuid] [nchar](10) NOT NULL,
[menuname] [nchar](30) NOT NULL,
[Parentid] [nchar](10) NULL,
[Css] [nchar](100) NULL,
[url] [nchar](100) NULL,
CONSTRAINT [PK_menus] PRIMARY KEY CLUSTERED
(
[menuid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
表内容如下:
1 00001 AAAA 00000 NULL NULL
2 00002 BBBB 00001 NULL /lhcl.jsp
3 00003 CCCC 00000 NULL NULL
4 00004 DDDD 00003 NULL NULL
5 00005 EEEE 00004 NULL NULL
6 00006 FFFF 00005 NULL /a.jsp
7 00007 GGGG 00000 NULL NULL
如何利用jaquery,用ul,li的形式展现出来,另外上述就是一个用户的所有菜单,这个我已经采用ajax+json获取@菠萝大象
  回复  更多评论
  
# re: jQuery学习总结(三) 2010-05-31 17:39 | 菠萝大象
@大灰狼
现在讨论的东西越说越远了,还是就本文的内容讨论吧,大象我的精力有限,不能一一回答你的其它问题,这些都超出本文范围了,请你自己解决吧,抱歉!  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: