본문으로 바로가기

 

너무 못생겼습니다...

 

input[type="file']을 디자인하기 위해는 input을 아예 숨기고, 붙어 있는 label을 이용해야 합니다.

여기서, 숨긴다고 input에 display:none을 주게 되면 연결된 label까지 없어지게 됩니다.

 

visibility를 hidden으로 준 다음, label을 스타일링하면 되겠습니다.

위치로는 form에 position을 relative로 주고, label을 form 내부에서 position:absolute로 주는 것이 좋겠죠?

 

<form
  encType="multipart/form-data"
  onSubmit={photoChange}
  style={{ position: "relative" }}
>
  <Label htmlFor="file">이미지 변경</Label>
  <input
    type="file"
    name="file"
    id="file"
    accept="image/*"
    style={{ visibility: "hidden" }}
  />
  <input type="submit" />
</form>
const Label = styled.label`
  display: inline-block;
  padding: 0.5em 0.75em;
  color: #999;
  font-size: inherit;
  line-height: normal;
  vertical-align: middle;
  background-color: #fdfdfd;
  cursor: pointer;
  border: 1px solid #ebebeb;
  border-bottom-color: #e2e2e2;
  border-radius: 0.25em;
  position: absolute;
  left: 5.6em;
  margin-top: 1.5em;
`;

 

이제 버튼을 눌러서 이미지 업로드를 할 수 있습니다.

 

 

자, 그런데 문제는 유저의 입장에서는 해당 버튼을 눌러 이미지를 선택하면 자동으로 업로드가 되어야 하는데, 이 당연한 듯한 동작이 위와 기본 적인 코드 상에서는 안된다는 것입니다. 

 

따라서 JS를 통한 DOM 조작을 이용해 강제로 이미지를 제출하도록 만들어야 합니다. 

 

 

 

시도 1) parentNode를 통한 제출

e.target.parentNode.submit();

preventDefault()가 안 된다는 사실을 알고선 우회

 

 

시도 2) 제출 버튼을 작성한 후 nextSibling으로 해당 버튼을 click

 

이 방법은 되더군요. 제출 버튼을 누른 것과 동일하므로 form을 제출했을 때의 로직을 그대로 작성해주시면 됩니다.

여기서 팁이 있다면, visibility: "hidden"이 아니라 display: "none"을 쓰라는 것입니다.

 

visibility를 쓰게 되면 버튼이 사라지긴 하지만 공간은 그대로 차지하고 있기 때문에 작성한 Label의 위치를 css로 재수정해야 합니다. 그러나 display: none을 설정하면 공간까지 깔끔하게 사라집니다.

<input type="submit" style={{ display: "none" }}></input>
const photoChange = (e) => {
  e.target.nextSibling.click();
};

 

 

 

React에서는 useRef를 통해서 입력하고자 하는 input 태그를 ref로 지정해서 가상 클릭을 만들어내면 쉽습니다.

const imageInput = useRef();

const onClickImageUpload = () => {
  imageInput.current.click();
}

<input type="file" multiple hidden ref={imageInput} onChange={onChangeImages} />
<Button onClick={onClickImageUpload}>이미지 업로드</Button>

 

 

시도 3) 아! 이런 현명한 방법이...

 

상당히 시간이 지난 후지만, 그냥 input과 label을 이용할 필요도 없이 예쁘게 button을 만들고, 해당 버튼을 누르면

input 자체를 가상으로만든 후 클릭하게 만들면 되겠다는 생각이 들었습니다.

 

뭘 숨기고 자시고 할 필요도 없이 말이죠. 이게 제일 현명한 방법 같습니다.

 

아래와 같은 방식 말이죠. 이 방법은 다른 프로젝트에서 사용해봐야겠습니다. ㅎ

  const input = document.createElement("input");

  input.setAttribute("type", "file");
  input.setAttribute("accept", "image/*");
  input.click();

 


참고한 글)

 

https://darrengwon.tistory.com/653


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체