웹 프론트엔드 JS 튜토리얼 Javascript를 사용하여 사용자 정의 이벤트 메커니즘을 구현하는 방법

Javascript를 사용하여 사용자 정의 이벤트 메커니즘을 구현하는 방법

Jun 20, 2018 pm 05:02 PM

웹 기술이 발전하면서 JavaScript를 사용하여 객체를 맞춤화하는 일이 점점 더 빈번해지고 있습니다. 생성한 객체에 이벤트 메커니즘과 이벤트를 통한 외부 통신을 허용하면 개발 효율성이 크게 향상될 수 있습니다. 다음 기사에서는 Javascript를 사용하여 사용자 정의 이벤트 메커니즘을 구현하는 방법에 대한 관련 정보를 주로 소개합니다.

머리말

이벤트 메커니즘은 웹 개발에 큰 편의를 제공하므로 언제든지 수행할 작업과 실행할 코드를 지정할 수 있습니다.

예를 들어, 클릭 이벤트는 사용자가 클릭할 때 발생하고, 키보드를 누르거나 팝업할 때 keydown 및 keyup 이벤트가 발생하며, 업로드 컨트롤에서는 파일이 추가되기 전과 업로드가 완료된 후에 이벤트가 발생합니다.

해당 이벤트가 적시에 발생하므로 이러한 이벤트에 해당하는 처리 기능을 지정할 수 있으며, 원본 프로세스에 다양한 개인화된 작업 및 처리를 삽입하여 전체 프로세스를 더욱 효율적으로 만들 수 있습니다.

클릭, 블러, 포커스 등의 이벤트는 원본 DOM에서 직접 제공하는 기본 이벤트입니다. 그러나 우리가 사용하는 다른 컨트롤에서 사용하는 다양한 이벤트 중 일부는 기본 DOM에서 사용할 수 없습니다. 업로드 컨트롤에 업로드하세요. 그러면 이러한 이벤트는 어떻게 구현되나요?

내가 개발한 컨트롤에 유사한 이벤트 메커니즘을 추가하고 싶습니다. 어떻게 구현하나요? 알아봅시다.

이벤트가 갖춰야 할 기능

구현에 앞서 먼저 이벤트 메커니즘이 갖춰야 할 기본 기능을 분석합니다.

간단히 말하면 이벤트는 다음 기능을 제공해야 합니다.

  • 이벤트 바인딩

  • 이벤트 트리거

  • 이벤트 바인딩 해제

사전 준비

해보자 이벤트는 특정 개체에 속해야 합니다. 예를 들어, 포커스 및 흐림 이벤트는 포커스를 얻을 수 있는 DOM 요소에 대한 것이고, 입력 이벤트는 입력 상자에 대한 것이며, 업로드 시작 및 업로드 성공은 업로드 성공에 대한 것입니다.

즉, 이벤트는 독립적으로 존재하는 것이 아니라 운반자가 필요합니다. 그렇다면 이벤트에 캐리어가 있도록 하려면 어떻게 해야 할까요? 간단한 구현 솔루션은 이벤트를 기본 클래스로 사용하고 이벤트가 필요한 이 이벤트 클래스를 상속하는 것입니다.

바인딩 이벤트, 트리거 이벤트, 바인딩 해제 이벤트의 이름을 각각 on, fire, off로 지정하고 간단히 이 이벤트 클래스를 작성할 수 있습니다. 바인딩은 이벤트 유형과 이벤트 처리 기능을 지정해야 합니다.

그럼 그 외에 무엇이 더 필요할까요? 커스텀 이벤트이므로 네이티브 이벤트처럼 버블링 단계에서 발생하는지, 캡처 단계에서 발생하는지 지정할 필요도 없고, jQuery처럼 추가로 발생시킬 요소를 지정할 필요도 없습니다. 이벤트 함수에 있는 것은 일반적으로 현재 인스턴스입니다. 경우에 따라 적용되지 않을 수도 있습니다. 이벤트 처리 함수가 실행될 때 컨텍스트를 다시 지정해야 합니다. 따라서 이벤트 바인딩을 결정할 때 세 가지 매개변수는 이벤트 유형, 이벤트 처리 함수, 이벤트 처리 함수 실행 컨텍스트입니다.

