【学习笔记九】 - 事件类型 + 表单脚本 《js高程》13-14笔记

写在前面:

这篇是《js高程》13.4-13.6和14.1-14.4的笔记,记在网上也是方便自己以后随时随地可以回看。

13章前面的内容在 JS冒泡与捕获 那篇单独拎出来整理了。

其他详见代码注释 : )


PS :前面的EventUtil具体怎么来的可以看冒泡和捕获那篇↑


var EventUtil={
  addHandler:function(element,type,handler){
    if(element.addEventListener){
      element.addEventListener(type,handler,false);
    }else if(element.attachEvent){
      element.attachEvent('on'+type,handler);
    }else{
      element['on'+type]=handler;
    }
  },

  getEvent:function(event){
    return event?event:window.event;
  },
  getTarget:function(event){
    return event.target||event.srcElement;
  },
  preventDefault:function(event){
    if(event.preventDefault){
      event.preventDefault();
    }else{
      event.returnValue=false;
    }
  },

  removeHandler:function(element,type,handler){
    if(element.removeEventListener){
      element.removeEventListener(type,handler,false);
    }else(element.detachEvent){
      element.detachEvent('on'+type,handler);
    }else{
      element['on'+type]=null;
    }
  },

  stopPropagation:function(event){
    if(event.stopPropagation){
      event.stopPropagation();
    }else{
      event.cancelBubble=true;
    }
  }

};


【事件类型】


// UI事件-load\unload

var isSupport=document.implementation.hasFeature('HTMLEvents','2.0');
//两种指定方式
//一:js,推荐
//这里传入的event对象不包含有关这个事件的任何附加信息,
//但在兼容DOM的浏览器中event.target被设为document,
//而IE并不会为这个事件设置srcElement属性
EventUtil.addHandler(window,'load',function(event){
  alert('Loaded!');
});
//二:向后兼容 <body onload="alert('...')">

//在图像上触发load时,要先指定事件再指定src,因为图像在指定src属性后就会开始下载
EventUtil.addHandler(window,'load',function(){
  //先向window添加load,因为要在dom中添加新元素,首先要确保文档加载完毕
  var image=document.createElement('img');
  EventUtil.addHandler(image,'load',function(event){
    event=EventUtil.getEvent(event);
    alert(EventUtil.getTarget(event).src);
  });
  document.body.appendChild(image);
  image.src='...';
});
//注:在不属于DOM文档的图像上触发load,IE8及以前版本不会生产event对象

//IE9+、Firefox、Opera、Chrome、Safari3+中,<script>也可触发load
//不同于img,只有在设置了<script>的src属性并将添加到文档后,才会开始下载js文件
//所以指定事件处理程序和src属性的先后顺序就不重要
//IE和Opera支持<link>上的load,未指定href并添加到文档之前也不会下载样式表

EventUtil.addHandler(window,'unload',function(event){
  alert('Unloaded!');
});
//生成的event对象在兼容dom的浏览器中只包含target,IE8及以前提供了srcElement
//鼠标与滚轮事件

//dom通过event的relatedTarget属性提供相关元素信息,
//这个属性只对mouseover、mouseout才包含值,对其他事件来说为null,
//IE8及以前不支持relatedTarget,但在mouseover中有fromElement,在mouseout中有toElement
//添加取得相关元素方法:
var EventUtil={
  //...其他代码
  getRelatedTarget:function(event){
    if(event.relatedTarget){
      return event.relatedTarget;
    }else if(event.toElement){
      return event.toElement;
    }else if(event.fromElement){
      return event.fromElement;
    }else{
      return null;
    }
  },
  //...
};

var div=document.getElementById('myDiv');
EventUtil.addHandler(div,'mouseout',function(event){
  event=EventUtil.getEvent(event);
  var target=EventUtil.getTarget(event);
  var relatedTarget=EventUtil.getRelatedTarget(event);
  alert('moused out of'+target.tagName+'to'+relatedTarget.tagName);
});


//鼠标按钮
//对mouseup和mousedown,event有一个button属性:
//值为0表示左键,1滚轮,2右键
//IE8及以前:
//0没有按,1左键,2右键,3左右,4滚轮,5左键滚轮,6右键滚轮,7左右滚轮
//Opera中不是操作左键不会触发mouseup和mousedown
var EventUtil={
  //...
  getButton:function(event){
    if(document.implementation.hasFeature('MouseEvents','2.0')){
      return event.button;
    }else{
      switch(event.button){
        case 0:
        case 1:
        case 3:
        case 5:
        case 7:
          return 0;//01357都返回0
        case 2:
        case 6:
          return 2;//26都返回2
        case 4:
          return 1;//4返回1
      }
    }
  },
  //...
};

