给元素注册事件时,事件函数中不能使用全局变量
最近在做项目的过程中,遇到这样的需求(为了便于说明,我对源需求进行了简化):需要通过js创建新的file元素,并要对新建的元素注册事件和添加属性。(注册的事件是用来在客户端验证上传的文件的大小和格式的)。
以下的代码并不是我项目中的代码,项目中的代码远比这个要复杂的多,而且摘下来的话,大家看的也费力。所以我就本着通俗易懂的原则,截取了一部分,并加工了一下。以便让大家更容易读懂!代码如下:
<script type="text/javascript>
var globalOne = 0; // 全局变量
var globalTwo = 0; // 全局变量
/*在此方法中,给新建元素注册的事件函数要用到全局变量的当前*/
function createElement(parentElement){
globalOne++;
globalTwo++;
var tempOne = globalOne; // 保存全局变量globalOne的当前值
var tempTwo = globalTwo; // 保存全局变量globalTwo的当前值
parentElement.appendChild(document.createTextNode("图片:"));
var textFiled3_pic = document.createElement("<input name=/"surveyOptPicfile_" + globalOne+ "_" + (globalTwo+ 1) + "/" >");
textFiled3_pic.setAttribute("type", "file");
textFiled3_pic.className = "input200";
textFiled3_pic.setAttribute("id", "surveyOptPicfile_" + globalOne+ "_" + (globalTwo + 1));
// 注册onchange事件
textFiled3_pic.attachEvent("onchange", function(){ var id = "surveyOptPicfile_" + globalOne+ "_" + (globalTwo+ 1); changeSrc(document.getElementById(id), id);}); // 此处不正确,不能用全局变量(本意是取得全局变量当时的值)
textFiled3_pic.attachEvent("onchange", function(){ var id = "surveyOptPicfile_" + tempOne + "_" + (tempTwo + 1); changeSrc(document.getElementById(id), id);}); // 此处正确(本意是取得全局变量当时的值)
parentElement.appendChild(textFiled3_pic); // 把创建的元素追加到父元素中
}
function changeSrc(obj, id){
// 在此做一些验证
}
</script>
在上面的注册onchange事件代码中,为什么红色标明的部分不正确,而绿色标明部分正确呢!
原因是在js中给新创建的元素注册事件时,注册的事件函数并不会在注册的时候就会被元素加载的,而是在元素的注册事件被触发的时候才加载,即执行事件定义的方法;但元素设置的属性,却会在元素定义之后立即被加载。大家可以通过在ie中用调试工具(或火狐的firebug)查看创建的元素的代码;代码中并不会显示事件。
所以,如果大家以红色的代码注册事件。当触发onchange事件时,注册函数中定义的变量id的值并不是当时注册的时候的全局变量的值;而是全局变量的当前值。要想让id的值重现全局变量重现当时注册时候的值,就应该使用绿色标明部分的代码。
说了这么多,也不知道我说明白了没有。下面我就给一简单的完整的例子——这样也算是对我上面说的一种解释吧。下面的代码兼容IE和火狐,其中蓝色标明部分的代码,请根据自己的浏览器注释掉不需要的部分。简单介绍下面的这段代码的作用:该段代码可以创建多个上传文件的file元素,在每个创建的file元素都注册一个onchange事件,用于验证上传的图片格式是否是.jpg或.gif或.png格式的。
<html>
<head>
<script type="text/javascript">
var globalOne = 0; // 全局变量
var globalTwo = 0; // 全局变量
/*在此方法中,给新建元素注册的事件函数要用到全局变量的当前*/
function createFileElement(parentElement){
globalOne++;
globalTwo++;
var tempOne = globalOne; // 保存全局变量globalOne的当前值
var tempTwo = globalTwo; // 保存全局变量globalTwo的当前值
parentElement.appendChild(document.createTextNode("新增上传图片组件" + globalOne + ":"));
/** IE创建新元素,并注册事件
var textFiled3_pic = document.createElement("<input name=/"surveyOptPicfile_" + globalOne + "_" + (globalTwo+ 1) + "/" >");
textFiled3_pic.className = "input200";
textFiled3_pic.setAttribute("id", "surveyOptPicfile_" + globalOne+ "_" + (globalTwo + 1));
// 注册onchange事件
textFiled3_pic.attachEvent("onchange", function(){ var id = "surveyOptPicfile_" + tempOne + "_" + (tempTwo + 1); changeSrc(document.getElementById(id), id);});
*/
/** FF创建新元素,并注册事件*/
var textFiled3_pic = document.createElement("input");
textFiled3_pic.setAttribute("name", "surveyOptPicfile_" + globalOne+ "_" + (globalTwo+ 1));
textFiled3_pic.setAttribute("type", "file");
textFiled3_pic.setAttribute("class", "input200");
textFiled3_pic.setAttribute("id", "surveyOptPicfile_" + globalOne+ "_" + (globalTwo+ 1));
textFiled3_pic.addEventListener("change", function(){var id = "surveyOptPicfile_" + tempOne + "_" + (tempTwo + 1); changeSrc(document.getElementById(id), id);}, false);
parentElement.appendChild(textFiled3_pic); // 把创建的元素追加到父元素中
}
// 验证文件格式(当然大家也可在这个函数中做其他一些操作)
function changeSrc(fileObj, fileElementId)
{
var fileName = fileObj.value;
if(!fileName.match(//.jpg|/.gif|/.png/ig)){
alert("您上传的图片格式不正确!");
return false;
}
return true;
}
</script>
</head>
<body>
<form name="form1" id="form1">
请选择图片:<input type="file" name="surveyOptPicfile_0_0" id="surveyOptPicfile_0_0" onchange="changeSrc(this, 'surveyOptPicfile_0_0')">
<input type="button" value="增加上传组件" onclick="createFileElement(document.form1);">
</form>
</body>
</html>
大家可以直接把上面的代码拷到本地执行!(如果在注册onchange事件的时候不是textFiled3_pic.addEventListener("change", function(){var id = "surveyOptPicfile_" + tempOne + "_" + (tempTwo + 1); changeSrc(document.getElementById(id), id);}, false); 而是使用全局变量textFiled3_pic.addEventListener("change", function(){var id = "surveyOptPicfile_" + globalOne+ "_" + (globalTwo+ 1); changeSrc(document.getElementById(id), id);}, false); 则用新创建的file组件上传图片,不能正确的验证上传的图片格式,即使你上传的格式正确,也会提示你格式错了!大家可以试试!)
另:在注册事件中使用关键字this也将不起作用,而是会把它当做普通的字符串!