在检查组内小伙伴提交的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元素本身。

用js的eval函数模拟Web API中的onclick事件的更多相关文章

  1. JS的eval函数解密反混淆

    https://www.hhtjim.com/js-decryption-de-obfuscate-eval-function.html JS的eval函数解密反混淆

  2. Java 实现 JS的eval函数

    JS的eval 函数, 给个表达式做参数, 返回表达式的值. Java的脚本引擎可以实现这个功能. 例子:   拼接一个字符串 \uxxxx, Unicode的十六进制编码, 然后把它打印出来. 即输 ...

  3. ASP.NET Web API中的JSON和XML序列化

    ASP.NET Web API中的JSON和XML序列化 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok ...

  4. 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务

    在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...

  5. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  6. Web APi 2.0优点和特点?在Web APi中如何启动Session状态?

    前言 曾几何时,微软基于Web服务技术给出最流行的基于XML且以扩展名为.asmx结尾的Web Service,此服务在.NET Framework中风靡一时同时也被.NET业界同仁所青睐,几年后在此 ...

  7. Asp.Net Web Api中使用Swagger

    关于swagger 设计是API开发的基础.Swagger使API设计变得轻而易举,为开发人员.架构师和产品所有者提供了易于使用的工具. 官方网址:https://swagger.io/solutio ...

  8. Asp.Net MVC Web API 中Swagger教程,使用Swagger创建Web API帮助文件

    什么是Swagger? Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法 ...

  9. 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理

    在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在 ...

随机推荐

  1. udhcp源码详解(二)--转

    定义的数据结构对于C程序的重要性,不言而喻.面向对象设计的程序是一个个对象的集合,而面向过程语言设计的程序则是数据结构与算法的集合. 下面来分析的是dhcp server中的定义结构体: 1).在pa ...

  2. WAMP的端口修改

    wamp集成了开源的利器mysql+apache+php,真的是有越来越火的趋势了,可是有些人,安装php的集成开发环境WAMP的时候,出现端口被占用了,无法连接服务器的时候, 这时,如果要修改WAM ...

  3. 【视频】零基础学Android开发:蓝牙聊天室APP(三)

    零基础学Android开发:蓝牙聊天室APP第三讲 3.1 ImageView.ImageButton控件具体解释 3.2 GridView控件具体解释 3.3 SimpleAdapter适配器具体解 ...

  4. hdu 2059 龟兔赛跑 (dp)

    /* 把起点和终点比作加油站,那总共同拥有n+2个加油站了, 每次都求出从第0个到第j个加油站(j<i)分别在加满油的情况下到第i个加油站的最短时间dp[i], 终于的dp[n+1]就是最优解了 ...

  5. c中的变量

    1 变量类型 1.1 static global or static .data/.bss 1.2 automic stack,its relevant to os kernel and compil ...

  6. Statement 与 PreparedStatement 区别

    Statement由方法createStatement()创建,该对象用于发送简单的SQL语句 PreparedStatement由方法prepareStatement()创建,该对象用于发送带有一个 ...

  7. 高负载linux调优

    调整Linux内核参数: # vi /etc/sysctl.conf# tells the Kernel it's ok if services bind to non-existant IP ADD ...

  8. HttpWebRequest以及HttpWebResponse

    上次介绍了用WebClient的方式提交POST请求,这次,我继续来介绍用其它一种方式 HttpWebRequest以及HttpWebResponse 自认为与上次介绍的WebClient最大的不同之 ...

  9. C# ListView 列宽调整 刷新

    /*********************************************************************** * C# ListView 列宽调整 刷新 * 说明: ...

  10. AutoIT: 对数据库的访问,数据提取操作

    #include<array.au3> $conn= ObjCreate("ADODB.Connection") $RS= ObjCreate("ADODB. ...