深入解析JavaScript框架Backbone.js中的事件机制

事件模型及其原理
Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力

var Events = Backbone.Events = { .. }

对象通过listenTo侦听其他对象,通过trigger触发事件。可以脱离Backbone的MVC,在自定义的对象上使用事件

var model = _.extend({},Backbone.Events);
var view = _.extend({},Backbone.Events);
view.listenTo(model,'custom_event',function(){ alert('catch the event') });
model.trigger('custom_event');

执行结果:

Backbone的Model和View等核心类,都是继承自Backbone.Events的。例如Backbone.Model:

var Events = Backbone.Events = { .. }

var Model = Backbone.Model = function(attributes, options) {
 ...
};

_.extend(Model.prototype, Events, { ... })

从原理上讲,事件是这么工作的:

被侦听的对象维护一个事件数组_event,其他对象在调用listenTo时,会将事件名与回调维护到队列中:

一个事件名可以对应多个回调,对于被侦听者而言,只知道回调的存在,并不知道具体是哪个对象在侦听它。当被侦听者调用trigger(name)时,会遍历_event,选择同名的事件,并将其下面所有的回调都执行一遍。

需要额外注意的是,Backbone的listenTo实现,除了使被侦听者维护对侦听者的引用外,还使侦听者也维护了被侦听者。这是为了在恰当的时候,侦听者可以单方面中断侦听。因此,虽然是循环引用,但是使用Backbone的合适的方法可以很好的维护,不会有问题,在后面的内存泄露部分将看到。

另外,有时只希望事件在绑定后,当回调发生后,就接触绑定。这在一些对公共模块的引用时很有用。listenToOnce可以做到这一点

与服务器同步数据
backbone默认实现了一套与RESTful风格的服务端同步模型的机制,这套机制不仅可以减轻开发人员的工作量,而且可以使模型变得更为健壮(在各种异常下仍能保持数据一致性)。不过,要真正发挥这个功效,一个与之匹配的服务端实现是很重要的。为了说明问题,假设服务端有如下REST风格的接口:

  • GET /resources 获取资源列表
  • POST /resources 创建一个资源,返回资源的全部或部分字段
  • GET /resources/{id} 获取某个id的资源详情,返回资源的全部或部分字段
  • DELETE /resources/{id} 删除某个资源
  • PUT /resources/{id} 更新某个资源的全部字段,返回资源的全部或部分字段
  • PATCH /resources/{id} 更新某个资源的部分字段,返回资源的全部或部分字段

backbone会使用到上面这些HTTP方法的地方主要有以下几个:

  • Model.save() 逻辑上,根据当前这个model的是否具有id来判断应该使用POST还是PUT,如果model没有id,表示是新的模型,将使用POST,将模型的字段全部提交到/resources;如果model具有id,表示是已经存在的模型,将使用PUT,将模型的全部字段提交到/resources/{id}。当传入options包含patch:true的时候,save会产生PATCH。
  • Model.destroy() 会产生DELETE,目标url为/resources/{id},如果当前model不包含id时,不会与服务端同步,因为此时backbone认为model在服务端尚不存在,不需要删除
  • Model.fetch() 会产生GET,目标url为/resources/{id},并将获得的属性更新model。
  • Collection.fetch() 会产生GET,目标url为/resources,并对返回的数组中的每个对象,自动实例化model
  • Collection.create() 实际将调用Model.save

options参数存在于上面任何一个方法的参数列表中,通过options可以修改backbone和ajax请求的一些行为,可以使用的options包括:

  • wait: 可以指定是否等待服务端的返回结果再更新model。默认情况下不等待
  • url: 可以覆盖掉backbone默认使用的url格式
  • attrs: 可以指定保存到服务端的字段有哪些,配合options.patch可以产生PATCH对模型进行部分更新
  • patch: 指定使用部分更新的REST接口
  • data: 会被直接传递给jquery的ajax中的data,能够覆盖backbone所有的对上传的数据控制的行为
  • 其他: options中的任何参数都将直接传递给jquery的ajax,作为其options

backbone通过Model的urlRoot属性或者是Collection的url属性得知具体的服务端接口地址,以便发起ajax。在Model的url默认实现中,Model除了会考察urlRoot,第二选择会是Model所在Collection的url,所有有时只需要在Collection里面书写url就可以了。

