자 바스 크 립 트 를 이용 하여 사용자 정의 이벤트 메커니즘 을 실현 하 다

머리말
이벤트 메커니즘 은 우리 의 웹 개발 에 매우 큰 편 의 를 제공 하여 우리 가 임의의 시간 에 어떤 조작 을 할 때 어떤 조작 을 하고 어떤 코드 를 실행 할 지 지정 할 수 있 게 한다.
이 벤트 를 클릭 하면 사용자 가 클릭 할 때 촉발 합 니 다.keydown,keyup 이벤트,키보드 누 르 기,키보드 팝 업 시 촉발;업로드 컨트롤 중 파일 가입 전 이벤트,업로드 완료 후 이벤트 도 있 습 니 다.
적당 한 시기 에 해당 하 는 사건 이 발생 하기 때문에 우 리 는 이러한 사건 에 해당 하 는 처리 함 수 를 지정 할 수 있 고 원래 의 절차 에 다양한 맞 춤 형 조작 과 처 리 를 삽입 하여 전체 절 차 를 더욱 풍부 하 게 할 수 있다.
예 를 들 어 click,blur,focus 등 사건 은 원래 dom 에서 직접 제공 하 는 네 이 티 브 사건 이 고 우리 가 사용 하 는 다른 컨트롤 들 이 사용 하 는 여러 가지 사건 은 네 이 티 브 dom 에 만 있 는 것 이 아 닙 니 다.예 를 들 어 업로드 컨트롤 에 업로드 시작 과 완료 사건 이 있 는데 이런 사건 들 은 어떻게 이 루어 집 니까?
자신 이 개발 한 컨트롤 에 비슷 한 사건 체 제 를 넣 으 려 면 어떻게 해 야 할 까?끝까지 알 아 보 자.
이벤트 기능
실현 되 기 전에 우 리 는 먼저 사건 체제 에 있어 야 할 기본 적 인 기능 을 분석 해 야 한다.
쉽게 말 하면 사건 은 다음 과 같은 몇 가지 기능 을 제공 해 야 한다.
  • 귀속 이벤트
  • 촉발 사건
  • 귀속 취소 이벤트
  • 전기 준비
    사건 의 한 특징 을 살 펴 보 자.사건 은 반드시 어떤 대상 에 속 할 것 이다.예 를 들 어 focus 와 blur 이 벤트 는 초점 을 얻 을 수 있 는 dom 요소 이 고 input 이 벤트 는 입력 상자 이 며 업로드 시작 과 업로드 에 성공 하면 업로드 에 성공 합 니 다.
    즉,사건 은 독립 적 으로 존재 하 는 것 이 아니 라 운반 체 가 필요 하 다 는 것 이다.그렇다면 우 리 는 어떻게 사건 에 운반 체 를 가지 게 합 니까?간단 한 실현 방안 은 사건 을 하나의 기본 유형 으로 하고 사건 이 필요 한 곳 에서 이 사건 류 를 계승 하면 된다 는 것 이다.
    저 희 는 바 인 딩 이벤트,트리거 이벤트,바 인 딩 취소 사건 을 각각 on,fire,off 라 고 명명 합 니 다.그러면 저 희 는 이 사건 종 류 를 간단하게 쓸 수 있 습 니 다.
    
    function CustomEvent() {
     this._events = {};
    }
    CustomEvent.prototype = {
     constructor: CustomEvent,
     //     
     on: function () {
     },
     //     
     fire: function () {
     },
     //       
     off: function () {
     }
    };
    이벤트 바 인 딩
    먼저 이벤트 의 바 인 딩 을 실현 합 니 다.이벤트 바 인 딩 은 이벤트 의 유형 과 이벤트 의 처리 함 수 를 지정 해 야 합 니 다.
    그럼 그 외 에 또 무엇이 필요 할 까요?저 희 는 사용자 정의 이벤트 입 니 다.네 이 티 브 이벤트 처럼 거품 단계 의 트리거 인지 포획 단계 의 트리거 인지 지정 할 필요 가 없습니다.jQuery 처럼 그 요소 의 트리거 를 추가 로 지정 할 필요 도 없습니다.
    이벤트 함수 에서 this 는 일반적으로 현재 인 스 턴 스 입 니 다.이것 은 어떤 상황 에서 적용 되 지 않 을 수 있 습 니 다.이벤트 처리 함수 가 실 행 될 때의 컨 텍스트 환경 을 다시 지정 해 야 합 니 다.
    따라서 이벤트 바 인 딩 을 확정 할 때 세 가지 매개 변 수 는 이벤트 유형,이벤트 처리 함수,이벤트 처리 함수 실행 컨 텍스트 입 니 다.
    그러면 이벤트 바 인 딩 은 무엇 을 해 야 합 니까?사실은 간단 합 니 다.이벤트 바 인 딩 은 해당 하 는 이벤트 이름과 이벤트 처리 함수 만 기록 하면 됩 니 다.
    나의 실현 은 다음 과 같다.
    
    {
     /**
      *     
      * 
      * @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;
     }
    }
    하나의 이벤트 가 여러 번 연결 되 어 있 기 때문에 실행 할 때 순서대로 실 행 됩 니 다.모든 이벤트 형식의 처리 함수 저장 소 는 배열 을 사용 합 니 다.
    이벤트 트리거
    이벤트 트리거 의 기본 기능 은 사용자 가 연 결 된 이 벤트 를 실행 하 는 것 입 니 다.따라서 이벤트 트리거 시 지정 한 실행 함수 가 있 는 지 확인 하고 있 으 면 호출 하면 됩 니 다.
    또한 이벤트 트리거 는 실제 적 으로 사용자 가 지정 한 처리 함수 가 실행 되 는 과정 이 고 많은 맞 춤 형 작업 을 할 수 있 는 것 도 사용자 가 지정 한 이벤트 처리 함수 에서 이 루어 지기 때문에 이 함수 만 실행 하 는 것 으로 는 부족 합 니 다.또한 현재 함수 에 필요 한 정 보 를 제공 해 야 합 니 다.예 를 들 어 클릭 이벤트 에 현재 클릭 된 요소 가 있 고 키보드 이벤트 에 현재 키 의 키 코드 가 있 으 며 업로드 시작 과 업로드 완료 에 현재 파일 이 있 는 정 보 를 제공 해 야 합 니 다.
    따라서 이벤트 가 실 행 될 때 이벤트 처리 함수 의 실제 인삼 에는 현재 이벤트 의 기본 정보 가 포함 되 어야 합 니 다.
    그 밖 에 사용자 가 이벤트 처리 함수 에서 의 작업 을 통 해 다음 정 보 를 조정 해 야 할 수도 있 습 니 다.예 를 들 어 keydwon 이벤트 에서 사용 자 는 이 키 의 입력 을 금지 할 수 있 습 니 다.파일 이 업로드 되 기 전에 사용 자 는 이벤트 에서 이 파일 의 업 로드 를 취소 하거나 파일 정 보 를 수정 할 수 있 습 니 다.따라서 이벤트 트리거 함 수 는 사용자 가 수정 한 이벤트 대상 으로 돌아 가 야 합 니 다.
    나의 실현 은 다음 과 같다.
    
    {
     /**
      *     
      * 
      * @param {String} type        
      * @param {Object} 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,
       // event = {
       //  //     
       //  type: type,
       //  //     
       //  origin: this,
       //  // scope   this          ,
       //  //      
       //  data: data,
       //  //     
       //  cancel: false
       // };
       //                                 
       event = $.extend({
        //     
        type: type,
        //     
        origin: this,
        // scope   this          ,
        //      
        // data: data,
        //     
        cancel: false
       }, data);
      if (!eventArr) {
       return event;
      }
      for (var i = 0, l = eventArr.length; i < l; ++i) {
       fn = eventArr[i][0];
       event.scope = eventArr[i][1] || this;
       fn.call(event.scope, event);
      }
      return event;
     }
    }
    위 에서 이 루어 진 이벤트 처리 함수 의 실제 인삼 에는 다음 과 같은 정보 가 포함 되 어 있 습 니 다.
  • type:현재 실행 중인 이벤트 종류
  • origin:현재 이벤트 가 연 결 된 대상
  • scope:이벤트 처리 함수 의 실행 문맥
  • 또한 서로 다른 사건 이 각종 촉발 시 이 사건 의 대상 에 각각 다른 정 보 를 추가 할 수 있다.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 에는 하나의 원 방법 이 있 습 니 다.바 인 딩 된 이 벤트 는 한 번 만 실 행 됩 니 다.이 방법 은 특정한 상황 에서 매우 유용 합 니 다.사용자 가 수 동 으로 바 인 딩 을 취소 할 필요 가 없습니다.
    이곳 의 실현 도 매우 간단 합 니 다.이 사건 을 촉발 할 때 만 귀속 을 취소 하면 됩 니 다.
    다음 과 같이 구현:
    
    {
     /**
      *             
      * 
      * @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 + '' !== 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;
     },
     /**
      *     
      * 
      * @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 등 방법 으로 계승 하면 된다 는 뜻 이다.하지만 사건 의 저장 대상 을 확보 해 야 합 니 다이 벤트 는 인 스 턴 스 를 직접 불 러 와 야 합 니 다.이 점 은 계승 할 때 자바 스 크 립 트 에서 계승 을 실현 하 는 방안 이 너무 많 습 니 다.
    위 에 달력 컨트롤 Calendar 에 이벤트 메커니즘 을 추가 하면 Calendar 에서 사용 할 수 있 습 니 다.
    달력 개발 시 달력 의 셀 렌 더 링 을 할 때 cellRender 이 벤트 를 촉발 합 니 다.
    
    //               
    var renderEvent = this.fire('cellRender', {
     //        
     date: date.format('YYYY-MM-DD'),
     //    iso  
     isoWeekday: day,
     //   dom
     el: this.el,
     //      
     tdEl: td,
     //     
     dateText: text.innerText,
     //   class
     dateCls: text.className,
     //         html
     extraHtml: '',
     isHeader: false
    });
    이벤트 에서 저 희 는 현재 렌 더 링 된 날짜,텍스트 class 등 정 보 를 사용자 에 게 제공 합 니 다.그러면 사용 자 는 이 사건 을 연결 하고 이 사건 에서 자신의 개성 아 화 처 리 를 할 수 있 습 니 다.
    렌 더 링 을 할 때 주말 이면'가짜'표 지 를 삽입 하고 날 짜 를 빨간색 으로 표시 합 니 다.
    
    var calendar = new Calendar();
    calendar.on('cellRender', function (e) {
     if(e.isoWeekday > 5 ) {
      e.extraHtml = '<span> </span>';
      e.dateCls += ' red';
     } 
    });
    컨트롤 에서 이벤트 체 제 를 사용 하면 개발 을 간소화 하고 절 차 를 통제 하기 쉬 우 며 실제 사용 할 때 매우 풍부 한 맞 춤 형 조작 을 제공 할 수 있 으 니 빨리 사용 하 세 요.
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기