js函数 事件,事件类型,事件对象,事件委托

js函数集

·字符串(String) 

1.声明 

var myString = new String("Every good boy does fine."); 

var myString = "Every good boy does fine.";

2.字符串连接 

var myString = "Every " + "good boy " + "does fine."; 

var myString = "Every "; myString += "good boy does fine.";

3.截取字符串 

//截取第 6 位开始的字符 

var myString = "Every good boy does fine."; 

var section = myString.substring(6); //结果: "good boy does fine."

//截取第 0 位开始至第 10 位为止的字符 

var myString = "Every good boy does fine."; 

var section = myString.substring(0,10); //结果: "Every good"

//截取从第 11 位到倒数第 6 位为止的字符 

var myString = "Every good boy does fine."; 

var section = myString.slice(11,-6); //结果: "boy does"

//从第 6 位开始截取长度为 4 的字符 

var myString = "Every good boy does fine."; 

var section = myString.substr(6,4); //结果: "good"

4.转换大小写 

var myString = "Hello"; 

var lcString = myString.toLowerCase(); //结果: "hello" 

var ucString = myString.toUpperCase(); //结果: "HELLO"

5.字符串比较 

var aString = "Hello!"; 

var bString = new String("Hello!"); 

if( aString == "Hello!" ){ } //结果: true 

if( aString == bString ){ } //结果: true 

if( aString === bString ){ } //结果: false (两个对象不同,尽管它们的值相同)

6.检索字符串 

var myString = "hello everybody."; 

// 如果检索不到会返回-1,检索到的话返回在该串中的起始位置 

if( myString.indexOf("every") > -1 ){ } //结果: true

7.查找替换字符串 

var myString = "I is your father."; 

var result = myString.replace("is","am"); //结果: "I am your father."

8.特殊字符: 

\b : 后退符 \t : 水平制表符 

\n : 换行符 \v : 垂直制表符 

\f : 分页符 \r : 回车符 

\" : 双引号 \' : 单引号 

\\ : 反斜杆

9.将字符转换成Unicode编码 

var myString = "hello"; 

var code = myString.charCodeAt(3); //返回"l"的Unicode编码(整型) 

var char = String.fromCharCode(66); //返回Unicode为66的字符

10.将字符串转换成URL编码 

var myString = "hello all"; 

var code = encodeURI(myString); //结果: "hello%20all" 

var str = decodeURI(code); //结果: "hello all" 

//相应的还有: encodeURIComponent() decodeURIComponent()

11.将字符串转换成base64编码 

// base64Encode() base64Decode() 用法同上

//-----------------------------------------------------------------------

·数字型(Number) 

1.声明 

var i = 1; 

var i = new Number(1);

2.字符串与数字间的转换 

var i = 1; 

var str = i.toString(); //结果: "1" 

var str = new String(i); //结果: "1" 

i = parseInt(str); //结果: 1 

i = parseFloat(str); //结果: 1.0

//注意: parseInt,parseFloat会把一个类似于"32G"的字符串,强制转换成32

3.判断是否为有效的数字 

var i = 123; var str = "string"; 

if( typeof i == "number" ){ } //true

//某些方法(如:parseInt,parseFloat)会返回一个特殊的值NaN(Not a Number) 

//请注意第2点中的[注意],此方法不完全适合判断一个字符串是否是数字型!! 

i = parseInt(str); 

if( isNaN(i) ){ }

4.数字型比较 

//此知识与[字符串比较]相同

5.小数转整数 

var f = 1.5; 

var i = Math.round(f); //结果:2 (四舍五入) 

var i = Math.ceil(f); //结果:2 (返回大于f的最小整数) 

var i = Math.floor(f); //结果:1 (返回小于f的最大整数)

6.格式化显示数字 

var i = 3.14159;

//格式化为两位小数的浮点数 

var str = i.toFixed(2); //结果: "3.14"

//格式化为五位数字的浮点数(从左到右五位数字,不够补零) 

var str = i.toPrecision(5); //结果: "3.1415"

7.X进制数字的转换 

//不是很懂 -.- 

var i = parseInt("0x1f",16); 

var i = parseInt(i,10); 

var i = parseInt("11010011",2);

