반응형

 

갑자기 부캠 프로젝트에서 시간 문제로 미완성 했었던

drag and drop 크기 변경 기능을 한번 구현해보고 싶어서 잠깐 해보았다.

 

레이아웃 틀만 잡아주고 팀원에게 넘기고 다른곳으로 넘어간곳이라 새로운 기능 추가가 어떤 사이드 이펙트를 낳을지 몰라 무섭긴 하지만... 프로젝트도 종료되었고 drag and drop 연습겸 해보았다!

 

기본 원리

const PAGEVW = 100;
const OPENSIZE = 82;
const SIDEBARSIZE = 18;
const CLOSEDSIZE = 61;

export const sizestate = atom<number>({
  key: 'sizeState',
  default: OPENSIZE,
});

구현할때 왼쪽부터 차례대로 Channels, Workspace(chat), Thread(reply)라고 나눴었고.

 

전체 width를 100(%)이라고 했을때

댓글창이 안열려 있다면 workspace의 width가 82(%)이고 channel이 18(%),

열려있다면 workspace의 width가 61(%)이고 나머지가 reply(21%) 창과 channel이 18(%)이 되도록 구현해놓은 상태였다.

 

그리고 위에서 구한 값을 recoil에 넣어 전역으로 관리했고, styled-component에 props로 넣어 각 화면의 width를 비율대로 맞추게 했다.

 

// workspace 길이 
export const mainWorkspaceSizeState = selector<number>({
  key: 'mainWorkspaceSizeState',
  get: ({ get }) => {
    const { isOpened } = get(replyToggleState);
    const OPENEDSIZE = get(sizestate);

    if (isOpened) return CLOSEDSIZE;
    return OPENEDSIZE;
  },
});

//reply 길이
export const replyWorkspaceState = selector<number>({
  key: 'replyWorkspaceSizeState',
  get: ({ get }) => {
    const { isOpened } = get(replyToggleState);

    if (!isOpened) return 0;

    const size = PAGEVW - get(mainWorkspaceSizeState) - SIDEBARSIZE;
    return size;
  },
});

(위 코드는 workspace 의 width를 기준으로 reply 창이 열렸을때, 안열렸을때 recoil의 selector를 이용해 각각 길이를 계산해주는 코드이다.)

 

그렇다면 여기서 넣어줄 기능은 drag and drop으로 동적으로 width를 변경할 수 있는 코드만 넣으면 되는데...

 

다음 방식을 사용했다.

 

저 빨간 선(div)를 구현한 코드는 다음과 같다.

 

import React from 'react';
import { useSetRecoilState } from 'recoil';
import { widthSizeState } from '@state/workspace';

import Container from './styles';

const DraggableDiv = (): JSX.Element => {
  const setWidthSize = useSetRecoilState(widthSizeState);

  const dragEventHandler = (e: React.DragEvent) => {
    const { target } = e;
    const { parentNode } = target;

    const parentBox = parentNode.getBoundingClientRect();
    setWidthSize(Math.max(47, (e.clientX / parentBox.width) * 100 + 1));
  };

  return <Container draggable="true" onDragEnd={dragEventHandler} />;
};

export default DraggableDiv;

원리는 상당히 간단하다.

 

drag 하고 마우스를 놨을때 drag가 끝난 점의 좌표를 계산해 넣어준다.

클릭한 점의 X 좌표를 빨간선 div의 부모 width로 나누고 100을 곱하면 백분위가 되는데

왜냐하면 전체 박스 길이(width)에서 맨 왼쪽을 기준으로 오른쪽만큼 간게 e.clientX가 되므로

단순히 나눠주고 100을 곱하면 백분위가 된다.

 

참고) draggable 이 달려있는게 빨간선이다.

 

그렇게 구한 값을 recoil에 적용해주면 workspace의 width이고, selector를 통해 reply의 크기가 자동으로 반영되므로 

화면의 크기를 동적으로 바꿀 수 있게된다.

 

 

channel도 동일하게 drag and drop을 붙일 수 있는데 노가다의 문제이므로 

drag and drop을 써본거에 만족하고 끝내려 한다. 

 

(구현하려면 DraggableDiv에서 setRecoilValue만 바꿔주면 되는데 위에서 주입하거나 view와 logic을 분리해서 구현하면 될꺼같다?)

반응형

'Front-end > React' 카테고리의 다른 글

react 17(개인 공부용)  (1) 2022.06.09
React18(개인 공부 메모용)  (0) 2022.06.09
react TMI  (0) 2022.04.13
redux, redux-saga로 로딩, 에러 페이지 구현  (0) 2022.02.12
redux 기본 구조  (0) 2022.02.02

+ Recent posts