详解JavaScript中的自定义事件编写_基础知识

我们可以自定义事件来实现更灵活的开发,事件用好了可以是一件很强大的工具,基于事件的开发有很多优势(后面介绍)。

与自定义事件的函数有 Event、CustomEvent 和 dispatchEvent。

直接自定义事件,使用 Event 构造函数:

var event = new Event('build');

// Listen for the event.
elem.addEventListener('build', function (e) { ... }, false);

// Dispatch the event.
elem.dispatchEvent(event);

CustomEvent 可以创建一个更高度自定义事件,还可以附带一些数据,具体用法如下:

var myEvent = new CustomEvent(eventname, options);

其中 options 可以是:

{
  detail: {
    ...
  },
  bubbles: true,
  cancelable: false
}

其中 detail 可以存放一些初始化的信息,可以在触发的时候调用。其他属性就是定义该事件是否具有冒泡等等功能。

内置的事件会由浏览器根据某些操作进行触发,自定义的事件就需要人工触发。dispatchEvent 函数就是用来触发某个事件:

element.dispatchEvent(customEvent);

上面代码表示,在 element 上面触发 customEvent 这个事件。结合起来用就是:

// add an appropriate event listener
obj.addEventListener("cat", function(e) { process(e.detail) });

// create and dispatch the event
var event = new CustomEvent("cat", {"detail":{"hazcheeseburger":true}});
obj.dispatchEvent(event);

使用自定义事件需要注意兼容性问题,而使用 jQuery 就简单多了:

// 绑定自定义事件
$(element).on('myCustomEvent', function(){});

// 触发事件
$(element).trigger('myCustomEvent');
此外,你还可以在触发自定义事件时传递更多参数信息:

$( "p" ).on( "myCustomEvent", function( event, myName ) {
 $( this ).text( myName + ", hi there!" );
});
$( "button" ).click(function () {
 $( "p" ).trigger( "myCustomEvent", [ "John" ] );
});

JavaScript 自定义事件就是有别于如 click, submit 等标准事件的自行定制的事件,在叙述自定义事件有何好处之前,先来看一个自定义事件的例子:

<div id="testBox"></div>

// 创建事件
var evt = document.createEvent('Event');
// 定义事件类型
evt.initEvent('customEvent', true, true);
// 在元素上监听事件
var obj = document.getElementById('testBox');
obj.addEventListener('customEvent', function(){
  console.log('customEvent 事件触发了');
}, false);

具体效果可以查看 Demo,在 console 中输入 obj.dispatchEvent(evt),可以看到 console 中输出“customEvent 事件触发了”,表示自定义事件成功触发。

在这个过程中,createEvent 方法创建了一个空事件 evt,然后使用 initEvent 方法定义事件的类型为约定好的自定义事件,再对相应的元素进行监听,接着,就是使用 dispatchEvent 触发事件了。

没错,自定义事件的机制如普通事件一样——监听事件,写回调操作,触发事件后执行回调。但不同的是,自定义事件完全由我们控制触发时机,这就意味着实现了一种 JavaScript 的解耦。我们可以把多个关联但逻辑复杂的操作利用自定义事件的机制灵活地控制好。

当然,可能你已经猜到了,上面的代码在低版本的 IE 中并不生效,事实上在 IE8 及以下版本的 IE 中并不支持 createEvent(),而有 IE 私有的 fireEvent() 方法,但遗憾的是,fireEvent 只支持标准事件的触发。因此,我们只能使用一个特殊而简单的方法触发自定义事件。

// type 为自定义事件,如 type = 'customEvent',callback 为开发者实际定义的回调函数
obj[type] = 0;
obj[type]++;

obj.attachEvent('onpropertychange', function(event){
  if( event.propertyName == type ){
    callback.call(obj);
  }
});

这个方法的原理实际上是在 DOM 中增加一个自定义属性,同时监听元素的 propertychange 事件,当 DOM 的某个属性的值发生改变时就会触发 propertychange 的回调,再在回调中判断发生改变的属性是否为我们的自定义属性,若是则执行开发者实际定义的回调。从而模拟了自定义事件的机制。

为了使到自定义事件的机制能配合标准事件的监听和模拟触发,这里给出一个完整的事件机制,这个机制支持标准事件和自定义事件的监听,移除监听和模拟触发操作。需要注意的是,为了使到代码的逻辑更加清晰,这里约定自定义事件带有 'custom' 的前缀(例如:customTest,customAlert)。

/**
 * @description 包含事件监听、移除和模拟事件触发的事件机制,支持链式调用
 *
 */