Backbone会根据与服务端要进行什么类型的操作,决定是否要添加id在url后面,以下代码是Model的默认url实现:

url: function () {
 var base =
 _.result(this, 'urlRoot') ||
 _.result(this.collection, 'url') ||
 urlError();
 if (this.isNew()) return base;
 return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
},

其中的正则式/([^\/])$/是个很巧妙的处理,它解决了url最后是否包含'/'的不确定性。

这个正则匹配的是行末的非/字符,这样,像/resources这样的目标会匹配s,然后replace中使用分组编号$1捕获了s,将s替换为s/,这样就自动加上了缺失的/;而当/resources/这样目标却无法匹配到结果,也就不需要替换了。
Model和Collection的关系
在backbone中,即便一类的模型实例的确是在一个集合里面,也并没有强制要求使用集合类。但是使用集合有一些额外的好处,这些好处包括:

url继承
Model属于Collection后,可以继承Collection的url属性。Collection沿用了underscore90%的集合和数组操作,使得集合操作极其方便:

// Underscore methods that we want to implement on the Collection.
// 90% of the core usefulness of Backbone Collections is actually implemented
// right here:
var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
'lastIndexOf', 'isEmpty', 'chain', 'sample'];
Backbone巧妙的使用下面的代码将这些方法附加到Collection中:

// Mix in each Underscore method as a proxy to `Collection#models`.
_.each(methods, function (method) {
 Collection.prototype[method] = function () {
 var args = slice.call(arguments); //将参数数组转化成真正的数组
 args.unshift(this.models);  //将Collection真正用来维护集合的数组,作为第一个个参数
 return _[method].apply(_, args); //使用apply调用underscore的方法
 };
});

自动侦听和转发集合中的Model事件
集合能够自动侦听并转发集合中的元素的事件,还有一些事件集合会做相应的特殊处理,这些事件包括:

destroy 侦听到元素的destroy事件后,会自动将元素从集合中移除,并引发remove事件
change:id 侦听到元素的id属性被change后,自动更新内部对model的引用关系
自动模型构造
利用Collection的fetch,可以加载服务端数据集合,与此同时,可以自动创建相关的Model实例,并调用构造方法

元素重复判断
Collection会根据Model的idAttribute指定的唯一键,来判断元素是否重复,默认情况下唯一键是id,可以重写idAttribute来覆盖。当元素重复的时候,可以选择是丢弃重复元素,还是合并两种元素,默认是丢弃的

模型转化
有时从REST接口得到的数据并不能完全满足界面的处理需求,可以通过Model.parse或者Collection.parse方法,在实例化Backbone对象前,对数据进行预处理。大体上,Model.parse用来对返回的单个对象进行属性的处理,而Collection.parse用来对返回的集合进行处理,通常是过滤掉不必要的数据。例如:

//只挑选type=1的book
var Books = Backbone.Collection.extend({
 parse:function(models,options){
 return _.filter(models , function(model){
  return model.type == 1;
 })
 }
})

//为Book对象添加url属性,以便渲染
var Book = Backbone.Model.extend({
 parse: function(model,options){
 return _.extend(model,{ url : '/books/' + model.id });
 }
})

通过Collection的fetch,自动实例化的Model,其parse也会被调用。

模型的默认值
Model可以通过设置defaults属性来设置默认值,这很有用。因为,无论是模型还是集合,fetch数据都是异步的,而往往视图的渲染确实很可能在数据到来前就进行了,如果没有默认值的话,一些使用了模板引擎的视图,在渲染的时候可能会出错。例如underscore自带的视图引擎,由于使用with(){}语法,会因为对象缺乏属性而报错。

视图的el
Backbone的视图对象十分简答,对于开发者而言,仅仅关心一个el属性即可。el属性可以通过五种途径给出,优先级从高到低:

  • 实例化View的时候,传递el
  • 在类中声明el
  • 实例化View的时候传入tagName
  • 在类中声明tagName
  • 以上都没有的情况下使用默认的'div'