var div=document.getElementById('myDiv');
EventUtil.addHandler(div,'mousedown',function(event){
  event=EventUtil.getEvent(event);
  alert(EventUtil.getButton(event));
});


//鼠标滚轮事件
//mousewheel事件对应的event有一个wheelDelta属性,向前滚动是值为120的倍数,向后-120的倍数
//Opera9.5以前正负相反
//Firefox支持DOMMouseScroll事件,detail属性,向前是-3的倍数,向后3的倍数

//键盘与文本事件
//IE9、Firefox、Chrome、Safari的event支持一个charCode属性,
//只有在发生keypress时才包含值,保存按键代表字符ASCII码,
//keyCode通常为0或按键键码;
//IE8及以前和Opera则在keyCode中保存ASCII码;

var EventUtil={
  //...
  getCharCode:function(event){
    if(typeof event.charCode=='number'){
      //先检查charCode是否包含数值,在不支持这个属性的浏览器中值为undefined
      return event.charCode;
    }else{
      return event.keyCode;
    }
  },
  //...
};

var textbox=document.getElementById('myText');
EventUtil.addHandler(textbox,'keypress',function(event){
  event=EventUtil.getEvent(event);
  var ch=EventUtil.getCharCode(event);
  alert(ch);
  alert(String.fromCharCode(ch));
  //取得字符编码后可用String.fromCharCode()将其转换成实际字符
});

//HTML5事件

//contextmenu事件,用以表示合适应该显示上下文菜单,冒泡,属于鼠标事件
//IE、Firefox、Safari、Chrome、Opera 11+
EventUtil.addHandler(window,'load',function(event){
  var div=document.getElementById("myDiv");
  EventUtil.addHandler(div,'contextmenu',function(event){
    event=EventUtil.getEvent(event);
    EventUtil.preventDefault(event);//取消浏览器默认菜单

    var menu=document.getElementById('myMenu');
    menu.style.left=event.clientX+'px';
    menu.style.top=event.clientY+'px';//确定放置菜单(<ul>)的位置
    menu.style.visibility='visible';//显示菜单
  });

  EventUtil.addHandler(document,'click',function(event){
    document.getElementById('myMenu').style.visibility='hidden';
  });//单词鼠标隐藏菜单
});


//beforeunload事件,在页面卸载操作之前阻止卸载操作
//IE、Safari、Firefox、Chrome支持,但Opera11及以前不支持
EventUtil.addHandler(window,'beforeunload',function(event){
  event=EventUtil.getEvent(event);
  var message="Sure to navigate away from this page?";
  event.returnValue=message;//IE、Firefox
  return message;//Safari、Chrome
});

【内存与性能】


//事件委托,是对"事件处理程序过多"的解决方案,利用冒泡,只指定一个事件处理程序,管理某一类型所以事件。
//最适合采用事件委托的事件有:click、mousedown、mouseup、keydown、keyup、keypress
//如果可行,也可在document对象上添加一个事件处理程序,用以处理某种特定类型的事件
/*
<ul id="myLinks">
  <li id="goSomewhere">Go somewhere</li>
  <li id="doSomething">Do something</li>
  <li id="sayHi">Say hi</li>
</ul>
 */
var list=document.getElementById('myLinks');
EventUtil.addHandler(list,"click",function(event){
  event=EventUtil.getEvent(event);
  var target=EventUtil.getTarget(event);

  switch(target.id){
    case "doSomething":
      document.title="I changed the document's title";
      break;
    case "goSomewhere":
      location.href="http://www.wrox.com";
      break;
    case "sayHi":
      alert("hi");
      break;
  }

});
//移除事件处理程序
//内存中留有那些过时不用的"空事件处理程序"的两种原因:
//1、从文档中移除带事件处理程序的元素,如纯粹DOM操作:removeChild()、replaceChild(),或用innerHTML替换
  btn.onclick=function(){
    btn.onclick=null;//先移除事件处理程序再替换
    document.getElementById("myDiv").innerHTML="...";
  };
//注:在事件处理程序中删除按钮也能阻止事件冒泡,元素在文档中是冒泡的前提
//2、卸载页面时(可能是在两个页面来回切换或刷新),内存中滞留的对象数目会增加
//  最好的做法是,卸载之前先通过onunload事件处理程序移除所有事件处理程序


【模拟事件】