(function( window, undefined ){

var Ev = window.Ev = window.$ = function(element){

  return new Ev.fn.init(element);
};

// Ev 对象构建

Ev.fn = Ev.prototype = {

  init: function(element){

    this.element = (element && element.nodeType == 1)? element: document;
  },

  /**
   * 添加事件监听
   *
   * @param {String} type 监听的事件类型
   * @param {Function} callback 回调函数
   */

  add: function(type, callback){

    var _that = this;

    if(_that.element.addEventListener){

      /**
       * @supported For Modern Browers and IE9+
       */

      _that.element.addEventListener(type, callback, false);

    } else if(_that.element.attachEvent){

      /**
       * @supported For IE5+
       */

      // 自定义事件处理
      if( type.indexOf('custom') != -1 ){

        if( isNaN( _that.element[type] ) ){

          _that.element[type] = 0;

        } 

        var fnEv = function(event){

          event = event ? event : window.event

          if( event.propertyName == type ){
            callback.call(_that.element);
          }
        };

        _that.element.attachEvent('onpropertychange', fnEv);

        // 在元素上存储绑定的 propertychange 的回调,方便移除事件绑定
        if( !_that.element['callback' + callback] ){

          _that.element['callback' + callback] = fnEv;

        }

      // 标准事件处理
      } else {

        _that.element.attachEvent('on' + type, callback);
      }

    } else {

      /**
       * @supported For Others
       */

      _that.element['on' + type] = callback;

    }

    return _that;
  },

  /**
   * 移除事件监听
   *
   * @param {String} type 监听的事件类型
   * @param {Function} callback 回调函数
   */

  remove: function(type, callback){

    var _that = this;

    if(_that.element.removeEventListener){

      /**
       * @supported For Modern Browers and IE9+
       */

      _that.element.removeEventListener(type, callback, false);

    } else if(_that.element.detachEvent){

      /**
       * @supported For IE5+
       */

      // 自定义事件处理
      if( type.indexOf('custom') != -1 ){

        // 移除对相应的自定义属性的监听
        _that.element.detachEvent('onpropertychange', _that.element['callback' + callback]);

        // 删除储存在 DOM 上的自定义事件的回调
        _that.element['callback' + callback] = null;

      // 标准事件的处理
      } else {

        _that.element.detachEvent('on' + type, callback);

      }

    } else {

      /**
       * @supported For Others
       */

      _that.element['on' + type] = null;

    }

    return _that;

  },

  /**
   * 模拟触发事件
   * @param {String} type 模拟触发事件的事件类型
   * @return {Object} 返回当前的 Kjs 对象
   */

  trigger: function(type){

    var _that = this;

    try {
        // 现代浏览器
      if(_that.element.dispatchEvent){
        // 创建事件
        var evt = document.createEvent('Event');
        // 定义事件的类型
        evt.initEvent(type, true, true);
        // 触发事件
        _that.element.dispatchEvent(evt);
      // IE
      } else if(_that.element.fireEvent){

        if( type.indexOf('custom') != -1 ){

          _that.element[type]++;

        } else {

          _that.element.fireEvent('on' + type);
        }

      }

    } catch(e){

    };

    return _that;

  }
}

Ev.fn.init.prototype = Ev.fn;

})( window );
测试用例1(自定义事件测试)

// 测试用例1(自定义事件测试)
// 引入事件机制
// ...
// 捕捉 DOM
var testBox = document.getElementById('testbox');
// 回调函数1
function triggerEvent(){
    console.log('触发了一次自定义事件 customConsole');
}
// 回调函数2
function triggerAgain(){
    console.log('再一次触发了自定义事件 customConsole');
}
// 封装
testBox = $(testBox);
// 同时绑定两个回调函数,支持链式调用
testBox.add('customConsole', triggerEvent).add('customConsole', triggerAgain);

完整的代码在 Demo。

打开 Demo 后,在 console 中调用 testBox.trigger('customConsole') 自行触发自定义事件,可以看到 console 输出两个提示语,再输入 testBox.remove('customConsole', triggerAgain) 移除对后一个监听,这时再使用 testBox.trigger('customConsole') 触发自定义事件,可以看到 console 只输出一个提示语,即成功移除后一个监听,至此事件机制所有功能正常工作。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript
, js
, 事件
, event
自定义事件
javascript自定义事件、javascript闭包详解、javascript编写工具、编写javascript的工具、编写javascript的软件,以便于您获取更多的相关知识。

时间: 2024-10-21 22:24:48

详解JavaScript中的自定义事件编写_基础知识的相关文章

详解JavaScript中shift()方法的使用_基础知识