8.随机数 

//返回0-1之间的任意小数 

var rnd = Math.random(); 

//返回0-n之间的任意整数(不包括n) 

var rnd = Math.floor(Math.random() * n)

//-----------------------------------------------------------------------

·Math对象 

1. Math.abs(num) : 返回num的绝对值 

2. Math.acos(num) : 返回num的反余弦值 

3. Math.asin(num) : 返回num的反正弦值 

4. Math.atan(num) : 返回num的反正切值 

5. Math.atan2(y,x) : 返回y除以x的商的反正切值 

6. Math.ceil(num) : 返回大于num的最小整数 

7. Math.cos(num) : 返回num的余弦值 

8. Math.exp(x) : 返回以自然数为底,x次幂的数 

9. Math.floor(num) : 返回小于num的最大整数 

10.Math.log(num) : 返回num的自然对数 

11.Math.max(num1,num2) : 返回num1和num2中较大的一个 

12.Math.min(num1,num2) : 返回num1和num2中较小的一个 

13.Math.pow(x,y) : 返回x的y次方的值 

14.Math.random() : 返回0到1之间的一个随机数 

15.Math.round(num) : 返回num四舍五入后的值 

16.Math.sin(num) : 返回num的正弦值 

17.Math.sqrt(num) : 返回num的平方根 

18.Math.tan(num) : 返回num的正切值 

19.Math.E : 自然数(2.718281828459045) 

20.Math.LN2 : 2的自然对数(0.6931471805599453) 

21.Math.LN10 : 10的自然对数(2.302585092994046) 

22.Math.LOG2E : log 2 为底的自然数(1.4426950408889634) 

23.Math.LOG10E : log 10 为底的自然数(0.4342944819032518) 

24.Math.PI : π(3.141592653589793) 

25.Math.SQRT1_2 : 1/2的平方根(0.7071067811865476) 

26.Math.SQRT2 : 2的平方根(1.4142135623730951)

//-----------------------------------------------------------------------

·日期型(Date) 

1.声明 

var myDate = new Date(); //系统当前时间

var myDate = new Date(yyyy, mm, dd, hh, mm, ss); 

var myDate = new Date(yyyy, mm, dd); 

var myDate = new Date("monthName dd, yyyy hh:mm:ss"); 

var myDate = new Date("monthName dd, yyyy"); 

var myDate = new Date(epochMilliseconds);

2.获取时间的某部份 

var myDate = new Date(); 

myDate.getYear(); //获取当前年份(2位) 

myDate.getFullYear(); //获取完整的年份(4位,1970-????) 

myDate.getMonth(); //获取当前月份(0-11,0代表1月) 

myDate.getDate(); //获取当前日(1-31) 

myDate.getDay(); //获取当前星期X(0-6,0代表星期天) 

myDate.getTime(); //获取当前时间(从1970.1.1开始的毫秒数) 

myDate.getHours(); //获取当前小时数(0-23) 

myDate.getMinutes(); //获取当前分钟数(0-59) 

myDate.getSeconds(); //获取当前秒数(0-59) 

myDate.getMilliseconds(); //获取当前毫秒数(0-999) 

myDate.toLocaleDateString(); //获取当前日期 

myDate.toLocaleTimeString(); //获取当前时间 

myDate.toLocaleString( ); //获取日期与时间

3.计算之前或未来的时间 

var myDate = new Date(); 

myDate.setDate(myDate.getDate() + 10); //当前时间加10天 

//类似的方法都基本相同,以set开头,具体参考第2点

4.计算两个日期的偏移量 

var i = daysBetween(beginDate,endDate); //返回天数 

var i = beginDate.getTimezoneOffset(endDate); //返回分钟数

5.检查有效日期 

//checkDate() 只允许"mm-dd-yyyy"或"mm/dd/yyyy"两种格式的日期 

if( checkDate("2006-01-01") ){ }

//正则表达式(自己写的检查 yyyy-mm-dd, yy-mm-dd, yyyy/mm/dd, yy/mm/dd 四种) 

var r = /^(\d{2}|\d{4})[\/-]\d{1,2}[\/-]\d{1,2}$/; 

if( r.test( myString ) ){ }