//可用js在任意时刻触发特定事件,在测试时非常有用

//DOM中的事件模拟
//在document对象上使用createEvent()创建event对象,接收一个参数,表示要创建事件类型的字符串
//如:UIEvents\MouseEvents\MutationEvents\HTMLEvents
//调用dispatchEvent()触发事件,接收一个参数,表示要触发事件的event对象,这样触发的事件照样冒泡

//模拟鼠标事件
//创建的对象有一个initMouseEvent()方法,用于指定与该鼠标事件有关的信息,接收15个参数,前5个为:
//type要触发的事件类型、bubbles是否冒泡、cancelable是否可以取消、view与事件关联的视图、detail与事件有关的详细信息
var btn=document.getElementById("myBtn");
var event=document.createEvent("MouseEvents");
//初始化对象
event.initMouseEvent("click",true,true,document.defaultView,0,0,0,0,0,false,false,false,false,0,null);
btn.dispatchEvent(event);

//模拟键盘事件
var textbox=document.getElementById("myTextbox"),event;
//以DOM3级方式创建事件对象
if(document.implementation.hasFeature("KeyboardEvents","3.0")){
  event=document.createEvent("KeyboardEvent");
  event.initKeyboardEvent("keydown",true,true,document.defaultView,"a",0,"Shift",0);
  //'a' 按下的键码-按下了哪里的键,0是主键盘-空调图-在一行中按了多少次这个键,0
}
textbox.dispatchEvent(event);

//在Firefox中
var textbox=document.getElementById("myTextbox"),event;
event=document.createEvent("KeyEvents");
event.initKeyEvent('keypress',true,true,document.defaultView,false,false,false,false,65,65);
//ctrl-alt-shift-meta-keyCode键码-charCode ASCII码
textbox.dispatchEvent(event);

//其他浏览器中,创建一个通用的事件
var textbox=document.getElementById("myTextbox"),event;
event=document.createEvent("Events");

event.initEvent(type,bubbles,cancelable);
event.view=document.defaultView;
event.altKey=false;
event.ctrlKey=false;
event.shiftKey=false;
event.metaKey=false;
event.keyCode=65;
event.charCode=65;

textbox.dispatchEvent(event);

//像这样模拟事件虽然会触发键盘事件,但却不会向文本框中写入文本,这是由于无法精确模拟键盘事件造成的


//DOM3还定义了自定义事件,调用createEvent("CustomEvent"),
//返回的对象有一个initCustomEvent()方法,接收四个参数:
//type、bubbles、cancelable、detail
//IE9+、Firefox6+
var div=document.getElementById('myDiv'),event;
EventUtil.addHandler(div,'myevent',function(event){
  alert('DIV:'+event.detail);
});
EventUtil.addHandler(document,"myevent",function(event){
  alert('DOCUMENT:'+event.detail);
});
if(document,implementation.hasFeature("CustomEvents","3.0")){
  event=document.createEvent("CustomEvent");
  event.initCustomEvent("myevent",true,false,"hello world!");
  div.dispatchEvent(event);
}



//IE中的事件模拟
//调用document.createEventObject(),无参数,返回一个通用event对象,要手动添加必要信息,
//在目标上调用fireEvent()方法,接收两个参数:事件处理程序名称和event对象,
//在调用这个方法时会自动为event对象添加srcElement和type属性,其他属性手动添加

var btn=document.getElementById('myBtn');
var event=document.createEventObject();
event.screenX=100;
event.screenY=0;
event.clientX=0;
event.clientY=0;
event.ctrlKey=false;
event.altKey=false;
event.shiftKey=false;
event.button=0;
btn.fireEvent("onclick",event);

var textbox=document.getElementById("myTextbox");
var event=document.createEventObject();
event.altKey=false;
event.ctrlKey=false;
event.shiftKey=false;
event.keyCode=65;
textbox.fireEvent("onkeypress",event);



【表单基础】


//避免多次提交表单

EventUtil.addHandler(form,'submit',function(event){
	event=EventUtil.getEvent(event);
	target=EventUtil.getTarget(event);

	var btn=target.elements['submit-btn'];
	btn.disabled=true;
});
//focus()\blur()

EventUtil.addHandler(window,'load',function(event){
	document.forms[0].elements[0].focus();
});
//如果第一个表单字段是<input>,且type为'hidden',上面代码会出错
//如果css的display和visibility隐藏了该字段,同样致错

//HTML5新增autofocus属性,自动把焦点移到相应字段
//Firefox4+、Safari5+、Chrome、Opera9.6
//<input type='text' autofocus>

