用js的eval函数模拟Web API中的onclick事件
2024-08-24 22:48:31
在检查组内小伙伴提交的tabToggler插件的js代码时,发现了onclick的如下用法:
el.onclick = function(){
//按钮样式切换
for(var i=0;i<obj.btns.length;i++){
obj.btns[i].classList.remove("current");
}
this.classList.add("current");
//内容显示切换
for(var j = 0;j<obj.divs.length;j++){
obj.divs[j].style.display = 'none';
}
obj.divs[this.index].style.display = 'block';
console.log(this.index);
}
显然这个this指向事件源对象—eventTarget,最近一直在钻研闭包和this的我,看到这里觉得非常的怪,为什么这里的this可以指向eventTarget呢,而且在书写在html标签里的事件处理函数也可以在非闭包作用域下直接访问this(指向target),如下代码:
<div id="tab1" myonclick = "console.log(this.id);console.log(this)">Tab1</div>
打印结果:
这到底怎么实现的?按照需求一步一步分析就可以了,其实onclick的事件处理函数包括了两部分:
Part 1: 来自html标签内的onclick属性内的js代码;
Part 2: 来自己js脚本里的onclick方法
需求如下:
Part 1 里的onclick字符串可以被click事件执行,而且this作用域是eventTarget
问题:js里有什么机制能执行字符串形式的js代码?如何让代码作用域指向eventTarget?
答案:eval,且eval执行本身就有作用域的概念,让代码的作用域指向eventTarget就行了。
Part 2 里的onclick方法被click事件执行内部逻辑,而且this作用域是eventTarget;
综上,我们可以用eval和指定作用域的办法来扩展一个myonclick时间了,具体实现如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="tab1" myonclick = "console.log(this.id);console.log(this)">Tab1</div>
<div id="tab2">Tab2</div>
</body>
<script>
//扩展HTMLDivElement原型
HTMLElement.prototype.clickHandle = function(){
//1.检查dom标签里有myonclick属性
var _evalClickStr = this.getAttribute( "myonclick" );
//2.检查dom有无指定myonclick方法
if( !!this.myonclick && typeof this.myonclick === "function" ){
var _clickHandle = this.myonclick;
}
var nativeEventBind = this.addEventListener || this.attachEvent;
if( !!nativeEventBind ){
nativeEventBind( 'click',(function( e ){
//执行eavl代码串
eval( _evalClickStr );
//执行myonclick事件处理函数
_clickHandle.apply( this,e );
}).bind(this) );
}
else return;
} var tab1 = document.getElementById( "tab1" );
tab1.myonclick = function(){
console.log( this.id );
};
tab1.clickHandle(); </script>
</html>
核心设计要点:扩展了HTMLElement.prototype对象,在clickHandle方法里,指定了两部分onclick代码的执行上下文为HTMLElement元素本身。
最新文章
- Knockout.js随手记(1)
- 手势-webview与scrollView重复手势处理
- 数据库测试DbUnit
- 7 Types of Regression Techniques you should know!
- 基于jQuery的宽屏可左右切换的焦点图插件
- IPhone 设备状态、闪光灯状态
- 关于新feature对应的增加一个新的测试单子(QA)和文档单子(Doucmentation)的步骤
- linux 简单命令
- security Export/import
- unix c 10
- 体系结构复习2——指令级并行(分支预測和VLIW)
- JS 多个参数的传递
- redhat6.4配置yum
- xtream 示例介绍
- Jmeter-----【mac电脑】配置web浏览器的代理抓取请求
- Apache Hadoop 2.9.2 完全分布式部署
- zookeeper在windows及linux(含多节点)环境下安装及其命令使用
- 悲观并发 乐观并发 Entity Framework Core中的并发处理
- Linux:Red Hat系统的安装
- Confluence 6 用户目录图例 - 使用 LDAP 授权的内部目录
热门文章
- Kemans算法及其Python 实现
- Random-随机生成电话号
- 加密壳之ACProtect之OEP的处理
- Android 怎样在java/native层改动一个文件的权限(mode)与用户(owner)?
- 树莓派 mongodb 安装&;报错处理
- [IT学习]GIT 学习
- 卸载ubuntu自带openJDK,更改成自己的JDK版本
- Lightoj 1017 - Brush (III)
- uboot中关于LCD的代码分析【转】
- YTU 2960: 改错题--小鼠标,你要干什吗?