Skip to content

Commit

Permalink
chore: 윈도우 작업본
Browse files Browse the repository at this point in the history
  • Loading branch information
9yurilee committed Dec 26, 2024
1 parent fe4e314 commit 8a4fd71
Showing 1 changed file with 33 additions and 27 deletions.
60 changes: 33 additions & 27 deletions src/lib/eventManager.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
// 1. addEvent와 removeEvent를 통해 element에 대한 이벤트 함수를 어딘가에 저장하거나 삭제합니다.
// 2. setupEventListeners를 이용해서 이벤트 함수를 가져와서 한 번에 root에 이벤트를 등록합니다.

// 이벤트 위임 방식
// "setupEventListeners를 실행하면 addEvent로 저장된 함수들이 root에 register된다!"

// 이벤트 위임을 위한 전역 이벤트 맵
// 이 맵은 이벤트 타입별로 요소와 해당 요소의 이벤트 핸들러를 저장합니다.
// getEventListener의 반환 형태 참고({click: [{type: click, listener: f}, {type: click, listener: f2}]})
// 이벤트 타입별로 요소와 해당 요소의 이벤트 핸들러를 저장
const eventMap = new Map();

let rootElement = null;
Expand All @@ -14,6 +11,7 @@ export function setupEventListeners(root) {
// 1. rootElement 설정
rootElement = root;
// 2. 기존에 설정된 이벤트 리스너 제거 (있다면)

// 3. eventMap에 등록된 모든 이벤트 타입에 대해 루트 요소에 이벤트 리스너 추가
// 주의: 이벤트 캡처링을 사용하여 이벤트를 상위에서 하위로 전파
eventMap.forEach((_, eventType) => {
Expand All @@ -23,19 +21,22 @@ export function setupEventListeners(root) {
}

function handleEvent(e) {
// 이벤트 타겟 식별:
// - `event.target`을 사용하여 실제 이벤트가 발생한 요소를 식별
// - 조건문을 통해 특정 요소나 클래스에 대해서만 이벤트 처리 가능
let target = e.target; // element
let element = e.target;

while (target && target !== rootElement) {
const handlers = eventMap.get(e.type).get(target);
while (element) {
const typeMap = eventMap.get(e.type);
if (!typeMap) return; // 이벤트 타입이 없으면 종료

const handlers = typeMap.get(element);
if (handlers) {
handlers.forEach((handler) => handler(e));
for (const handler of handlers) {
handler(e);
if (e.immediatePropagationStopped) return; // 전파 중단 처리
}
}

target = target.parentNode; // 버블링?
if (element === rootElement) break; // 루트 요소에서 종료
element = element.parentNode; // 상위 요소로 이동
}
}

Expand All @@ -46,32 +47,37 @@ export function addEvent(element, eventType, handler) {
}

const eventTypeMap = eventMap.get(eventType);

if (!eventTypeMap.has(element)) {
eventTypeMap.set(element, new Set()); // handler의 내용은 중복되면 안되므로 set 사용
}

eventTypeMap.get(element).add(handler);
}

// 목적: evnetMap에 저장되어있는 element에 대한 이벤트 함수를 삭제
export function removeEvent(element, eventType, handler) {
// eventMap에 해당 eventType이 있는지 먼저 확인
const eventTypeMap = eventMap.get(eventType);
if (!eventTypeMap) return;
// 타입 : 엘리먼트 => 핸들러
// 타입이 있는지 확인
const elementMap = eventMap.get(eventType);
if (!elementMap) return; // 타입 없으면 종료

// eventMap에서 해당 요소와 이벤트 타입에 대한 핸들러 제거
const handlerSet = eventTypeMap.get(element);
// 엘리먼트 있는지 확인
const handlerSet = elementMap.get(element);
console.log(typeof element);

if (handlerSet) {
handlerSet.delete(handler);
if (handlerSet.size === 0) eventTypeMap.delete(element);
}
handlerSet.delete(handler); // 엘리먼트가 있다면 핸들러 삭제

// 해당 이벤트 타입의 모든 핸들러가 제거되면 루트 요소의 리스너도 제거
// 이를 통해 더 이상 필요 없는 이벤트 핸들러를 정리하고 메모리 누수 방지
if (eventTypeMap.size === 0) {
eventMap.delete(eventType);
if (rootElement) {
rootElement.removeEventListener(eventType, handleEvent);
// 만약 엘리먼트만 있고 핸들러는 없다면 엘리먼트도 삭제할 것 (메모리 및 공간 이슈 방지)
console.log("핸들러 다 삭제 됐을 경우(0)를 찾아라", handlerSet.size);
if (handlerSet.size === 0) {
console.log(element, "를 삭제할고야 => ", elementMap);
elementMap.delete(element);
console.log(element, "를 삭제했지롱", elementMap);
}
}

// 만약 해당 타입에 대한 엘리먼트도 다 삭제 됐다면?
// 리스너도 삭제해야지.
}

0 comments on commit 8a4fd71

Please sign in to comment.