EventUtil.addHandler(window,'load',function(event){
	var element=document.forms[0].elements[0];
	if(element.autofocus!==true){
		//autofocus在支持的浏览器中是true,不支持的是空字符串
		element.focus();
	}
});
//change事件常用于验证用户在字段中输入的数据

var textbox=document.forms[0].elements[0];
EventUtil.addHandler(textbox,'focus',function(event){
	event=EventUtil.getEvent(event);
	var target=EventUtil.getTarget(event);

	if(target.style.backgroundColor!='red'){
		target.style.backgroundColor='yellow';
	}
});

EventUtil.addHandler(textbox,'blur',function(event){
	event=EventUtil.getEvent(event);
	var target=EventUtil.getTarget(event);

	if(/[^\d]/.test(target.value)){
		target.style.backgroundColor='red';
	}else{
		target.style.backgroundColor='';
	}
});

EventUtil.addHandler(textbox,'change',function(event){
	event=EventUtil.getEvent(event);
	var target=EventUtil.getTarget(event);

	if(/[^\d]/.test(target.value)){
		target.style.backgroundColor='red';
	}else{
		target.style.backgroundColor='';
	}
});



【文本框脚本】

//选择文本select(),无参。
//应用:让用户在文本框获得焦点时选择所有文本,不必一个一个删除。
//IE9+、Opera、Firefox、Chrome、Safari,只有用户选择且释放鼠标才触发select事件;
//IE8及以前,只要选择一个字符,不释放鼠标,就触发;
//调用select()会触发select事件;

//HTML5新增selectionStart和selectionEnd属性
//IE9+、Opera、Firefox、Chrome、Safari
//IE8及以前用document.selection对象,保存着用户在整个文档范围选择的文本信息

function getSelectedText(textbox){
	if(typeof textbox.selectionStart=='number'){
		return textbox.value.substring(textbox.selectionStart,textbox.selectionEnd);
	}else if(document.selection){
		return document.selection.createRange().text;
	}
}

//HTML5选择部分文本:setSelectionRange(),两个参数,起始结束索引
//IE9+、Opera、Firefox、Chrome、Safari
//IE8及以前用范围选择文本

function selectText(textbox,startIndex,stopIndex){
	if(textbox.setSelectionRange){
		textbox.setSelectionRange(startIndex,stopIndex);
	}else if(textbox.createTextRange){
		var range=textbox.createTextRange();
		range.collapse(true);//折叠范围,true表示折叠刀范围起点
		range.moveStart('character',startIndex);
		range.moveEnd('character',stopIndex-startIndex);
		range.select();
	}
	textbox.focus();
}
textbox.value='hello world!';
selectText(textbox,0,textbox.value.length);


//过滤输入屏蔽字符
//在Firefox中所有由非字符键触发的keypress事件对应字符编码0,Safari3以前为8

EventUtil.addHandler(textbox,'keypress',function(event){
	event=EventUtil.getEvent(event);
	var target=EventUtil.getTarget(event);
	var charCode=EventUtil.getCharCode(event);

	if(!/\d/.test(String.fromCharCode(charCode))&&charCode>9&&!event.ctrlKey){
		EventUtil.preventDefault(event);
	}
});

//剪切板事件:
//beforecopy、copy、beforecut、cut、beforepaste、paste
//在Safari、Chrome、Firefox中三个before事件只会显示针对文本框的上下文菜单的情况触发,
//IE会在触发copy、cut、paste之前先行触发before。
//
//通过before可以向剪贴板发送数据,或者从剪贴板取得之前修改数据,
//访问数据用clipboardData对象,IE中是window的属性,Firefox4+、Safari、Chrome中是event的属性,
//在Firefox、Safari、Chrome中只有在处理剪贴板事件期间这个对象才有效,IE中可随时访问。
//
//clipboardData的三个方法:getData()、setData()、clearData()
//在Firefox、Safari、Chrome中只允许在onpaste事件处理程序中访问getData()
//
//补充:可以在paste事件中确认剪贴板中的值是否有效,若无效可取消默认行为

var EventUtil={
	//...
	getClipboardText:function(event){
		var clipboardData=(event.clipboardData||window.clipboardData);
		return clipboardData.getData('text');
	},
	setClipboardText:function(event){
		if(event.clipboardData){
			return event.clipboardData.setData('text/plain',value);
		}else if(window.clipboardData){
			return window.clipboardData.setData('text',value);
		}
	},
	//...
};
//自动切换焦点
//在前一个文本框字符数达到最大后,自动切换焦点到下一个文本框

