起因
下面的讲述的事情是从开发出差申请流程开始的。涉及的知识点偏多,且得容我慢慢梳理出来。以下篇幅可能会有点儿长,但内容我会争取写得精彩的。
发起表单样式如图1,我想实现的是当修改出发日期或结束日期的时候,自动计算时长,时长不能被人为修改。并且时长要有合计。
经过
总结起来,需求还是挺简单的。那就一项一项的来。
一、解决出发日期控件和结束日期控件的事件绑定。
这里建议先读一下《E8-怎么监听表单里的日期控件被修改过_rarenmen的博客-CSDN博客》,这里讲述了关于日期控件的结构,以及需要监听的事件,是本文的一个基础知识点。
* 注:本文中,灰色字体代码为相关但非重点代码,下同。
$("#fieldfield10484span").bind('DOMNodeInserted',function(e){ alert("444"); }); |
看到这里,引出了第一个问题,明细表里的日期控件的命名格式是“field9442_” + 行号 + “span”的格式,并且表单里有多少明细行,是由用户操作而来的,那么能不能在JQuery的选择器里用变量或模糊匹配呢。
其实JQuery是支持选器的模糊匹配的,也测试成功了,适用于这个例子的语法如下,还有其它匹配方式,感兴趣的朋友请自行百度。
$("span[id^='field10484']").each(function(index,obj){ $(obj).bind("DOMNodeInserted",function(){ }); |
写了个HTML,试了一下,这么写,功能倒是可以实现给页面里现有的所有ID以field10484开头的SPAN标签梆定了事件,但这种方法存在两个问题:1、如果把它放在jQuery(document).ready(function(){});里,实现不了给新增行里的相应日期控件绑定事件,解决办法会在问题二里去说;2、如果这么处理,每次是给页面里所有的符合条件的控件绑定事件,仔细想,其实要做事情是当新增行的时候去给新增行里的日期控件绑定事件,那是给指定控件去绑事件的,看来要把之前的方法升级一下。在热心网友的帮助下,把绑定事件的方法改成了这样。
for(var i = indexnum0Old; i < indexnum0New; i++) { // 给指定的控件绑定事件 (function (arg) { jQuery("#field10484_"+arg+"span").bind("DOMNodeInserted", function(){ alert($(obj).attr("id")); }); }(i));//匿名function,i是实参 }//end for |
我个人觉得,这里有两个值得关注的知识点:1、JQuery里的选择器里是要以写变量的;2、有这么一种定义匿名函数的方法,并可以直接给它传递实参。第一个问题聊到这里结束。
二、该选择在什么时候绑定控件的事件
之前提到了,如果在jQuery(document).ready(function(){});里绑定事件,作用对象只会是表单里的现有控件。就是在流程表单里设置的默认的空行里的对应控件被绑定事件了,但用户新增行的对应控件是没有绑定事件的。去分析了一下页面关于明细行的HTML代码,发现明细行是被包含在一个ID叫作detailDiv_0的DIV里。这么说,可以给detailDiv_0绑定DOMNodeInserted事件,当其中内容被改的时候,去绑定日期控件的事件。但这么做也不合适,在实测的时候,发现在点击新增的时候,触发执行了若干次的DOMNodeInserted事件。
热心网友又给出了一个好方法。页面里有一个ID是indexnum0的控件,保存了内表的行数。可以给它绑定控件。嗯,看起来这是个好办法。这里需要注意,不能绑定change事件,要去绑定bindPropertyChange事件。
整理一下思路,实现给新增行的日期控件绑定事件。
jQuery(document).ready(function(){ $("#indexnum0").bindPropertyChange(function(){ // 根据新旧行数的比较,判断是增行还是减行,如果是增行了,做事件绑定 // 开始日期 // 结束日期 jQuery("#field10485_"+arg+"span").bind("DOMNodeInserted", function(){ |
以上代码里,calculationDays(i)是计算从开始日期到结束日期间,一共多少天,在给日期控件绑定了事件之后,调用一次这个方法,主要是解决在默认的空行里,只有默认开始日期和结束日期,但没有天数的问题。
三、怎么能让“时长”不被修改
明细表里有个字段,叫“时长”,记录从开始日期到结束日期间,一共的天数。
从需求的字面意思来看,这个问题非常简单,把“时长”设置成只读就好了。最简单的解决办法确实是这样,但新问题又来了。当用$("#field10486_" + line).val(totalDays);给“时长”赋值的时候,前台没有效果。看页面的源码可以发现,当控件属性被设置成“只读”的时候,<input>标签是存在但被隐藏的,应该是用作和后台的信息交互,用户所看到的内容其实是展示在对应的<span>标签里的文本。
情况了解了,那么处理的方法也就有了。<input>控件正常赋值,判断<span>控件存不存在,如果存在,修改一下它其中的文字就好了。
$("#field10486_" + line).val(totalDays); if($("#field10486_" + line + "span").length>0){ // 判断<span>标签是否存在 |
四、“时长”变了,但“合计”不变怎么办
初发现这情况的时候,以为是由于“时长”设置成了“只读”造成的。这里可以说一句“实则不然”,但也有关系,当把“时长”设置成“编辑”的时候,在控件的onChange事件里有一个calSum(0)的方法,它是负责计算合计行的。参数里的0,我猜是和detailDiv_0里的0同样是代表的是第一个明细表。在用JS给"时长"对应的<input>控件赋值后,再调用一下这个方法,就可以实现计算合计。可能有些小伙伴会想,如果“时长”是可编辑的,是不是就没有这个问题了。其实在用JS去修改<input>控件的值时,onChange事件是不被触发的,依然会有同样问题。
到此,遇到的问题都讲述完了。整体粘一下代码。
<script type="text/javascript"> $("#indexnum0").bindPropertyChange(function(){ // 根据新旧行数的比较,判断是增行还是减行,如果是增行了,做事件绑定 // 开始日期 // 结束日期 // 根据行号,取开始日期和结束日期,计算时长 // 触发计算合计的方法 if($("#field10486_" + line + "span").length>0){ |
结果
功能实现完成,至于知识点,这里先不整理了,有砖要搬,请小伙伴们自行归纳。