//-----------------------------------------------------------------------

·数组(Array) 

1.声明 

var arr = new Array(); //声明一个空数组 

var arr = new Array(10); //声明一个10个长度的数组 

var arr = new Array("Alice", "Fred", "Jean"); //用值初始化数组 

var arr = ["Alice", "Fred", "Jean"]; //用值初始化数组 

var arr = [["A","B","C"][1,2,3]]; //声明一个二(多)维数组

2.数组的访问 

arr[0] = "123"; //赋值 

var str = arr[0]; //获取 

arr[0][0] = "123"; //多维数组赋值

3.数组与字符串间的转换 

var arr = ["A","B","C","D"]; //声明

//数组按分隔符转换成字符串 

var str = arr.join("|"); //结果: "A|B|C|D"

//字符串切割成数组 

arr = str.split("|");

4.遍历数组 

for( var i=0; i

5.排序 

var arr = [12,15,8,9]; 

arr.sort(); //结果: 8 9 12 15

6.组合与分解数组 

var arr1 = ["A","B","C","D"]; 

var arr2 = ["1","2","3","4"];

//奖两个数组组合成一个新的数组 

var arr = arr1.concat(arr2); //结果: ["A","B","C","D","1","2","3","4"]

//将一个数组切成两个数组(参数1:起始索引,参数2:切割长度) 

var arr3 = arr.splice(1,3); //结果: arr3:["B","C","D"] arr["A","1","2","3","4"]

//将一个数组切成两个数组,并在原数组补新值 

var arr4 = arr.splice(1,3,"AA"); //结果: arr4:["B","C","D"] arr["A","AA","1","2","3","4"]

//-----------------------------------------------------------------------

·自定义对象 

1.声明: 

function myUser(uid,pwd){ 

this.uid = uid; 

this.pwd = pwd || "000000"; //默认值 

this.show = showInfo; //方法 

}

//下面的函数不是自定义对象,是自定义对象的方法.继续看下去就明白了 

function showInfo(){ 

alert("用户名:" + this.uid + ",密码:" + this.pwd) 

}

2.实例化: 

var user = new myUser("user","123456"); 

var user = {uid:"user",pwd:"123456"};

3.获取与设置 

alert("用户名是:" + user.uid); //get 

user.uid = "newuser"; //set 

user.show(); //调用show()方法

//-----------------------------------------------------------------------

·变量 函数 流程控制 

1.变量 

var i = 1; 

var i = 1, str = "hello";

2.函数 

function funName(){ 

//do something. 

function funName(param1[,paramX]){ 

//do something. 

}

3.嵌套函数 

//某种情况,你需要创建一个函数本身所独有的函数. 

function myFunction(){ 

//do something. 

privateFunction(); 

function privateFunction(){ 

//do something. 

}

4.匿名函数 

var tmp = function(){ alert("only test."); } 

tmp();

5.延迟函数调用 

var tId = setTimeout("myFun()",1000); //延迟1000毫秒后再调用myFun()函数 

fucntion myFun(){ 

//do something 

clearTimeout(tId); //销毁对象 

}

6.流程控制 

if( condition ){ } 

if( condition ){ } else{ } 

if( condition ){ } else if( condition ){ } else{ }

switch( expression ){ 

case valA : statement; break; 

case valB : statement; break; 

default : statement; break; 

}

7.异常捕获 

try{ expression } catch(e){ } finally{ }

//不处理任何异常 

window.onerror = doNothing; 

function doNothing(){ return true; }

//异常类可用的属性 

description : 异常描述(IE,NN) 

fileName : 异常页面URI(NN) 

lineNumber : 异常行数(NN) 

message : 异常描述(IE,NN) 

name : 错误类型(IE,NN) 

number : 错误代码(IE)

//错误信息(兼容所有浏览器) 

try{ } 

catch(e){ 

var msg = (e.message) ? e.message : e.description; 

alert(msg); 

}

8.加快脚本的执行速度 

-避免使用 eval() 函数 

-避免使用 with 关键字 

-将重复的表达式赋值精简到最小 

-在较大的对象中使用索引来查找数组 

-减少 document.write() 的使用

//-----------------------------------------------------------------------

·浏览器特征( navigator ) 

1.浏览器名称 

//IE : "Microsoft Internet Explorer" 

//NS : "Netscape" 

var browserName = navigator.appName;

2.浏览器版本 

bar browserVersion = navigator.appVersion;

3.客户端操作系统 

var isWin = ( navigator.userAgent.indexOf("Win") != -1 ); 

var isMac = ( navigator.userAgent.indexOf("Mac") != -1 ); 

var isUnix = ( navigator.userAgent.indexOf("X11") != -1 );

4.判断是否支持某对象,方法,属性 

//当一个对象,方法,属性未定义时会返回undefined或null等,这些特殊值都是false 

if( document.images ){ } 

if( document.getElementById ){ }

5.检查浏览器当前语言 

if( navigator.userLanguage ){ var l = navigator.userLanguage.toUpperCase(); }

6.检查浏览器是否支持Cookies 

if( navigator.cookieEnabled ){ }

//-----------------------------------------------------------------------

·控制浏览器窗口( window ) 

1.设置浏览器的大小 

window.resizeTo(800, 600); //将浏览器调整到800X600大小 

window.resizeBy(50, -10); //在原有大小上改变增大或减小窗口大小

2.调整浏览器的位置 

window.moveTo(10, 20); //将浏览器的位置定位到X:10 Y:20 

window.moveBy(0, 10); //在原有位置上移动位置(偏移量)

3.创建一个新的窗口 

var win = window.open("about.htm","winName","height=300,width=400");

//参数 

alwaysLowered //始终在其它浏览器窗口的后面(NN) 

alwaysRaised //始终在其它浏览器窗口的前面(NN) 

channelMode //是否为导航模式(IE) 

copyhistory //复制历史记录至新开的窗口(NN) 

dependent //新窗口随打开它的主窗口关闭而关闭(NN) 

fullscreen //全屏模式(所有相关的工具栏都没有)(IE) 

location //是否显示地址栏(NN,IE) 

menubar //是否显示菜单栏(NN,IE) 

scrollbars //是否显示滚动条(NN,IE) 

status //是否显示状态栏(NN,IE) 

toolbar //是否显示工具栏(NN,IE) 

directories //是否显示链接栏(NN,IE) 

titlebar //是否显示标题栏(NN) 

hotkeys //显示菜单快捷键(NN) 

innerHeight //内容区域的高度(NN) 

innerWidth //内容区域的宽度(NN) 

resizable //是否可以调整大小(NN,IE) 

top //窗口距离桌面上边界的大小(NN,IE) 

left //窗口距离桌面左边界的大小(NN,IE) 

height //窗口高度(NN,IE) 

width //浏览器的宽度

4.与新窗口通讯 

win.focus(); //让新窗口获得焦点 

win.document.write("abc"); //在新窗口上操作 

win.document.close(); //结束流操作 

opener.close();

5.模式窗口 

window.showModalDialog("test.htm",dialogArgs,"param"); //传递对象 

window.showModelessDialog("test.htm",myFunction,"param"); //传递函数 

window.dialogArguments //对话框访问父窗口传递过来的对象 

window.returnValue //父窗口获取对话框返回的值

//参数 

center //窗口居中屏幕 

dialogHeight //窗口高度 

dialogWidth //窗口宽度 

dialogTop //窗口距离屏幕的上边距 

dialogLeft //窗口距离屏幕的左边距 

edge //边框风格(raised|sunken) 

help //显示帮助按钮 

resizable //是否可以改变窗口大小 

status //是否显示状态栏

//例子 


function openDialog(myForm) { 

var result = window.showModalDialog("new.html",myForm,"center"); 





//另一个页面new.html 


window.dialogArguments.btnChk.enabled = false; //将父窗口中的按钮设置为不可用 

//do something to check the Id. 

window.write("用户ID: " + window.dialogArguments.txtId.value + " 可使用!"); //获取文本框的值 

//-----------------------------------------------------------------------

·管理框架网页( frames ) 

1.创建一个框架架构网页 


2.访问框架网页 

window.frames[i] 

window.frames["frameName"] 

window.frameName

window.frames["frameName"].frames["frameName2"] 

parent.frames["frameName"] 

top.frames["frameName"]

3.将某一页面定向到某框架 

location = "new.html"; 

parent.frameName.location.href = "new.html"; 

top.frameName.location = "new.html";

4.强制不让其它框架引用某页面 

if (top != self) { 

top.location.href = location.href; 

}

5.更改框架的大小 

document.framesetName.rows = "50,*"; 

document.framesetName.cols = "50,*";

6.动态创建框架网页 

var frag = document.createDocumentFragment( ); 

var newFrame= document.createElement("frame"); 

newFrame.id = "header"; 

newFrame.name = "header"; 

newFrame.src="header.html" 

frag.appendChild(newFrame); 

newFrame = document.createElement("frame"); 

newFrame.id = "main"; 

newFrame.name = "main"; 

newFrame.src="main.html" 

frag.appendChild(newFrame); 

document.getElementById("masterFrameset").rows = "50,*";



事件,事件类型,

JS事件之事件类型[焦点事件

焦点事件会在页面获得或失去焦点时触发。利用这些事件并与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪,有以下6信焦点事件:

blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它;

DOMFocusIn:在元素获得焦点时触发。这个事件与HTML事件focus等价,但它冒泡,只有Opera支持这个事件;DOM3级事件废弃了DOMFocusIn,选择了focusin;

DOMFocusOut:在元素失去焦点时触发。这个事件是HTML事件blur的通用版本,只有Opera支持这个事件;DOM3级事件废弃了DOMFocusOut,选择了focusout;

focus:在元素获得焦点时触发。这个事件不会冒泡,所有浏览器都支持它;

focusin:在元素获得焦点时触发。 这个事件与HTML事件focus等价,但它冒泡,支持这个事件的浏览器有IE5+ safari5.1+ Opera11.5+ 和 Chrome;

focusout: 在元素获得失去时触发。 这个事件是HTML事件blur的通用版本,,支持这个事件的浏览器有IE5+ safari5.1+ Opera11.5+ 和 Chrome;

这一类事件中最主要的两个foucs和blur,它们都是JavasScript早期就得到所有浏览器支持的事件。这些事件的最大问题是它们不冒泡。因此,IE的focusin和focusout与Opera的DOMFocusIn和DOMFocusOut才会发生重叠。IE的方式最后被DOM3级事件采纳为标准 方式。

当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:

focusout 在失去焦点的元素上触发;

focusin 在获得焦点的元素上触发;

blur 在失去焦点的元素上触发;

DOMFocusOut 在焦点的元素上触发 ;

focus 在获得焦点的元素上触发;

DOMFoucsIn 在获得焦点的元素上触发;

其中,blur DOMFoucsOut和focusout的事件目标是失去焦点的元素;而focus DOMFocusIn和focusin的事件 目标是获得焦点的元素;

在确定浏览器是否支持这些事件,可以使用如下代码:

varisSupported = document.implementation.hasFeature('FocusEvent','3.0');

即使focus和blur不冒泡,也可以在捕获阶段侦听到它们



事件对象,事件委托

JS 事件绑定、事件监听、事件委托详细介绍


这篇文章主要介绍了JS 事件绑定、事件监听、事件委托详细介绍的相关资料,需要的朋友可以参考下

在JavaScript的学习中,我们经常会遇到JavaScript的事件机制,例如,事件绑定、事件监听、事件委托(事件代理)等。这些名词是什么意思呢,有什么作用呢?

事件绑定

要想让 JavaScript 对用户的操作作出响应,首先要对 DOM 元素绑定事件处理函数。所谓事件处理函数,就是处理用户操作的函数,不同的操作对应不同的名称。

在JavaScript中,有三种常用的绑定事件的方法:

在DOM元素中直接绑定;

在JavaScript代码中绑定;

绑定事件监听函数。

在DOM中直接绑定事件

我们可以在DOM元素上绑定onclick、onmouseover、onmouseout、onmousedown、onmouseup、ondblclick、onkeydown、onkeypress、onkeyup等。好多不一一列出了。如果想知道更多事件类型请查看, DOM事件 。


<input type="button"value="click me"onclick="hello()">


<script>

functionhello(){

 alert("hello world!");

}

</script>

在JavaScript代码中绑定事件

在JavaScript代码中(即 script 标签内)绑定事件可以使JavaScript代码与HTML标签分离,文档结构清晰,便于管理和开发。


<input type="button"value="click me"id="btn">


<script>

document.getElementById("btn").onclick = function(){

 alert("hello world!");

}

</script>

使用事件监听绑定事件

绑定事件的另一种方法是用 addEventListener() 或 attachEvent() 来绑定事件监听函数。下面详细介绍,事件监听。

事件监听

关于事件监听,W3C规范中定义了3个事件阶段,依次是捕获阶段、目标阶段、冒泡阶段。

起初Netscape制定了JavaScript的一套事件驱动机制(即事件捕获)。随即IE也推出了自己的一套事件驱动机制(即事件冒泡)。最后W3C规范了两种事件机制,分为捕获阶段、目标阶段、冒泡阶段。IE8以前IE一直坚持自己的事件机制(前端人员一直头痛的兼容性问题),IE9以后IE也支持了W3C规范。

W3C规范

语法:

element.addEventListener(event, function, useCapture)

event : (必需)事件名,支持所有 DOM事件 。

function:(必需)指定要事件触发时执行的函数。

useCapture:(可选)指定事件是否在捕获或冒泡阶段执行。true,捕获。false,冒泡。默认false。

注:IE8以下不支持。


<input type="button"value="click me"id="btn1">


<script>

document.getElementById("btn1").addEventListener("click",hello);

functionhello(){

 alert("hello world!");

}

</script>

IE标准

语法:

element.attachEvent(event, function)

event:(必需)事件类型。需加“on“,例如:onclick。

function:(必需)指定要事件触发时执行的函数。


<input type="button"value="click me"id="btn2">


<script>

document.getElementById("btn2").attachEvent("onclick",hello);

functionhello(){

 alert("hello world!");

}

</script>

事件监听的优点

1、可以绑定多个事件。


<input type="button"value="click me"id="btn3">


<script>

varbtn3 = document.getElementById("btn3");

btn3.onclick = function(){

 alert("hello 1"); //不执行

}

btn3.onclick = function(){

 alert("hello 2"); //执行

}

</script>

常规的事件绑定只执行最后绑定的事件。


<input type="button"value="click me"id="btn4">


<script>

varbtn4 = document.getElementById("btn4");

btn4.addEventListener("click",hello1);

btn4.addEventListener("click",hello2);


functionhello1(){

 alert("hello 1");

}

functionhello2(){

 alert("hello 2");

}

</script>

两个事件都执行了。

2、可以解除相应的绑定


<input type="button"value="click me"id="btn5">


<script>

varbtn5 = document.getElementById("btn5");

btn5.addEventListener("click",hello1);//执行了

btn5.addEventListener("click",hello2);//不执行

btn5.removeEventListener("click",hello2);


functionhello1(){

 alert("hello 1");

}

functionhello2(){

 alert("hello 2");

}

</script>

封装事件监听


<input type="button"value="click me"id="btn5">


//绑定监听事件

functionaddEventHandler(target,type,fn){

 if(target.addEventListener){

 target.addEventListener(type,fn);

 }else{

 target.attachEvent("on"+type,fn);

 }

}


//移除监听事件

functionremoveEventHandler(target,type,fn){

 if(target.removeEventListener){

 target.removeEventListener(type,fn);

 }else{

 target.detachEvent("on"+type,fn);

 }

}


//测试

varbtn5 = document.getElementById("btn5");

addEventHandler(btn5,"click",hello1);//添加事件hello1

addEventHandler(btn5,"click",hello2);//添加事件hello2

removeEventHandler(btn5,"click",hello1);//移除事件hello1

事件委托

事件委托就是利用冒泡的原理,把事件加到父元素或祖先元素上,触发执行效果。


<input type="button"value="click me"id="btn6">


varbtn6 = document.getElementById("btn6");

document.onclick = function(event){

 event = event || window.event;

 vartarget = event.target || event.srcElement;

 if(target == btn6){

 alert(btn5.value);

 }

}

上面只是个例子,代码尽可能的简化了。在实际的代码中 我们可能用到jQuery的live()、delegate()、bind()、on()等。

事件委托优点

1、提高JavaScript性能。事件委托可以显著的提高事件的处理速度,减少内存的占用。 实例分析JavaScript中的事件委托和事件绑定 ,这篇文章写得还不错。

传统写法


<ul id="list">

 <li id="item1">item1</li>

 <li id="item2">item2</li>

 <li id="item3">item3</li>

</ul>


<script>

varitem1 = document.getElementById("item1");

varitem2 = document.getElementById("item2");

varitem3 = document.getElementById("item3");


item1.onclick = function(){

 alert("hello item1");

}

item2.onclick = function(){

 alert("hello item2");

}

item3.onclick = function(){

 alert("hello item3");

}

</script>

事件委托


<ul id="list">

 <li id="item1">item1</li>

 <li id="item2">item2</li>

 <li id="item3">item3</li>

</ul>


<script>

varitem1 = document.getElementById("item1");

varitem2 = document.getElementById("item2");

varitem3 = document.getElementById("item3");


document.addEventListener("click",function(event){

 vartarget = event.target;

 if(target == item1){

 alert("hello item1");

 }elseif(target == item2){

 alert("hello item2");

 }elseif(target == item3){

 alert("hello item3");

 }

})

</script>

2、动态的添加DOM元素,不需要因为元素的改动而修改事件绑定。

传统写法


<ul id="list">

 <li id="item1">item1</li>

 <li id="item2">item2</li>

 <li id="item3">item3</li>

</ul>


<script>

varlist = document.getElementById("list");


varitem = list.getElementsByTagName("li");

for(vari=0;i<item.length;i++){

 (function(i){

 item[i].onclick = function(){

 alert(item[i].innerHTML);

 }

 })(i)

}


varnode=document.createElement("li");

vartextnode=document.createTextNode("item4");

node.appendChild(textnode);

list.appendChild(node);


</script>

点击item1到item3都有事件响应,但是点击item4时,没有事件响应。说明传统的事件绑定无法对动态添加的元素而动态的添加事件。

事件委托


<ul id="list">

 <li id="item1">item1</li>

 <li id="item2">item2</li>

 <li id="item3">item3</li>

</ul>


<script>

varlist = document.getElementById("list");


document.addEventListener("click",function(event){

 vartarget = event.target;


 if(target.nodeName == "LI"){

 alert(target.innerHTML);

 }

})


varnode=document.createElement("li");

vartextnode=document.createTextNode("item4");

node.appendChild(textnode);

list.appendChild(node);


</script>

当点击item4时,item4有事件响应。说明事件委托可以为新添加的DOM元素动态的添加事件。



事件对象,事件委托

原生js事件绑定和事件委托

原创我家有条大大狗 最后发布于2018-09-17 15:03:00 阅读数 3217  收藏

展开

最近常在移动端开发,由于不是大型站点,不需要使用vue等库,也不需要引用jquery和zepto等。

写得最多得就是各种元素选择器和事件绑定,操作下来也是有点烦人。这时候怀念起jquery的美好来了,但是仅为了这个引用这么大个库,实在时下不了手,思考了一下,直接在html构造函数上拓展支持了。

按照习惯来走,一般我们会喜欢在选择的元素上直接 on + 事件 ,加上相应的逻辑函数完成一个事件绑定的。

这里要说明一下,js的事件绑定是特殊的,不同于老旧版本的事件绑定

element.onclick = function () {}

1

这种方式绑定的事件,后面有其他相同绑定事件,会覆盖前面的逻辑代码,因此我们会使用 addEventListener 实现绑定,按照绑定事件的顺序执行所有操作。

element.addEventListener('click', function() {

    console.log(1)

}, false)

element.addEventListener('click', function() {

    console.log(2)

}, false)

>> 1

>> 2


再深一步思考一下,什么是 事件委托 ,意义是什么。

事件委托,实际是把目标元素的事件绑定到其他元素上,借助触发事件。举个例子,我需要做个div容器展示文章,容器有个按钮,需要点击放大字体。这里你可以考虑把事件绑定到按钮上,也可以绑定到div上,两者实现效果并无不同。

但是要记得一点,所有的元素查找和事件绑定都是需要消耗性能和内存的,而复杂页面上的操作区域可能多达数十上百,每一个都独立绑定事件,页面在低端设备上也会出现执行卡顿的情况,影响体验。此外,常见需求里是有未来事件绑定的,你无法为尚未存在的元素绑定事件。

原生js实现委托一般是从event属性中获取当前点击位置的元素,并对元素进行逻辑代码。因此,可以考虑将两者做到一起。

/**

* 事件绑定和事件委托

* 类似jQuery的on/off/one的用法

* @author mo

* @param eventName 事件名称

* @param selector 委托的子元素,可以为空

* @param callback 事件逻辑代码

* @description 在选择的元素上直接用on/off/one就好了,同时存在自身绑定事件和委托事件的,如需解绑,要分别解绑,仅off选择元素的事件是不会解绑代理的事件的

* @example

*

* var test = document.querySelector('.test')

*

* test.on('click', function () {

*    // TODO

* })

*

* test.one('click', function () {

*    // TODO

* })

*

* test.on('click', '.childElement', function () {

*    // TODO

* })

*

* test.off('click')

*

* test.off('click', '.childElement')

*

*/

var p_n_space = /(^\s*)|(\s*$)/g, // 前后空格正则

    bind_list = {} // 绑定事件列表

HTMLElement.prototype.on = function(eventName, selector, callback) {

    // 预处理参数

    if (!eventName || !selector) {

        console.log('Arguments is require!')

        return false

    } else {

        eventName = eventName.toLowerCase()

        if (typeof selector == 'function') {

            callback = selector

            selector = null

        }

    }

    // 事件绑定逻辑

    if (!bind_list.eventName) bind_list.eventName = []

    bind_list.eventName.push({

        selector: selector,

        fn: function(event) {

            var ev = event || window.event,

                target = ev.target || ev.srcElement,

                targets, sSets, i = j = 0

            if (!selector) {

                // 当前元素绑定

                callback.apply(this, [ev])

                if (this.once) {

                    delete this.once

                    this.off(eventName, callback)

                }

            } else {

                targets = selector.split(',')

                for (; i < targets.length; i++) {

                    // 删除前后空格

                    targets[i] = targets[i].replace(p_n_space, '')

                    // 遍历集合

                    sSets = this.querySelectorAll(targets[i])

                    // 如果集合为空则说明不存在这种委托元素,不做处理

                    if (sSets.length) {

                        // 关系拆分

                        // targets[i] = targets[i].split(/\s+/g).reverse()

                        // 事件委托

                        for (var j = 0; j < sSets.length; j++) {

                            if (target === sSets[j]) {

                                callback.apply(target, [ev])

                                if (this.once) {

                                    delete this.once

                                    this.off(eventName, selector, callback)

                                }

                                break;

                            }

                        }

                    } else {

                        return false

                    }

                }

            }

        }

    })

    // 所有事件,包括委托事件都绑定到目标元素本身

    if (this.addEventListener) {

        this.addEventListener(eventName, bind_list.eventName[bind_list.eventName.length - 1].fn, false);

    } else if (this.attachEvent) {

        this.attachEvent("on" + eventName, bind_list.eventName[bind_list.eventName.length - 1].fn);

    }

}

// 移除全部事件

HTMLElement.prototype.off = function(eventName, selector) {

    if (!selector) selector = null

    // 预处理参数

    if (!eventName) {

        console.log('Arguments is require!')

        return false

    } else {

        eventName = eventName.toLowerCase()

    }

    // 遍历已添加列表

    for (var k = 0; k < bind_list.eventName.length; k++) {

        // 仅移除相关的事件,分目标元素和委托元素绑定的事件

        if (bind_list.eventName[k] && selector == bind_list.eventName[k].selector) {

            if (this.removeEventListener) {

                this.removeEventListener(eventName, bind_list.eventName[k].fn, false);

            } else if (this.detachEvent) {

                this.detachEvent("on" + eventName, bind_list.eventName[k].fn);

            }

        }

        // 移除

        bind_list.eventName[k] = null

    }

}

// 一次性事件

HTMLElement.prototype.one = function(eventName, selector, callback) {

    this.once = true

    this.on(eventName, selector, callback)

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容