그렇다면 이벤트 바인딩은 실제로는 매우 간단합니다. 이벤트 바인딩에는 해당 이벤트 이름과 이벤트 처리 기능만 기록하면 됩니다.

내 구현은 다음과 같습니다.

function CustomEvent() {
 this._events = {};
}
CustomEvent.prototype = {
 constructor: CustomEvent,
 // 绑定事件
 on: function () {
 },
 // 触发事件
 fire: function () {
 },
 // 取消绑定事件
 off: function () {
 }
};
로그인 후 복사

이벤트는 여러 번 바인딩되고 순차적으로 실행될 수 있으므로 모든 이벤트 유형의 처리 함수는 배열에 저장됩니다.

이벤트 트리거링

이벤트 트리거링의 기본 기능은 사용자가 바인딩한 이벤트를 실행하는 것이므로, 이벤트가 트리거될 때 지정된 실행 함수가 있는지만 확인하면 되고, 그렇다면 그냥 전화해.

또한 이벤트 트리거링은 실제로 사용자가 지정한 처리 기능을 실행하는 과정이고, 사용자가 지정한 이벤트 처리 기능에서도 많은 개인화된 작업이 수행되므로 이 기능을 실행하는 것만으로는 충분하지 않습니다. 클릭 이벤트의 현재 클릭된 요소, 키보드 이벤트의 현재 키의 키 코드, 업로드 시작 및 업로드 완료의 현재 파일 정보 등 현재 기능에 필요한 정보도 제공되어야 합니다. 따라서 이벤트가 발생하면 이벤트 처리 함수의 실제 매개변수에는 현재 이벤트의 기본 정보가 포함되어야 합니다. 또한 이벤트 처리 기능에서 사용자 작업을 통해 후속 정보를 조정해야 할 수도 있습니다. 예를 들어 keydwon 이벤트에서는 사용자가 파일을 업로드하기 전에 이 키의 입력을 금지할 수 있습니다. 이벤트 발생 시 파일 업로드를 취소하거나 일부 파일 정보를 수정합니다. 따라서 이벤트 트리거 함수는 사용자가 수정한 이벤트 객체를 반환해야 합니다.

내 구현은 다음과 같습니다.

{
 /**
  * 绑定事件
  * 
  * @param {String} type 事件类型
  * @param {Function} fn 事件处理函数
  * @param {Object} scope 要为事件处理函数绑定的执行上下文
  * @returns 当前实例对象
  */
 on: function (type, fn, scope) {
  if (type + '' !== type) {
   console && console.error && console.error('the first argument type is requird as string');
   return this;
  }
  if (typeof fn != 'function') {
   console && console.error && console.error('the second argument fn is requird as function');
   return this;
  }
  type = type.toLowerCase();

  if (!this._events[type]) {
   this._events[type] = [];
  }
  this._events[type].push(scope ? [fn, scope] : [fn]);
  return this;
 }
}
로그인 후 복사

위 구현에서 이벤트 처리 함수에 제공된 실제 매개변수에는 다음 정보가 포함되어야 합니다.

type : 현재 트리거된 이벤트 유형

