바닐라 자바스크립트로 구현한 나름 첫 프로젝트! 이자 첫 클론코딩... 배운 것도 많고 너무너무너무x999 재밌었다🥳💃👏🎉💖✨✨✨
▶ 목차
🪐 1. id & password 타이핑 시 효과들
🪐 2. id, password Validation
🪐 3. 검색창 선택 시 아이콘 & 글자 이동
🪐 4. 댓글 추가, 좋아요, 삭제 (🌟로그인 시 입력한 id로 댓글 달기!🌟)
🪐 5. 게시물 좋아요 (클릭시 애니메이션)
🪐 6. id 검색 기능
🪐 7. 인스타 스토리 바
🪐 8. 스크린 이미지 전환
처음에는 input의 attribute인 placeholder로 텍스트를 넣고 input이 입력되면 자바스크립트로 css를 조작해서 구현하려고 했는데, placeholder는 타이핑을 하면 사라져버렸다. 뭔가 display나 visiblity 값을 바꿔 보면 되지 않을까...? 했는데 잘 안 돼서 다른 방법으로 접근했다.
<div> <input type="text" id="id" name="id"> <label for="id">전화번호, 사용자 이름 또는 이메일</label> </div>
input 아래에 placeholder 대신 label로 텍스트를 넣고,
position:absolute
로 글자가 input 안에 들어가게 위치를 조정했다. absolute가 작동하게 하기 위해서 input과 label을 감싸는 div를 만들어position: relative
를 지정함!
const idLabel = document.querySelectorAll('.login label')[0], pwLabel = document.querySelectorAll('.login label')[1]; function typeId() { id.classList.add('typing') idLabel.classList.add('typing'); if(!id.value) { id.classList.remove('typing') idLabel.classList.remove('typing'); } } id.addEventListener('input', typeId);
그리고 querySelector로 input 폼과 lable을 잡아서 input 이벤트 발생시마다 'typing'이라는 클래스명이 있는지 검사해서 있으면 추가하고, 없으면 제거했다.
css에서 typing 클래스를 선택해 position, padding, font-size 설정해 주면 끝. 로그인 버튼 활성화도 같은 방법으로 구현!
그 다음 살짝 다른 비밀번호 표시 버튼. 이건 css style 값을 변경하는 게 아니라 input의 attribute인 type의 값을 변경해야 하기 때문!
function showAndHide() { if(pw.type === "password") { pw.type = "text"; showPw.innerHTML = "숨기기"; } else { pw.type = "password"; showPw.innerHTML = "비밀번호 표시"; } } showPw.addEventListener('click', showAndHide);
클릭할 때마다 if 조건을 걸어 type이 password면 text로, text면 password로 바꾸면서 버튼의 텍스트도 바뀌게 했다.
나는 id에는 문자(영문, 숫자, 언더바)만 들어가도록, 비밀번호는 'wecode'로 validation의 조건을 잡았다. 파이썬에서 살짝 공부했던 정규표현식으로... 문자가 아닌 것과 매치되는 변수를 생성함.
const validId = /\W/
그리고 exec메서드로 id에 문자가 아닌 값이 있다면, 또는 패스워드가 'wecode'가 아니라면 빨간 글씨가 생기는 로직을 짰다.
if((validId.exec(id.value)) || (pw.value !== 'wecode')) { const invalid = document.querySelector(".invalid"); const invalidMessage = document.createElement('p'); invalidMessage.innerHTML = "아이디는 영문, 숫자, '_'로 구성되어야 합니다.<br />패스워드는 'wecode'입니다."; invalid.appendChild(invalidMessage); }
근데 form이다보니까 자꾸 value가 submit되면 뭘 하기도 전에 다음 페이지로 넘어가 버려서 고생함😫 (다음 페이지는 form의 attribute인 action에 url을 넣어 주면 연결된다)
뭔가 preventDefault()로 될 것 같았는데 이건 새로고침은 막되 submit 자체는 실행하는...? 그런 메서드라고 한다.집념의 구글링 결과! html form태그에 onsubmit이라는 attribute를 주고, 그 값으로 return 함수()를 설정해서 함수의 리턴값이 false면 submit이 실행되지 않는다고 한다. 짱신기~~~
그래서 html에서 form을 아래처럼 수정하고<form action="./feed.html" onsubmit="return checkValidation()">
자바스크립트에 checkValidation이라는 함수를 선언하면서 if 조건에 걸릴 경우 false를 리턴하도록 했다.
function checkValidation() { if((validId.exec(id.value)) || (pw.value !== 'wecode')) { const invalid = document.querySelector(".invalid"); const invalidMessage = document.createElement('p'); invalidMessage.innerHTML = "아이디는 영문, 숫자, '_'로 구성되어야 합니다.<br />패스워드는 'wecode'입니다."; invalid.appendChild(invalidMessage); return false; } }
근데 여기서 또 발생한 문제... 유효하지 않은 아이디나 패스워드를 입력하고 submit을 시도할 때마다 저 함수가 실행되면서 경고 메세지 밑에 경고 메세지를 중복으로 계속 append했다. 그래서 create&append 전 단계에 조건문을 하나 더 추가해서, invalid라는 클래스를 가진 div 안에 p element가 없을 경우에만 저 메세지를 생성하도록 수정함! 그래서 유효성 검사를 통과 못해도 경고 메세지가 이미 있으면 아무것도 하지 않고 false만 리턴하게 했다.
function checkValidation() { if((validId.exec(id.value)) || (pw.value !== 'wecode')) { const invalid = document.querySelector(".invalid"); if(invalid.querySelector("p") === null) { const invalidMessage = document.createElement('p'); invalidMessage.innerHTML = "아이디는 영문, 숫자, '_'로 구성되어야 합니다.<br />패스워드는 'wecode'입니다."; invalid.appendChild(invalidMessage); return false; } return false; } }
자바스크립트 없이 순수 CSS로 구현한 효과들! 가상 클래스인 :focus가 매우 매우 유용했다.
일단 html로 틀을 잡아 놓고,
<form class="search"> <input type="text" placeholder="검색"><i class="fas fa-search"></i> <div class="searchList"> </div> </form>
css에서 placeholder를 디폴트 스타일/input이 포커스될 때 스타일으로 나누어 다음과 같이 설정했다.
.search input::placeholder { color: #9BA2AE; text-align: center; } .search input:focus::placeholder { text-align: left; }
문제는 돋보기 아이콘은 어떻게 옮기느냐...! '.search input:focus .fa-search' 이런 식으로 시도해 봤는데, 돋보기는 input의 자식 요소가 아니기 때문에 input이 focus될 때 따로 선택할 수는 없는 것 같았다. :focus 가상클래스와 함께 선택할 수 있는 건 자기 자신이나 자식 요소만 되는 듯?
그래서 검색해 보니 focus 말고도
:focus-within
이라는 가상 클래스가 또 있었다. 이건 자손 요소 중 하나가 focus되면 부모 요소를 focus된 걸로 치는(선택하는) 가상 클래스.. 라고 이해함...ㅎㅎ 암튼 이걸 input과 검색 아이콘의 공통부모인 .search에 걸고, 그 뒤에 아이콘의 클래스(fa-search)를 넣으니까 설정이 먹혔다~~~🥳🥳그래서 검색 아이콘에도 디폴트 스타일 외에 아래처럼 .search의 자식인 input이 포커스 되었을 때 스타일을 지정해 줌!
.fa-search { position: absolute; top: 10px; left: 32%; color: #9BA2AE; font-size: 11px; } .search:focus-within .fa-search { left: 4%; }
- 우선 댓글창을 감싼 전체 form을 쿼리스트링으로 선택하고, 해당 요소에 submit 이벤트 시 handleSubmit이라는 함수가 실행되도록 했다.
const commentForm = document.querySelector(".comments form"); commentForm.addEventListener("submit", handlesubmit);
- 다음으로 handleSubmit이라는 함수에 e.preventDefault()를 넣어서 submit해도 창이 새로고침되지 않도록 만들고, input value를 인자로 댓글 요소를 추가하는 leaveaComment 함수를 호출했다. 그 뒤에 input의 value를 빈 스트링("")으로 만들어서 댓글을 달면 댓글창이 다시 비워지도록 만들었다.
function handlesubmit(e) { e.preventDefault(); const currentValue = comment.value; leaveaComment(currentValue); comment.value = ""; }
- 마지막으로 leaveaComment 함수에
- 댓글을 구성하는 div, p를 createElement로 만들고
- 각 요소들에 각자 스타일을 준 클래스명을 부여하고
- 입력받은 input vlaue를 p의 innerHTML로 지정했다!
근데 댓글을 달 때! 이전 로그인 페이지에서 사용자가 입력한 id값을 계정으로 주고 싶었다. 같은 페이지에서 입력한 input value는 가져올 수 있는데, 이전 페이지에서 넘어온 value도 받아올 수 있지 않을까...? 했는데 아무리 구글링해 봐도 못 찾음 🤒
근데 어쨌든 submit을 했으니까 어딘가엔 제출됐겠지! 싶어서 혼자 고민하다 document를 파헤쳐 보기로 했다. 메인 페이지에서 개발자 도구로 콘솔창을 켜서 dir(document)을 찍었더니...
이런게 나왔다.ㅎㅎ;;;;;;
천천히 탐색한 결과...... location 안에 search라는 키값으로 쿼리스트링 정보가 들어 있었음!
전체 쿼리스트링에서 id value만 추출하기 위해서 일단 저걸 inputValue라는 변수에 담고, slice 메서드로 4번째부터('?id=' 뒤) & 전까지 잘라냈다.
const inputValue = document.location.search; const inputId = inputValue.slice(4, inputValue.indexOf('&'));
그리고 이걸 아이디 요소의 innerHTML로 넣었더니 입력한 아이디로 댓글이 달렸다>0<!!!!!! 너무 재밌고 신기~~~
와우 도은님 인스타를 똑 뗴오셨네요 !