일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- CRUD
- mybatis
- JDBC
- git revase
- react
- MVC
- WHEREIN
- SQL
- HTML
- git reset
- passwordencoder
- assertequals
- git
- JavaScript
- PathVariable
- 부적합한열
- Spring
- git amend
- Variabla
- 배열
- localStorage
- BCryptPasswordEncoder
- useContext
- content-box
- Thymeleaf
- Java
- oracle
- ResultType
- springboot
- 이딴게개발자
- Today
- Total
개발새발
[JavaScript] localStorage를 이용한 사진 업로드. 근데 이제 팝업창을 곁들인 본문
1. 어떤 프로그램을 만들 것인가?
메인화면에서 팝업창으로 이동해 사진을 선택하면 메인화면에 사진이 업로드 되는 프로그램
(마치라잌 프로필사진 변경)
2. 어떻게 구현할 것인가?
- 메인화면에서 '사진변경' 버튼을 누르면 팝업창이 활성화 된다
- 팝업창 내에서 파일선택을 가능하게 하고, 선택한 사진의 썸네일을 확인한다
- 팝업창 내에서 저장 버튼을 누르면 메인화면에 저장이 된다
3. 코드를 만들어보자!
0) 메인화면 구현
<!DOCTYPE html>
<html>
<head>
<title>이미지 올리기</title>
</head>
<body>
<h1>이미지</h1>
<div id="post-list"></div>
<button id="add-post">이미지추가</button>
</body>
</html>
<div>태그에 저장한 이미지를 추가할 예정이다
아래부터는 쭉 JavaScript
1) 이미지추가 버튼을 클릭했을 때 새 창 띄우기 id=add-post
document.getElementById('add-post').addEventListener('click',()=>{
const popupWindow = window.open('','','width=400, height=400');
const popupDocument = popupWindow.document;
});
하지만 팝업창만 띄워놓으면 아무 일도 일어나지 않는다
팝업창 내에서 어떤 작업을 할 수 있도록 구현하는 코드를 추가해주자
2) 팝업창 구현하기
document.getElementById('add-post').addEventListener('click', () => {
const popupWindow = window.open('', '', 'width=400,height=400');
const popupDocument = popupWindow.document;
popupDocument.write('<h2>이미지 업로드</h2>');
popupDocument.write('<input type="file" id="image-upload" accept="image/*"><br>');
//이미지가 업로드 될 공간
popupDocument.write('<img id="image-preview" style="max-width: 100%; max-height: 200px;"><br>');
popupDocument.write('<button id="save-post">저장</button>');
});
사진은 '파일 선택'과 '저장'버튼 사이에 업로드 될 것..
그리고 이제는 만들어진 팝업창에서 원하는 기능을 구현해보자
3) 팝업창에서 파일 선택하고, 선택한 이미지가 보이는 기능
팝업창에서 선택한 파일을 localStorage에 저장해서 메인에 띄우는게 목적이긴 했지만..
그 전에 내가 고른 파일이 생각했던게 맞는지 팝업창 내에서 먼저 확인을 해보기로 하자
(2번의 팝업창 생성 코드와 이어짐)
const imageUploadInput = popupDocument.getElementById('image-upload');
const imagePreview = popupDocument.getElementById('image-preview');
imageUploadInput.addEventListener('change', () => {
const selectedImage = imageUploadInput.files[0];
if (selectedImage) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
};
reader.readAsDataURL(selectedImage);
}
나는 <input type="file"> 태그가 화면상에서 '파일선택'이라는 버튼으로 구현이 되길래,
addEventListener의 이벤트도 click으로 하면 될 줄 알았는데 그건 또 아니더라..;;;
찾아보니
change는 폼 컨트롤(value의 값)의 `값이 변경 되었을 때 발생하는 이벤트로, click과는 용도가 꽤 다른 것을 알 수 있었다.
따라서 input(text,radio,checkbox), textarea, select 태그에 적용된다고... 암튼 버튼의 모양만 하고있을 뿐 버튼의 기능과는 전혀 다른 놈이라고 보면 될 듯하다. 생각해보니까 뭐 선택한 사진(값)이 있어야 그걸 선택한 이미지에 넣든가 하지, 그냥 클릭만 했다고는 실행할 수 없는게 당연하긴 하다 ㅋㅋ
4) 선택한 파일을 localStorage에 저장하기
이제 거의 다옴..
popupDocument.getElementById('save-post').addEventListener('click',() => {
const savedImage = imagePreview.src;
if(savedImage){
const postKey = `post-${Date.now()}`;
const post = {image : savedImage};
localStorage.setItem(postKey,JSON.stringify(post));
//localStorage에 저장 후, 메인 페이지에 바로 게시하는 함수를 실행하자
displayImage();
popupWindow.close();
}
});
localStroge 저장까지는 괜찮은데, 하나 이상한 코드가 있다.
displayImage () ? 이건 또 뭔가? 하면~
우리 목적이 뭐였는가! 팝업창에서 이미지 선택&저장하면 바로 메인에 올라가는 프로그램이었으니...
저장한 놈을 게시할 함수도 필요하겠지?
사실 뭐.. 함수를 쓰지 않고 구구절절하게 이어 쓸 수도 있긴한데 그렇게하면 너무 보기 불편하니까~
일단 저 displayImage()라는 함수로 이미지를 바로 띄울 작정이라고 써놓기만 하기로 하자.
아무튼 이렇게 팝업창을 통해 일어나는 일에 대한 구현은 모두 끝났다.
그래서 2) ~ 4) 까지의 코드를 이어 붙이면
document.getElementById('add-post').addEventListener('click', () => {
const popupWindow = window.open('', '', 'width=400,height=400');
const popupDocument = popupWindow.document;
popupDocument.write('<h2>이미지 업로드</h2>');
popupDocument.write('<input type="file" id="image-upload" accept="image/*"><br>');
popupDocument.write('<img id="image-preview" style="max-width: 100%; max-height: 200px;"><br>');
popupDocument.write('<button id="save-post">저장</button>');
const imageUploadInput = popupDocument.getElementById('image-upload');
const imagePreview = popupDocument.getElementById('image-preview');
imageUploadInput.addEventListener('change', () => {
const selectedImage = imageUploadInput.files[0];
if (selectedImage) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
};
reader.readAsDataURL(selectedImage);
}
});
popupDocument.getElementById('save-post').addEventListener('click', () => {
const savedImage = imagePreview.src;
if (savedImage) {
const postKey = `post-${Date.now()}`;
const post = { image: savedImage };
localStorage.setItem(postKey, JSON.stringify(post));
displayImage();
popupWindow.close();
}
});
});
위와 같은 모양이 나온다 후후.. 매우 길지만 뿌듯하군..
자! 그럼 마지막으로 할 일을 해보자. 그게 뭐냐면..
바로 실행 선언만 해놓고 만들어두지도 않은 함수 구현하기ㅋㅋ 폰함수
displayImage( ) <- 이놈이요. 진짜 만들러 가봅시다
5) 저장 목록을 가져오고 화면에 나타내는 함수 만들기
function displayImage() {
const postList = document.getElementById('post-list');
postList.innerHTML = '';
const key = localStorage.key(0);
if (key.startsWith('post-')) {
const post = JSON.parse(localStorage.getItem(key));
const image = post.image;
const imageElement = document.createElement('img');
imageElement.src = image;
imageElement.alt = '이미지';
postList.appendChild(imageElement);
}
}
아까 html코드에서 이미지가 업로드 될 공간을 <div id="post-list"></div>로 지정해 뒀으니까..
그곳에 <img scr="이미지 주소" alt="이미지설명">을 추가하는 코드를 작성했다.
주소값은 아까 이용한 localStorage에 저장한 이미지의 정보를 통해 작성했다. 그렇게 되면 저장된 이미지도 가져오기 끝
6) 실행?
와! 이제 진짜 코드가 완성이 됐다!!! 한번 실행해보자
<!DOCTYPE html>
<html>
<head>
<title>이미지 올리기</title>
</head>
<body>
<h1>이미지</h1>
<div id="post-list"></div>
<button id="add-post">이미지추가</button>
<script>
// 게시글 목록을 가져오고 화면에 나타내기
function displayImage() {
const postList = document.getElementById('post-list');
postList.innerHTML = '';
const key = localStorage.key(0);
if (key.startsWith('post-')) {
const post = JSON.parse(localStorage.getItem(key));
const image = post.image;
const imageElement = document.createElement('img');
imageElement.src = image;
imageElement.alt = '이미지';
postList.appendChild(imageElement);
}
}
// add-post 버튼을 클릭했을 때 새 창에서 이미지 업로드
document.getElementById('add-post').addEventListener('click', () => {
const popupWindow = window.open('', '', 'width=400,height=400');
const popupDocument = popupWindow.document;
popupDocument.write('<h2>이미지 업로드</h2>');
popupDocument.write('<input type="file" id="image-upload" accept="image/*"><br>');
popupDocument.write('<img id="image-preview" style="max-width: 100%; max-height: 200px;"><br>');
popupDocument.write('<button id="save-post">저장</button>');
const imageUploadInput = popupDocument.getElementById('image-upload');
const imagePreview = popupDocument.getElementById('image-preview');
imageUploadInput.addEventListener('change', () => {
const selectedImage = imageUploadInput.files[0];
if (selectedImage) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
};
reader.readAsDataURL(selectedImage);
}
});
popupDocument.getElementById('save-post').addEventListener('click', () => {
const savedImage = imagePreview.src;
if (savedImage) {
const postKey = `post-${Date.now()}`;
const post = { image: savedImage };
localStorage.setItem(postKey, JSON.stringify(post));
displayImage();
popupWindow.close();
}
});
});
</script>
</body>
</html>
~실행 결과~
7) 문제점
와! 이제 진짜 끝났다! 나 쫌 개쩌는듯ㅋㅋ
.
.
.
하던 찰나에 발견된 문제점 두 가지
<문제 1>
한 번 업로드 된 이미지가 존재하는 이상.. 아무리 새로운 이미지를 업로드해도 기존의 이미지가 계속해서 나타난다
왜 이런 것일까?
바로 localStorage에 기존에 저장한 정보가 계속해서 남아있기 때문이다..!
이를 해결하는 데에는 여러가지 방법이 있을 수 있겠지만, 나는 팝업창에서 '저장'버튼을 누르면 기존에 저장소에 있는 데이터를 먼저 비우는 코드를 추가 해주기로 했다.
이하 코드 모두 동일
그러면 이렇게 새로운 사진이 잘 올라가는 모습을 확인할 수 있다.
해결완료!!!
<문제 2>
창을 새로고침 or 재접속 할 경우, 저장한 이미지가 화면에 나타나지 않는다
이와같은 경우는 사실 문제는 되지 않는다.. 애초에 팝업창에서 선택한 이미지가 메인 화면에 잘 연결이 되게 만들 수 있는가? 가 주된 목적이었기 때문에..
하지만 블로그와같은 곳에서 프로필 사진을 변경하는 상황이라고 생각을 해보자.
사이트에 다시 들어오기만하면 기껏 변경한 프로필 사진이 사라져있다? 얼마나 어이가 없겠는가;;
그럼 뭐 어떻게 하라고
진짜 더도 말고 덜도 말고 코드 딱 한 줄만 추가해주면 된다
스크립트 맨 마지막 줄에 아까 만든 displayImage(); 를 추가하면 끝!
이렇게 되면 사이트에 접속 할 때마다 따로 버튼을 누른다든지 어쩌든지 별 다른 행동을 하지 않아도 그냥 사진이 나타나게 된다. 항상 그 자리에 있던 것처럼... (이때 다른 함수 내에 코드 추가하지 않기 주의)
아무튼 코드를 실행하면
이렇게 창에 들어가자마자 localStorage에 저장된 윈디 사진이 나를 바로 반기는 것을 확인할 수 있다 ㅎㅎ
~최종 코드~
<!DOCTYPE html>
<html>
<head>
<title>이미지 올리기</title>
</head>
<body>
<h1>이미지</h1>
<div id="post-list"></div>
<button id="add-post">이미지추가</button>
<script>
// 게시글 목록을 가져오고 화면에 나타내기
function displayImage() {
const postList = document.getElementById('post-list');
postList.innerHTML = '';
const key = localStorage.key(0);
if (key.startsWith('post-')) {
const post = JSON.parse(localStorage.getItem(key));
const image = post.image;
const imageElement = document.createElement('img');
imageElement.src = image;
imageElement.alt = '이미지';
postList.appendChild(imageElement);
}
}
// add-post 버튼을 클릭했을 때 새 창에서 이미지 업로드
document.getElementById('add-post').addEventListener('click', () => {
const popupWindow = window.open('', '', 'width=400,height=400');
const popupDocument = popupWindow.document;
popupDocument.write('<h2>이미지 업로드</h2>');
popupDocument.write('<input type="file" id="image-upload" accept="image/*"><br>');
popupDocument.write('<img id="image-preview" style="max-width: 100%; max-height: 200px;"><br>');
popupDocument.write('<button id="save-post">저장</button>');
const imageUploadInput = popupDocument.getElementById('image-upload');
const imagePreview = popupDocument.getElementById('image-preview');
imageUploadInput.addEventListener('change', () => {
const selectedImage = imageUploadInput.files[0];
if (selectedImage) {
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
};
reader.readAsDataURL(selectedImage);
}
});
popupDocument.getElementById('save-post').addEventListener('click', () => {
//파일 선택 후 저장 버튼 누르면 원래 localStorage 저장소 내용 삭제
localStorage.clear();
const savedImage = imagePreview.src;
if (savedImage) {
const postKey = `post-${Date.now()}`;
const post = { image: savedImage };
localStorage.setItem(postKey, JSON.stringify(post));
displayImage();
popupWindow.close();
}
});
});
// 초기 게시글 목록 표시
displayImage();
</script>
</body>
</html>
이렇게 길다면 길고, 짧다면 짧은 코드가 완성되었다.
분명 처음 구현할 때는 머리 쥐어뜯으면서 골머리 앓으면서 코드를 짰던 것같은데..
막상 완성된 코드를 계속 쳐다보고 하다보니까 또 별거 아닌 것같기도하고~
(라고 하지만 큰따옴표 하나 발견 못해서 코드 5시간동안 들여다보고 소리지른 사람 여기요)
암튼 사람 맘이라는게 참 이상하다
코딩 개어렵다 포기하고싶을 때마다 하는 생각이 있는데,
바야흐로 6년 전.. R언어를 통해 처음 코딩이라는 것을 접한 내 모습을 생각하면 지금의 나는 엄청 발전했구나싶다.
그 때의 나는 print, scan, cat 어쩌구 문도 이해를 못해서 책 보고 떠듬떠듬 타이핑 하던 사람이었는데 분명,
지금은 기본 문법따위 찾아보지도 않고 휙휙~ 맘대로 쓰고 다룰 수 있는 사람이 되었으니 말이다.
지나고보면 사실 엄청 어려운 개념도 아니었고..
그래서 막히는 부분 때문에 스트레스 받고 불안할 때마다 이런 생각을 하면 조금은 마인드 컨트롤이 된다.
지금 배우는 것도 어려운게 아닌, 단지 어색한 문제일 뿐이라고..!!!
새벽에 주절주절 말이 많아졋네요 ㅎㅋㅋ
근데 이 말은 진짜 항상 마음에 새기고싶어서 괜히 한번 써봄요
근데 아무도 안읽을듯 ㅎ 분명 열려있는 글인데 아무도 도달하지 못하는 곳ㅋㅋ
오늘도 짤과 함께 글을 마무리하며~ 안녕~
'FRONT > HTML_CSS_JS' 카테고리의 다른 글
[JavaScript] localStorage를 이용한 게시글 추가 (1) | 2023.11.02 |
---|---|
[CSS] box-sizing: border-box (1) | 2023.10.30 |