究竟如何选择,取决于以下几点:

  • 一般而言,如果模块是公用模块,在类中不提供el,而是让外部在实例化的时候传入,这样可以保持公共的View的独立性,不至于依赖已经存在的DOM元素
  • tagName一般对于自成体系的View有用,比如table中的某行tr,ul中的某个li
  • 有些DOM事件必须在html存在的情况下才能绑定成功,比如blur,对于这种View,只能选择已经存在的html

视图类还有几个属性可以导出,由外部初始化,它们是:

// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];

内存泄漏
事件机制可以很好的带来代码维护的便利,但是由于事件绑定会使对象之间的引用变得复杂和错乱,容易造成内存泄漏。下面的写法就会造成内存泄漏:

var Task = Backbone.Model.extend({})

var TaskView = Backbone.View.extend({
 tagName: 'tr',
 template: _.template('<td><%= id %></td><td><%= summary %></td><td><%= description %></td>'),
 initialize: function(){
 this.listenTo(this.model,'change',this.render);
 },
 render: function(){
 this.$el.html( this.template( this.model.toJSON() ) );
 return this;
 }
})

var TaskCollection = Backbone.Collection.extend({
 url: 'http://api.test.clippererm.com/api/testtasks',
 model: Task,
 comparator: 'summary'
})

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 },
 render: function(){
 var _this = this;

 //简单粗暴的将DOM清空
 //在sort事件触发的render调用时,之前实例化的TaskView对象会泄漏
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

使用下面的测试代码,并结合Chrome的堆内存快照来证明:

var tasks = null;
var tasklist = null;

$(function () {
 // body...
 $('#start').click(function(){
 tasks = new TaskCollection();
 tasklist = new TaskCollectionView({
  collection : tasks,
  el: '#tasklist'
 })

 tasklist.render();
 tasks.fetch();
 })

 $('#refresh').click(function(){
 tasks.fetch({ reset : true });
 })

 $('#sort').click(function(){
 //将侦听sort放在这里,避免第一次加载数据后的自动排序,触发的sort事件,以至于混淆
 tasklist.listenToOnce(tasks,'sort',tasklist.render);
 tasks.sort();
 })
})

点击开始,使用Chrome的'Profile'下的'Take Heap Snapshot'功能,查看当前堆内存情况,使用child类型过滤,可以看到Backbone对象实例一共有10个(1+1+4+4):

之所以用child过滤,因为我们的类继承自Backbone的类型,而继承使用了重写原型的方法,Backbone在继承时,使用的变量名为child,最后,child被返回出来了
点击排序后,再次抓取快照,可以看到实例个数变成了14个,这是因为,在render过程中,又创建了4个新的TaskView,而之前的4个TaskView并没有释放(之所以是4个是因为记录的条数是4)

再次点击排序,再次抓取快照,实例数又增加了4个,变成了18个!

那么,为什么每次排序后,之前的TaskView无法释放呢。因为TaskView的实例都会侦听model,导致model对新创建的TaskView的实例存在引用,所以旧的TaskView无法删除,又创建了新的,导致内存不断上涨。而且由于引用存在于change事件的回调队列里,model每次触发change都会通知旧的TaskView实例,导致执行很多无用的代码。那么如何改进呢?

修改TaskCollectionView:

var TaskCollectionView = Backbone.View.extend({
 initialize: function(){
 this.listenTo(this.collection, 'add',this.addOne);
 this.listenTo(this.collection, 'reset',this.render);
 //初始化一个view数组以跟踪创建的view
 this.views =[]
 },
 addOne: function(task){
 var view = new TaskView({ model : task });
 this.$el.append(view.render().$el);
 //将新创建的view保存起来
 this.views.push(view);
 },
 render: function(){
 var _this = this;

 //遍历views数组,并对每个view调用Backbone的remove
 _.each(this.views,function(view){
  view.remove().off();
 })

 //清空views数组,此时旧的view就变成没有任何被引用的不可达对象了
 //垃圾回收器会回收它们
 this.views =[];
 this.$el.empty();

 this.collection.each(function(model){
  _this.addOne(model);
 })

 return this;
 }

})

Backbone的View有一个remove方法,这个方法除了删除View所关联的DOM对象,还会阻断事件侦听,它通过在listenTo方法时记录下来的那些被侦听对象(上文事件原理中提到),来使这些被侦听的对象删除对自己的引用。在remove内部使用事件基类的stopListening完成这个动作。
上面的代码使用一个views数组来跟踪新创建的TaskView对象,并在render的时候,依次调用这些视图对象的remove,然后清空数组,这样这些TaskView对象就能得到释放。并且,除了调用remove,还调用了off,把视图对象可能的被外部的侦听也断开。

事件驱动模块
自定义事件:自定义事件比较适合多人合作开发,因为我们知道,函数名如果一样的话,那么后面的函数会覆盖前面的,而事件在绑定的情况下是不会被覆盖的。

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4';
 },
 initialization : function(){ //初始化构造函数
  this.on('change',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>

事件绑定
除此之外,我们还可以自定义要绑定的被改变的数据类型:

object.on(event, callback, [context])

绑定一个回调函数到一个对象上, 当事件触发时执行回调函数 :

<script type="text/javascript">
 //自定义事件
 var Mod = backbone.Model.extend({
 defaults : {
  name : 'trigkit4',
  age : 21;
 },
 initialization : function(){ //初始化构造函数
  this.on('change:age',function(){ //绑定change事件,当数据改变时执行此回调函数
  alert(123);
  });
 }
 });

 var model = new Mod;
 model.set('name' ,'backbone');//修改默认的name属性值为backbone,此时数据被改变,弹出123
</script>
listenTo
<script type="text/javascript">
 $(function(){
 var Mod = Backbone.Model.extend({
  defaults : {
  name : 'trigkit4'
  }
 });
 var V = Backbone.View.extend({
  initialize : function(){
  this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
  },
  show : function(model){
  $('body').append('<div>' + model.get('name') + '</div>');
  }
 });

 var m = new Mod;
 var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
 m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了
 });
</script>

istenTo

<script type="text/javascript">
 $(function(){
  var Mod = Backbone.Model.extend({
   defaults : {
    name : 'trigkit4'
   }
  });
  var V = Backbone.View.extend({
   initialize : function(){
    this.listenTo(this.model,'change',this.show);//listenTo比on多了个参数
   },
   show : function(model){
    $('body').append('<div>' + model.get('name') + '</div>');
   }
  });

  var m = new Mod;
  var v = new V({model:m});//model指定创建的模型对象m,即前面的路由,哈希值的对应
  m.set('name','hello');//对模型进行就改时,触发事件,页面也就更新了
 });
</script>

模型集合器
Backbone.Collection
集合是模型的有序组合,我们可以在集合上绑定 "change" 事件,从而当集合中的模型发生变化时获得通知,集合也可以监听 "add" 和 “remove" 事件, 从服务器更新,并能使用 Underscore.js 提供的方法

路由与历史管理

<script type="text/javascript">
  var Workspace = Backbone.Router.extend({
    routes: {
      "help":         "help",
      "search/:query":      "search",
      "search/:query/p:page":"    search"
    },

    help : function(){
      alert(123);
    },

    search : function(query,page){
      alert(345);
    }
  });

  var w = new Workspace;

  Backbone.history.start();//backbone通过hash值找到对应的回调函数
</script>
事件委托
  <script type="text/javascript">
    $(function(){
      var V = Backbone.View.extend({
        el : $('body'),
        //对events进行集体操作
        events : {
          "click input" : "hello",
          "mouseover li" : "world"
        },
        hello : function(){
          alert(1234);
        },
        world : function(){
          alert(123)
        }
      });
      var view = new V;
    });
  </script>
<body>
  <imput type = "button" value = "hwx" />
  <ul>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
    <li>1234</li>
  </ul>
</body>

事件委托 格式:事件 + 空格 + 由谁来触发 : 对应的回调函数

(0)

相关推荐

  • ExtJs事件机制基本代码模型和流程解析

    代码实现的目的:为一个自定义的类的某个属性在使用它时候,触发某个事件. 该程序的效果:点击输入按钮,弹出一个脚本提示输入框让用户输入他的姓名,确定后,用户录入的姓名会显示在页面的姓名文本框中,并且页面标题变成和姓名一致,接着再弹出脚本提示输入框让用户输入性别,录入完毕并点击确定后,用户录入的性别将会显示在页面的性别文本框里. 复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &quo

  • 深入理解JS DOM事件机制

    1.事件流 html 元素触发事件的顺序. 2.事件冒泡IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档).3.事件捕获事件捕获的思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该在最后接收到节点.事件捕获的用意在于事件到达预定目标之前捕获它. DOM事件流 "DOM2级事件流"规定的事件流包括三个阶段:事件捕获阶段.处于目标阶段和冒泡阶段.首先发生的是事件捕获,

  • 谈一谈JS消息机制和事件机制的理解

    消息/事件机制是几乎所有开发语言都有的机制,并不是deviceone的独创,在某些语言称之为消息(Event),有些地方称之为(Message). 其实原理是类似的,只不过有些实现的方式要复杂一点.我们deviceone统一就叫消息. 消息基础概念 还有一些初学者不太熟悉这个机制,我们先简单介绍一些基础概念,如果熟悉的人可以跳过这个部分. 一个/条消息可以理解为是一个数据结构,包含以下几个基本部分: 1.消息源:就是消息的来源,发出这个消息的对象 2.消息名:就是消息的唯一标示 3.消息数据:消

  • JavaScript的事件机制详解

    事件是将JavaScript脚本与网页联系在一起的主要方式,是JavaScript中最重要的主题之一,深入理解事件的工作机制以及它们对性能的影响至关重要.本文将详细探讨JavaScript的事件机制,并对比分析了浏览器之间的不同,具体内容包括事件流.事件处理程序绑定方式.事件对象等. 如何理解事件? JavaScript与HTML之间的交互就是通过事件实现的. 事件:用户或浏览器自身执行的某种动作,换言之,文档或浏览器发生的一些特定的交互瞬间. 事件处理程序:又称事件侦听器,事件发生时执行的代码

  • 浅析JavaScript中的事件机制

     事件是什么 ? JavaScript与HTML交互是通过在用户或浏览器操纵页面上发生的事件进行处理. 当页面加载,这是一个事件.当用户点击一个按钮,这一下,也就是一个事件.事件的另一个例子是类似按下任意键,关闭窗口,调整窗口等. 开发者可以使用这些事件执行JavaScript编码响应,这引起按钮以关闭视窗,消息,以便显示给用户,要验证的数据,以及几乎任何其它类型的响应可以发生的. 事件是文档对象模型(DOM)第3级,每一个HTML元素的一部分有一套可以触发JavaScript代码事件. 例子:

  • javaScript事件机制兼容【详细整理】

    [添加事件机制]  addEventListener  和  attachEvent [W3C] addEventListener('click' , function(){alert('Hello World')} ,false )  //W3C规范添加事件(IE8及以上不兼容):  第一个参数为事件类型 ,第二个为事件程序 ,第三个 false为事件冒泡,true为事件捕获 [IE] attachEvent('onclick',function(){alert('Hello World')}

  • 详解Node.js中的事件机制

    前言 在前端编程中,事件的应用十分广泛,DOM上的各种事件.在Ajax大规模应用之后,异步请求更得到广泛的认同,而Ajax亦是基于事件机制的. 通常js给我们的第一印象就是运行在客户端浏览器上面的脚本,通过node.js我们可以在服务端运行javascript. node.js是基于单线程无阻塞异步式的I/O,异步式的I/O指的是当遇到I/O操作的时候,线程不阻塞而是进行下面的操作,那么I/O操作完成之后,线程时如何知道该操作完成的呢? 当操作完成耗时的I/O操作之后,会以事件的形式通知I/O操

  • 深入解析JavaScript框架Backbone.js中的事件机制

    事件模型及其原理 Backbone.Events就是事件实现的核心,它可以让对象拥有事件能力 var Events = Backbone.Events = { .. } 对象通过listenTo侦听其他对象,通过trigger触发事件.可以脱离Backbone的MVC,在自定义的对象上使用事件 var model = _.extend({},Backbone.Events); var view = _.extend({},Backbone.Events); view.listenTo(model

  • 全面解析JavaScript的Backbone.js框架中的Router路由

    Backbone 中的 Router 充当路由的作用,控制 URL 的走向,当在 URL 中使用 # 标签时生效. 定义 Router 至少需要一个 Router 和一个函数来映射特定的 URL,而且我们需要记住,在 Backbone 中,# 标签后的任意字符都会被 Router 接收并解释. 下面我们来定义一个 Router: <script> var AppRouter = Backbone.Router.extend({ routes: { "*actions": &

  • 使用JavaScript实现node.js中的path.join方法

    Node.JS中的 path.join 非常方便,能直接按相对或绝对合并路径,使用: path.join([path1], [path2], [...]),有时侯前端也需要这种方法,如何实现呢? 其实直接从 node.js 的 path.js 拿到源码加工一下就可以了: 1. 将 const 等 es6 属性改为 var,以便前端浏览器兼容 2. 添加一个判断路戏分隔符的变量 sep,即左斜杠还是右斜杠,以第一个路戏分隔符为准 3. 将引用的变量和函数放到一个文件里就可以了: Path 的源码:

  • 一文详解JS中的事件循环机制

    目录 前言 1.JavaScript是单线程的 2.同步和异步 3.事件循环 前言 我们知道JavaScript 是单线程的编程语言,只能同一时间内做一件事,按顺序来处理事件,但是在遇到异步事件的时候,js线程并没有阻塞,还会继续执行,这又是为什么呢?本文来总结一下js 的事件循环机制. 1.JavaScript是单线程的 JavaScript 是一种单线程的编程语言,只有一个调用栈,决定了它在同一时间只能做一件事.在代码执行的时候,通过将不同函数的执行上下文压入执行栈中来保证代码的有序执行.在

  • 实例详解JS中的事件循环机制

    目录 一.前言 二.宏.微任务 三.Tick 执行顺序 四.案例详解 1.掺杂setTimeout 2.掺杂微任务,此处主要是Promise.then 3.掺杂async/await 一.前言 之前我们把react相关钩子函数大致介绍了一遍,这一系列完结之后我莫名感到空虚,不知道接下来应该更新有关哪方面的文章.最近想了想,打算先回归一遍JS基础,把一些比较重要的基础知识点回顾一下,然后继续撸框架(可能是源码.也可能补全下全家桶).不积跬步无以至千里,万丈高楼咱们先从JS的事件循环机制开始吧,废话

  • zepto.js中tap事件阻止冒泡的实现方法

    本文实例讲述了zepto.js中tap事件阻止冒泡的实现方法.分享给大家供大家参考.具体如下: 最近在弄一个手机版的网站,本来想用jQuery Mobile,但文件太大了,所以用了zepto.js 由于移动网页中使用click事件会有延迟,所以就用上了zepto.js中的tap事件. 使用click事件可以使用stopPropagation来阻止冒泡,但tap使用该方法无效 现在我需要实现这样一个效果:点击a.btn这个按钮,然后显示div.panel,当我点击非div.panel时隐藏div.

  • js中键盘事件实例简析

    本文实例分析了js中键盘事件.分享给大家供大家参考.具体分析如下: 该实例效果: 按键盘上的任意一个键,弹出相应的ASCII码,兼容ie,chrome和firefox. 但还是有不少问题: (1)ie和chrome中,一些键没有效果,如上.下.左.右等: (2)而firefox中的向右键,与单引号键,都为39. 具体代码如下: 复制代码 代码如下: <html> <head> <script type="text/javascript">  wind

  • js中的事件捕捉模型与冒泡模型实例分析

    本文实例讲述了js中的事件捕捉模型与冒泡模型.分享给大家供大家参考. 具体实现方法如下: 实例1: 复制代码 代码如下: <html> <head> <script type="text/javascript">  window.onload = function(){   document.getElementById('par').addEventListener('click',function() {alert('par');},true);

  • JS中touchstart事件与click事件冲突的解决方法

    前言 移动互联网是未来的发展趋势,现在国内很多互联网大佬都在争取移动这一块大饼,如微信及支付宝是目前比较成功的例子,当然还有各种APP和web运用. 下面这篇文章主要介绍了关于JS中touchstart事件与click事件冲突解决的相关内容,下面话不多说了,来一起看看详细的介绍吧. 一 · 业务场景的描述 在对已完成的PC站点进行移动端适配时,我们想要站点在移动设备上有更快的响应速度,以带给用户更好的体验,此时,我们应该使用移动设备专用的事件系统,例如,使用 touchstart 事件代替 cl

随机推荐