JavaScript数组shift()方法删除数组中的第一个元素,并返回该元素.语法 array.shift(); 下面是参数的详细信息:     NA 返回值: 返回数组中删除单个值.例子: <html> <head> <title>JavaScript Array shift Method</title> </head> <body> <script type="text/javascript">

详解JavaScript中的表单验证_基础知识

 表单验证用于发生在服务器,客户端已经输入所有必要的数据,然后按下提交按钮之后.如果一些已被输入的客户端的数据的已在错误形式或者被简单地丢失,则服务器将必须的所有数据发送回客户端,并请求的形式以正确的信息重新提交.这是一个漫长的过程,会增加服务器负担. JavaScript中,提供了一种方法将其发送到web服务器之前验证客户端的计算机上的形式的数据.表单验证通常执行两种方式.     基本验证 - 首先,该表必须进行检查,以确保数据输入的需要将其每一个表单字段.这将通过表格的每个字段只需要循环,

详解JavaScript中循环控制语句的用法_基础知识

 JavaScript提供完全控制来处理循环和switch语句.可能有一种情况,当你需要退出一个循环,但未达到其底部.也可能有一种情况,当要跳过的码块的一部分,并直接开始下一个迭代. 为了处理这些情况下,JavaScript提供了break和continue语句.这些语句是用来马上退出任何循环或启动循环的下一次迭代.break 语句: break语句,这是简单地用switch语句介绍,用于提前退出循环,打破封闭的花括号. 例子: 这个例子说明了如何使用break语句同while循环.请注意循环打

详解JavaScript中getFullYear()方法的使用_基础知识

 javascript Date.getFullYear()方法按照本地时间返回指定日期的年份.通过getFullYear返回的值是一个绝对的数字.对于1000年和9999之间的日期,getFullYear返回一个4位数字,例如2008年.语法 Date.getFullYear() 下面是参数的详细信息:     NA 返回值: 按照本地时间返回指定日期的年份.例子: <html> <head> <title>JavaScript getFullYear Method&

详解JavaScript的while循环的使用_基础知识

 在写一个程序时,可能有一种情况,当你需要一遍又一遍的执行一些操作.在这样的情况下,则需要写循环语句,以减少代码的数量. JavaScript支持所有必要的循环,以帮助您在所有编程的步骤. while 循环 在JavaScript中最基本的循环是while循环,这将在本教程中学习讨论. 语法 while (expression){ Statement(s) to be executed if expression is true } while循环的目的是为了反复执行语句或代码块(只要表达式为t

详解JavaScript语言的基本语法要求_基础知识

JavaScript语言的基本语法要求有哪些呐?下面将为大家一一解答:  一.区分大小写        JavaScript语言区分字符大小写,两个字符串相同大小写不同,被认为是不同的字符串.JavaScript语言的关键字也区分大小写,按语法要求应小写.二.书写格式         JavaScript语言忽略语句间空白,即语句间的空格,空行,缩进等.为了提高程序的可读性,应当使用这些格式,使程序更加清晰,可读性更高. 三.注释语句         为了提高程序的可维护性和可读性,应当有一定的

Javascript中的数据类型之旅_基础知识

虽然Javascript是弱类型语言,但是,它也有自己的几种数据类型,分别是:Number.String.Boolean.Object.Udefined.Null.其中,Object属于复杂数据类型,Object   由无序的键值对组成.其余几种都属于简单数据类型.注意:变量类型首字母大写,而变量值首字母是小写的. JavaScript不支持自定义类型,所以JavaScript中的所有值都属于这六种类型之一. 根据ECMAScript 5.1的规范,javascript中共有六种数据类型,分别为

关于javascript中的parseInt使用技巧_基础知识

要对表单中填写的日期格式进行客户端验证,于是在网上找了段代码,其中用到parseInt对年月日做判断,其中有类似这样的语句: ...... else if(parseInt(month)<1 || parseInt(month) >12) ...... 可是对于当前本来正确的日期,这里怎么也通不过.后来一查才明白,parseInt实际上有两个参数,第一个是要转换的值,第二个是指定的进制.如果不指定第二个参数,那么它只能正确地转换01到07(即把它们转换成1到7),从08开始,它就会按照&quo

JavaScript中的Window窗口对象_基础知识

JavaScript中的Window窗口对象 他是JavaScript中最大的对象,它描述的是一个浏览器窗口.一般要引用它的属性和方法时,不需要用"window.xxx"这种形式,而直接使用"xxx".一个框架页面也是一个窗口. Window窗口对象有如下属性: name 窗口的名称,由打开它的连接(<a target="...">)或框架页(<frame name="...">)或某一个窗口调用的 o