[js] 이벤트 타겟이 아닌 요소에 이벤트 발생시키기

·2024년 9월 27일
0

개발 기록

목록 보기
66/68
post-thumbnail

구현해야 할 기능

  • 배경으로 깔려있는 이미지의 위치를 드래그해서 이동할 수 있어야 한다.

구현

두 요소가 겹쳐져 있어 배경 이미지는 클릭 이벤트가 발생할 수 없다. 하지만 이미지 위치를 조정하기 위해선 이미지에 드래그 이벤트를 발생시켜야 한다.

최상위 컨테이너 요소에 마우스 클릭 이벤트가 발생하면 배경 이미지에 드래그 이벤트를 발생시키면 될 것 같았다.

찾아보니 자바스크립트는 커스텀 이벤트를 생성하고 수동으로 이벤트를 발생시킬 수 있다. 🧐

커스텀 이벤트 생성

드래그 이벤트를 생성해 준다. 이때 이벤트 객체도 직접 넣어줘야 한다.
이미지 위치를 옮기기 위해서 필요한 값들을 마우스(터치) 이벤트 객체에서 뽑아내서 전달했다.

  const createCustomDragEvent = (
    event: MouseEvent | DragEvent | TouchEvent,
    eventType: 'dragstart' | 'dragover' | 'drop',
    dataTransfer: DataTransfer,
  ) => {
    let clientY;
    let clientX;

    if (event instanceof MouseEvent) {
      // 마우스 이벤트인 경우
      clientY = event.clientY;
      clientX = event.clientX;
    } else {
      // 터치 이벤트인 경우
      const touch = event.touches[0] || event.changedTouches[0];
      clientY = touch?.clientY;
      clientX = touch?.clientX;
    }

    return new DragEvent(eventType, {
      bubbles: true,
      cancelable: true,
      clientY,
      clientX,
      dataTransfer,
    });
  };

수동으로 이벤트 발생시키기

	const dataTransfer = new DataTransfer();

    dropzone.addEventListener('mousedown', (e) => {
      const dragStartEvent = createCustomDragEvent(
        e,
        'dragstart',
        dataTransfer,
      );
      draggableImage.dispatchEvent(dragStartEvent);
    });

    draggableImage.addEventListener('dragstart', handleDragStart);

컨테이너 요소(=dropzone)에 mousedown 이벤트가 발생하면 draggableImage 요소에 dragStart 이벤트가 발생한다.

이미지를 이동하기 위해 dragstart, dragover, drop 이렇게 세 가지 이벤트를 사용해야 해서 동일한 방법으로 커스텀 이벤트를 수동으로 발생시켰다.

	// PC를 위한 마우스 이벤트
    dropZone.addEventListener('mousedown', (e) => {
      const dragStartEvent = createCustomDragEvent(
        e,
        'dragstart',
        dataTransfer,
      );
      draggableImage.dispatchEvent(dragStartEvent);
    });

    document.addEventListener('mousemove', (e) => {
      const dragOverEvent = createCustomDragEvent(e, 'dragover', dataTransfer);
      dropZone.dispatchEvent(dragOverEvent);
    });

    document.addEventListener('mouseup', (e) => {
      const dropEvent = createCustomDragEvent(e, 'drop', dataTransfer);
      dropZone.dispatchEvent(dropEvent);
    });

	// 모바일을 위한 터치 이벤트
    dropZone.addEventListener(
      'touchstart',
      (e) => {
        if (e.target === dropZone || dropZone.contains(e.target as Node)) {
          e.preventDefault();
        }

        const dragStartEvent = createCustomDragEvent(
          e,
          'dragstart',
          dataTransfer,
        );
        draggableImage.dispatchEvent(dragStartEvent);
      },
      { passive: false },
    );

    document.addEventListener(
      'touchmove',
      (e) => {
        if (e.target === dropZone || dropZone.contains(e.target as Node)) {
          e.preventDefault();
        }

        const dragOverEvent = createCustomDragEvent(
          e,
          'dragover',
          dataTransfer,
        );
        dropZone.dispatchEvent(dragOverEvent);
      },
      { passive: false },
    );

    document.addEventListener('touchend', (e) => {
      const dropEvent = createCustomDragEvent(e, 'drop', dataTransfer);
      dropZone.dispatchEvent(dropEvent);
    });

	//이미지 위치를 이동하는 드래그 이벤트
    draggableImage.addEventListener('dragstart', handleDragStart);
    dropZone.addEventListener('dragover', handleDragOver);
    dropZone.addEventListener('drop', handleDrop);

0개의 댓글