origin : 현재 이벤트는 개체

  • 범위: 이벤트 처리 함수의 실행 컨텍스트

  • 에 바인딩됩니다. 또한, 다양한 이벤트가 트리거될 때 이 이벤트 개체에 다른 정보를 추가할 수 있습니다.

    关于 Object.assign(target, ...sources) 是ES6中的一个方法,作用是将所有可枚举属性的值从一个或多个源对象复制到目标对象,并返回目标对象,类似于大家熟知的$.extend(target,..sources) 方法。

    事件取消

    事件取消中需要做的就是已经绑定的事件处理函数移除掉即可。

    实现如下:

    {
     /**
      * 取消绑定一个事件
      * 
      * @param {String} type 取消绑定的事件名称
      * @param {Function} fn 要取消绑定的事件处理函数,不指定则移除当前事件类型下的全部处理函数
      * @returns 当前实例对象
      */
     off: function (type, fn) {
      type = type.toLowerCase();
      var eventArr = this._events[type];
      if (!eventArr || !eventArr.length) return this;
      if (!fn) {
       this._events[type] = eventArr = [];
      } else {
       for (var i = 0; i < eventArr.length; ++i) {
        if (fn === eventArr[i][0]) {
         eventArr.splice(i, 1);
         // 1、找到后不能立即 break 可能存在一个事件一个函数绑定多次的情况
         // 删除后数组改变,下一个仍然需要遍历处理!
         --i;
        }
       }
      }
      return this;
     }
    }
    로그인 후 복사

    此处实现类似原生的事件取消绑定,如果指定了事件处理函数则移除指定事件的指定处理函数,如果省略事件处理函数则移除当前事件类型下的所有事件处理函数。

    仅触发一次的事件

    jQuery中有一个 one 方法,它所绑定的事件仅会执行一次,此方法在一些特定情况下非常有用,不需要用户手动取消绑定这个事件。

    这里的实现也非常简单,只用在触发这个事件时取消绑定即可。

    实现如下:

    {
     /**
      * 绑定一个只执行一次的事件
      * 
      * @param {String} type 事件类型
      * @param {Function} fn 事件处理函数
      * @param {Object} scope 要为事件处理函数绑定的执行上下文
      * @returns 当前实例对象
      */
     one: function (type, fn, scope) {
      var that = this;
      function nfn() {
       // 执行时 先取消绑定
       that.off(type, nfn);
       // 再执行函数
       fn.apply(scope || that, arguments);
      }
      this.on(type, nfn, scope);
      return this;
     }
    }
    로그인 후 복사

    原理则是不把用户指定的函数直接绑定上去,而是生成一个新的函数,并绑定,此函数执行时会先取消绑定,再执行用户指定的处理函数。

    基本雏形

    到此,一套完整的事件机制就已经完成了,完整代码如下:

    function CustomEvent() {
     this._events = {};
    }
    CustomEvent.prototype = {
     constructor: CustomEvent,
     /**
      * 绑定事件
      * 
      * @param {String} type 事件类型
      * @param {Function} fn 事件处理函数
      * @param {Object} scope 要为事件处理函数绑定的执行上下文
      * @returns 当前实例对象
      */
     on: function (type, fn, scope) {
      if (type + &#39;&#39; !== type) {
       console && console.error && console.error(&#39;the first argument type is requird as string&#39;);
       return this;
      }
      if (typeof fn != &#39;function&#39;) {
       console && console.error && console.error(&#39;the second argument fn is requird as function&#39;);
       return this;
      }
      type = type.toLowerCase();
    
      if (!this._events[type]) {
       this._events[type] = [];
      }
      this._events[type].push(scope ? [fn, scope] : [fn]);
    
      return this;
     },
     /**
      * 触发事件
      * 
      * @param {String} type 触发事件的名称
      * @param {Anything} data 要额外传递的数据,事件处理函数参数如下
      * event = {
       // 事件类型
       type: type,
       // 绑定的源,始终为当前实例对象
       origin: this,
       // 事件处理函数中的执行上下文 为 this 或用户指定的上下文对象
       scope :this/scope
       // 其他数据 为fire时传递的数据
      }
      * @returns 事件对象
      */
     fire: function (type, data) {
      type = type.toLowerCase();
      var eventArr = this._events[type];
      var fn, scope,
       event = Object.assign({
        // 事件类型
        type: type,
        // 绑定的源
        origin: this,
        // scope 为 this 或用户指定的上下文,
        // 是否取消
        cancel: false
       }, data);
    
      if (!eventArr) return event;
    
      for (var i = 0, l = eventArr.length; i < l; ++i) {
       fn = eventArr[i][0];
       scope = eventArr[i][1];
       if (scope) {
        event.scope = scope;
        fn.call(scope, event);
       } else {
        event.scope = this;
        fn(event);
       }
      }
      return event;
     },
     /**
      * 取消绑定一个事件
      * 
      * @param {String} type 取消绑定的事件名称
      * @param {Function} fn 要取消绑定的事件处理函数,不指定则移除当前事件类型下的全部处理函数
      * @returns 当前实例对象
      */
     off: function (type, fn) {
      type = type.toLowerCase();
      var eventArr = this._events[type];
      if (!eventArr || !eventArr.length) return this;
      if (!fn) {
       this._events[type] = eventArr = [];
      } else {
       for (var i = 0; i < eventArr.length; ++i) {
        if (fn === eventArr[i][0]) {
         eventArr.splice(i, 1);
         // 1、找到后不能立即 break 可能存在一个事件一个函数绑定多次的情况
         // 删除后数组改变,下一个仍然需要遍历处理!
         --i;
        }
       }
      }
      return this;
     },
     /**
      * 绑定一个只执行一次的事件
      * 
      * @param {String} type 事件类型
      * @param {Function} fn 事件处理函数
      * @param {Object} scope 要为事件处理函数绑定的执行上下文
      * @returns 当前实例对象
      */
     one: function (type, fn, scope) {
      var that = this;
    
      function nfn() {
       // 执行时 先取消绑定
       that.off(type, nfn);
       // 再执行函数
       fn.apply(scope || that, arguments);
      }
      this.on(type, nfn, scope);
      return this;
     }
    };
    로그인 후 복사

    在自己的控件中使用

    上面已经实现了一套事件机制,我们如何在自己的事件中使用呢。

    比如我写了一个日历控件,需要使用事件机制。

    function Calendar() {
     // 加入事件机制的存储的对象
     this._event = {};
     // 日历的其他实现
    }
    Calendar.prototype = {
     constructor:Calendar,
     on:function () {},
     off:function () {},
     fire:function () {},
     one:function () {},
     // 日历的其他实现 。。。
    }
    로그인 후 복사

    以上伪代码作为示意,仅需在让控件继承到on、off 、fire 、one等方法即可。但是必须保证事件的存储对象_events 必须是直接加载实例上的,这点需要在继承时注意,JavaScript中实现继承的方案太多了。

    上面为日历控件Calendar中加入了事件机制,之后就可以在Calendar中使用了。

    如在日历开发时,我们在日历的单元格渲染时触发cellRender事件。

    // 每天渲染时发生 还未插入页面
    var renderEvent = this.fire(&#39;cellRender&#39;, {
     // 当天的完整日期
     date: date.format(&#39;YYYY-MM-DD&#39;),
     // 当天的iso星期
     isoWeekday: day,
     // 日历dom
     el: this.el,
     // 当前单元格
     tdEl: td,
     // 日期文本
     dateText: text.innerText,
     // 日期class
     dateCls: text.className,
     // 需要注入的额外的html
     extraHtml: &#39;&#39;,
     isHeader: false
    });
    로그인 후 복사

    在事件中,我们将当前渲染的日期、文本class等信息都提供给用户,这样用户就可以绑定这个事件,在这个事件中进行自己的个性阿化处理了。

    如在渲染时,如果是周末则插入一个"假"的标识,并让日期显示为红色。

    var calendar = new Calendar();
    calendar.on(&#39;cellRender&#39;, function (e) {
     if(e.isoWeekday > 5 ) {
      e.extraHtml = &#39;<span>假</span>&#39;;
      e.dateCls += &#39; red&#39;;
     } 
    });
    로그인 후 복사

    上面是我整理给大家的,希望今后会对大家有帮助。

    相关文章:

    使用jQuery封装animate.css(详细教程)

    vue-cli配置文件(详细教程)

    使用Vue2.x如何实现JSON树

    在Angular4中有关CLI的安装与使用教程

    使用JS实现换图时钟(详细教程)

    위 내용은 Javascript를 사용하여 사용자 정의 이벤트 메커니즘을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

프론트 엔드 열 용지 영수증에 대한 차량 코드 인쇄를 만나면 어떻게해야합니까? 프론트 엔드 열 용지 영수증에 대한 차량 코드 인쇄를 만나면 어떻게해야합니까? Apr 04, 2025 pm 02:42 PM

프론트 엔드 개발시 프론트 엔드 열지대 티켓 인쇄를위한 자주 묻는 질문과 솔루션, 티켓 인쇄는 일반적인 요구 사항입니다. 그러나 많은 개발자들이 구현하고 있습니다 ...

누가 더 많은 파이썬이나 자바 스크립트를 지불합니까? 누가 더 많은 파이썬이나 자바 스크립트를 지불합니까? Apr 04, 2025 am 12:09 AM

기술 및 산업 요구에 따라 Python 및 JavaScript 개발자에 대한 절대 급여는 없습니다. 1. 파이썬은 데이터 과학 및 기계 학습에서 더 많은 비용을 지불 할 수 있습니다. 2. JavaScript는 프론트 엔드 및 풀 스택 개발에 큰 수요가 있으며 급여도 상당합니다. 3. 영향 요인에는 경험, 지리적 위치, 회사 규모 및 특정 기술이 포함됩니다.

Demystifying JavaScript : 그것이하는 일과 중요한 이유 Demystifying JavaScript : 그것이하는 일과 중요한 이유 Apr 09, 2025 am 12:07 AM

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.

JavaScript를 사용하여 동일한 ID와 동일한 ID로 배열 요소를 하나의 객체로 병합하는 방법은 무엇입니까? JavaScript를 사용하여 동일한 ID와 동일한 ID로 배열 요소를 하나의 객체로 병합하는 방법은 무엇입니까? Apr 04, 2025 pm 05:09 PM

동일한 ID로 배열 요소를 JavaScript의 하나의 객체로 병합하는 방법은 무엇입니까? 데이터를 처리 할 때 종종 동일한 ID를 가질 필요가 있습니다 ...

Shiseido의 공식 웹 사이트와 같은 시차 스크롤 및 요소 애니메이션 효과를 달성하는 방법은 무엇입니까?
또는:
Shiseido의 공식 웹 사이트와 같은 페이지 스크롤과 함께 애니메이션 효과를 어떻게 달성 할 수 있습니까? Shiseido의 공식 웹 사이트와 같은 시차 스크롤 및 요소 애니메이션 효과를 달성하는 방법은 무엇입니까? 또는: Shiseido의 공식 웹 사이트와 같은 페이지 스크롤과 함께 애니메이션 효과를 어떻게 달성 할 수 있습니까? Apr 04, 2025 pm 05:36 PM

이 기사에서 시차 스크롤 및 요소 애니메이션 효과 실현에 대한 토론은 Shiseido 공식 웹 사이트 (https://www.shiseido.co.jp/sb/wonderland/)와 유사하게 달성하는 방법을 살펴볼 것입니다.

Console.log 출력 결과의 차이 : 두 통화가 다른 이유는 무엇입니까? Console.log 출력 결과의 차이 : 두 통화가 다른 이유는 무엇입니까? Apr 04, 2025 pm 05:12 PM

Console.log 출력의 차이의 근본 원인에 대한 심층적 인 논의. 이 기사에서는 Console.log 함수의 출력 결과의 차이점을 코드에서 분석하고 그에 따른 이유를 설명합니다. � ...

JavaScript는 배우기가 어렵습니까? JavaScript는 배우기가 어렵습니까? Apr 03, 2025 am 12:20 AM

JavaScript를 배우는 것은 어렵지 않지만 어려운 일입니다. 1) 변수, 데이터 유형, 기능 등과 같은 기본 개념을 이해합니다. 2) 마스터 비동기 프로그래밍 및 이벤트 루프를 통해이를 구현하십시오. 3) DOM 운영을 사용하고 비동기 요청을 처리합니다. 4) 일반적인 실수를 피하고 디버깅 기술을 사용하십시오. 5) 성능을 최적화하고 모범 사례를 따르십시오.

프론트 엔드 개발에서 VSCODE와 유사한 패널 드래그 앤 드롭 조정 기능을 구현하는 방법은 무엇입니까? 프론트 엔드 개발에서 VSCODE와 유사한 패널 드래그 앤 드롭 조정 기능을 구현하는 방법은 무엇입니까? Apr 04, 2025 pm 02:06 PM

프론트 엔드에서 VSCODE와 같은 패널 드래그 앤 드롭 조정 기능의 구현을 탐색하십시오. 프론트 엔드 개발에서 VSCODE와 같은 구현 방법 ...

See all articles