- 인스타그램의 로그인 페이지 및 피드 화면(페이지)를 최대한 동일하게 구현하고,
javascript를 통해 일부 기능 구현해보기
: 최대한 Relative Unit을 적용하여 창 크기에 맞게 사이즈 자연스럽게 변화하도록 구현
: box-shadow 적용을 통해 box 그림자 효과 적용
: input 란에 글자 입력되면, 버튼 활성화 및 background color 변화
: 이메일 형식(@ 포함 등ㅇ) 맞고, 비밀번호는 최소 5이상의 숫자 또는 문자만 입력하도록 유효성 체크
: 유효성 통과 or 미통과에 따른 메세지 alert 창으로 보여주기
function validate(e) {
e.preventDefault();
const valEmail = document.querySelector('.email').value;
const valPwd = document.querySelector('.password').value;
console.log(valPwd);
if (valEmail) {
const regExp = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/i;
valEmail.match(regExp)
? alert('유효한 이메일 주소입니다.')
: alert('올바른 이메일 주소를 입력해주세요');
if (valPwd) {
// 5자이상 숫자 또는 영자
const regExp = '^[a-zA-Z0-9]{5,}$';
valPwd.match(regExp)
? alert('유효한 패스워드 입니다.')
: alert('올바른 패스워드를 입력해주세요');
}
} else {
alert('이메일 주소를 입력해주세요.');
}
}
input.addEventListener('click', validate);
: 우상단 nav, 좌측 feed 영역, 우측 추천 프로필 영역으로 나누어 구현
: relative unit을 통해 반응형에 대응
: 신규 댓글 작성후 게시 버튼 클릭하면 하단에 표시
: 동시에 우측 '좋아요' 및 '삭제' 버튼 기능 구현
const feeds = document.querySelector('.feeds');
const input = document.querySelector('.postingCmt');
const button = document.querySelector('#post');
function addPost() {
const cmtText = input.value;
const newCmt = document.createElement('p');
const likeImg = document.createElement('img');
const likeCount = document.createElement('span');
const removeCmt = document.createElement('button');
if (cmtText) {
likeImg.src = '/img/heart.png';
removeCmt.innerText = '삭제';
newCmt.classList.add('newCmt');
newCmt.innerText = cmtText;
newCmt.appendChild(removeCmt);
newCmt.appendChild(likeCount);
newCmt.appendChild(likeImg);
feeds.appendChild(newCmt);
input.value = '';
// 댓글 좋아요 기능 추가(토글 버튼 방식)
const likes = document.querySelectorAll('.newCmt img');
let likeFlag = false;
function likeChange() {
if (!likeFlag) {
this.src = '/img/heartRed.png';
likeFlag = !likeFlag;
} else {
this.src = '/img/heart.png';
likeFlag = !likeFlag;
}
}
likes.forEach((like) => {
like.addEventListener('click', likeChange);
});
// 댓글 삭제 기능 추가
const removeCmts = document.querySelectorAll('.newCmt button');
function deleteCmt() {
this.parentNode.remove();
}
removeCmts.forEach((rmcmt) => {
rmcmt.addEventListener('click', deleteCmt);
});
} else return;
}
button.addEventListener('click', addPost);
: 중앙 상단 검색 창에 찾고자 하는 id 입력하면, 해당 검색어를 포함하는 프로필 list를 표시
: 결과 리스트를 보여주는 container 위치는 창 크기 변경 등에 영향 받지 않도록 구현
// 검색 창 아이디 검색 기능
const ids = [
'wecode',
'jung',
'hyun',
'we',
'code',
'dasom',
'cheerup',
'letsgo',
'wework',
];
const search = document.querySelector("input[type ='search']");
const nav = document.querySelector('.navContainer nav');
function findId(e) {
if (e.keyCode == 13) {
const targetId = search.value;
const result = ids.filter((id) => id.includes(targetId));
const listContainer = document.createElement('div');
listContainer.classList.add('listContainer');
if (targetId && result[0]) {
for (var i = 0; i < result.length; i++) {
const matchedList = document.createElement('p');
const profileImg = document.createElement('img');
matchedList.classList.add(`matchedIdName`);
matchedList.innerText = result[i];
profileImg.src = '/img/profile.jpeg';
listContainer.appendChild(profileImg);
listContainer.appendChild(matchedList);
}
nav.appendChild(listContainer);
const coordinate = this.getBoundingClientRect();
const targetBottom = coordinate.bottom;
const targetLeft = coordinate.left;
listContainer.top = `${targetBottom + 20}px`;
listContainer.left = targetLeft;
} else {
alert('검색하신 ID가 존재하지 않습니다.');
}
} else return;
}
search.addEventListener('keydown', findId);
search.addEventListener('blur', () => window.location.reload());
: 우측 상단 nav 프로필 사진 클릭 시 메뉴 표시
: 새로 보여지는 메뉴 container는 창 크기 변경에 영향 받지 않도록 구현
// nav 프로필 사진 클릭 시 메뉴 박스 생성 (Mission 8)
const navProfile = document.querySelector('#profileImg');
const menuContainer = document.querySelector('.menuContainer');
const body = document.querySelector('body');
function showMenu(e) {
if (e.target == navProfile) {
const coordinate = this.getBoundingClientRect();
const targetBottom = coordinate.bottom;
const targetLeft = coordinate.left;
menuContainer.top = `${targetBottom + 20}px`;
menuContainer.left = targetLeft;
menuContainer.style.display = 'block';
} else {
menuContainer.style.display = 'none';
}
}
body.addEventListener('click', showMenu);
: css media query 기능을 이용하여, 창 너비가 800 px 이하로 떨어지면, 우측 추천 프로필 영역 숨기기
/* width가 800px 이하로 떨어지면 우측 박스(.main-right) 사라짐 */
@media screen and (max-width: 800px) {
.mainRight {
display: none;
}
.mainLeft {
width: 100%;
}
}