(function(){
	function tabForward(event){
		event=EventUtil.getEvent(event);
		var target=EventUtil.getTarget(event);

		if(target.value.length==target.maxLength){
			var form=target.form;
			for (var i = 0,len=form.elements.length; i < len; i++){
				if(form.elements[i]==target){
					if(form.elements[i+1]){
						form.elements[i+1].focus();
					}
					return;
				}
			}
		}
	}
	var textbox1=document.getElementById('txtTel1');
	var textbox2=document.getElementById('txtTel2');
	var textbox3=document.getElementById('txtTel3');
	EventUtil.addHandler(textbox1,'keyup',tabForward);
	EventUtil.addHandler(textbox2,'keyup',tabForward);
	EventUtil.addHandler(textbox3,'keyup',tabForward);
	//keyup会在用户输入了新字符后出发,此时是检测内容长度最佳时机
})();



【选择框脚本】


//取得所有选中项
//遍历选项集合,然后测试每个选项的selected属性

function getSelectedOptions(selectbox){
	var result=new Array();
	var option=null;
	for (var i = 0,len=selectbox.options.length; i < len; i++) {
		option=selectbox.options[i];
		if(option.selected){
			result.push(option);
		}
	}
	return result;
}
//动态创建选项的三种方法:
//1、DOM方法
var selectbox=document.forms[0].elements['location'];
var newOption=document.createElement('option');
newOption.appendChild(document.createTextNode('Option text'));
newOption.setAttribute('value','Option value');
selectbox.appendChild(newOption);
//2、使用Option构造函数
//IE中存在bug,不能正确设置新选项的文本
var newOption=new Option('Option text','Option value');
selectbox.appendChild(newOption);
//3、使用选择框的add(newOpt,relOpt)方法
//该方法在relOpt之前插入newOpt,若要插入到最后,应将relOpt设为null,
//IE中第二个参数可选,但必须是新选项之后选项的索引,
//兼容DOM的浏览器要求必须指定第二个参数,
//所以,
//将relOpt设为undefined,兼容所有浏览器插入到最后
//(插入其他位置用DOM+insertBefore()方法)
var newOption=new Option('Option text','Option value');
selectbox.add(newOption,undefined);
//移除选项的三种方式:
//1、DOM的removeChild()方法
selectbox.removeChild(selectbox.options[0]);
//2、使用选择框的remove()方法
selectbox.remove(0);
//3、将相应选项设为null
selectbox.options[0]=null;
//移动和重排选项

//将第一个选择框中的第一个选项移动到第二个选择框
var selectbox1=document.getElementById('selLocations1');
var selectbox2=document.getElementById('selLocations2');
selectbox2.appendChild(selectbox1.options[0]);

//在选择框中向前移动一个选项的位置
var optionToMove=selectbox.options[1];
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index-1]);

//在选择框中向后移动一个选项的位置
var optionToMove=selectbox.options[1];
selectbox.insertBefore(optionToMove,selectbox.options[optionToMove.index+2]);

//注:IE7存在页面重绘问题,有时用DOM方法重排的选项不能马上正确显示


【表单序列化】


function serialize(form){
	var parts=[],
		field=null,
		i,len,j,optLen,option,optValue;
	for	(i = 0,len=form.elements.length; i < len; i++) {
		field=form.elements[i];

		switch(field.type){
			//type属性未定义的不需要序列化
			case "select-one":
			case "selsct-multiple":
				if(field.name.length){
					for(j=0,optLen=field.options.length;j<optLen;j++){
						option=field.options[j];
						if(option.selected){
							optValue='';
							if(option.hasAttribute){
								//兼容DOM的浏览器中
								optValue=(option.hasAttribute('value')?option.value:option.text);
								//如果不存在value特性,或存在但为空字符串,用选项的文本来代替
							}else{
								//IE
								optValue=(option.attributes['value'].specified?option.value:option.text);
							}
							parts.push(encodeURIComponet(field.name)+'='+encodeURIComponet(optValue));
						}
					}
				}
				break;
			case undefined:
			case "file":
			case "submit":
			case "reset":
			case "button":
				break;
			case "radio":
			case "checkbox":
				if(!field.checked){
					break;
				}
			default:
				//不包含没有名字的表单字段
				if(field.name.length){
					parts.push(encodeURIComponet(field.name)+'='+encodeURIComponet(optValue));
				}
		}
	}
	return parts.join("&");
}


猜你喜欢

转载自blog.csdn.net/jiuto_crx/article/details/78073928
今日推荐