April 24, 2021
목차
1. aside 부분 돔 구현
2. 댓글 추가, 삭제 및 좋아요 기능
3. 게시글에 좋아요 누르기
4. nav에 아이디 검색 기능
5. 후기
4월 12일부터 위코드 부트캠프 생활을 시작했다 !
바닐라 자바스크립트로 인스타그램 로그인페이지와 메인페이지를 만들었다.
다음주 3주차에는 인스타그램을 리액트를 이용해서 다시 구현해볼 것이다.
오른쪽 aside부분 프로필 리스트 추가 시 객체들의 배열을 만들고 배열을 반복하면서 돔을 그려나갔다. API를 받아와서 처리할 때 객체와 배열 사용에 익숙해져야 해서 하드코딩을 지양하고 유지보수, 확장성이 용이하게 만들려고 노력했다 !
const users = [
{ id: 'jiyon', img: './images/hao.jpg' },
{ id: 'Shaman_king', img: './images/hao2.jpg' },
{ id: 'iu', img: './images/iu.jpg' },
{ id: 'Jeon_dongseok', img: './images/dongseok.jpg' },
{ id: 'kakashi', img: './images/kakashi.png' },
{ id: 'gaara', img: './images/gaara.jpg' },
{ id: 'hyoshin', img: './images/hyoshin.jpeg' },
{ id: 'lock-li', img: './images/lock-li.jpg' },
{ id: 'naruto', img: './images/naruto.jpg' },
]
const userIds = users.reduce((pre, cur) => {
return [...pre, cur.id]
}, [])
const userImgs = users.reduce((pre, cur) => {
return [...pre, cur.img]
}, [])
const createProfileLists = (dom, imgsrc, profileName, postedTime) => {
const asideMain = document.querySelector(`${dom} .asideMain`)
const imgAndId = document.createElement('li')
const asideProfileImg = document.createElement('img')
const idAndTime = document.createElement('div')
const profileId = document.createElement('div')
const postTime = document.createElement('div')
imgAndId.classList.add('imgAndId')
asideProfileImg.classList.add('asideProfileImg')
idAndTime.classList.add('idAndTime')
profileId.classList.add('profileId')
postTime.classList.add('postTime')
postTime.classList.add('grey')
idAndTime.append(profileId)
idAndTime.append(postTime)
imgAndId.append(asideProfileImg)
imgAndId.append(idAndTime)
asideMain.append(imgAndId)
profileId.textContent = profileName
postTime.textContent = postedTime
asideProfileImg.setAttribute('src', imgsrc)
}
users.forEach(user => {
createProfileLists('.story', user.img, user.id, '20분 전')
})
users.forEach(user => {
createProfileLists('.recommend', user.img, user.id, '000님이 팔로우합니다.')
})
forEach 메소드로 users 객체를 돌면서 createProfileLists함수를 실행시켜서 돔을 그려냈다.
postCommentBtn.addEventListener('click', () => {
clickCommentBtn()
})
postCommentInput.addEventListener('keyup', e => {
postCommentInput.value.length > 0
? postCommentBtn.classList.add('blue')
: postCommentBtn.classList.remove('blue')
if (e.keyCode !== 13) {
return
} else {
clickCommentBtn()
}
})
const clickCommentBtn = () => {
if (postCommentInput.value.length == 0) {
return
}
const commentWrap = document.createElement('div')
const commenter = document.createElement('span')
const comment = document.createElement('span')
const commentDeleteBtn = document.createElement('button')
const commentLikesBtn = document.createElement('button')
commentWrap.classList.add('commentWrap')
commenter.classList.add('commenter')
comment.classList.add('comment')
commentDeleteBtn.classList.add('commentBtn')
commentDeleteBtn.classList.add('commentDeleteBtn')
commentLikesBtn.classList.add('commentBtn')
commentLikesBtn.classList.add('commentLikesBtn')
commentWrap.append(commenter)
commentWrap.append(comment)
commentWrap.append(commentDeleteBtn)
commentWrap.append(commentLikesBtn)
articleComment.append(commentWrap)
commentDeleteBtn.innerHTML = `<i class="far fa-trash-alt"></i>`
commentLikesBtn.innerHTML = `<i class="emptyHeart far fa-heart"></i>
<i class="redHeart fas fa-heart red hide"></i>`
commenter.textContent = 'Shaman_king'
comment.textContent = postCommentInput.value
postCommentInput.focus()
commentTime.textContent = '방금'
postCommentBtn.classList.remove('blue')
postCommentInput.value = ''
commentLikesBtn.addEventListener('click', e => {
let emptyHeart = e.currentTarget.querySelector('.emptyHeart')
let redHeart = e.currentTarget.querySelector('.redHeart')
emptyHeart.classList.toggle('hide')
redHeart.classList.toggle('hide')
})
const commentDeleteBtns = document.querySelectorAll('.commentDeleteBtn')
commentDeleteBtns.forEach(commentDeleteBtn => {
commentDeleteBtn.addEventListener('click', () => {
commentDeleteBtn.parentNode.remove()
})
})
}
pushLike.addEventListener('click', e => {
e.preventDefault()
if (pushLike.style.backgroundPosition.slice(0, 4) === '-156') {
pushLike.style.backgroundPosition = `-130px -478px`
likeNum.textContent = Number(likeNum.textContent) + 1
} else {
pushLike.style.backgroundPosition = `-156px -478px`
likeNum.textContent = Number(likeNum.textContent) - 1
}
})
const createSearchLists = searchInputValue => {
if (searchPopup.childNodes.length > 0) {
return
}
const searchedList = document.createElement('li')
const profileImg = document.createElement('img')
const idAndNickname = document.createElement('div')
const userid = document.createElement('div')
const nickname = document.createElement('div')
userid.textContent = searchInputValue
let userIdIndex = userIds.indexOf(searchInputValue)
profileImg.setAttribute('src', users[userIdIndex].img)
// ----------------------------------------
// ex) iu의 위치를 받아서 그 위치의 이미지를 넣어줬다.
// setAttribute를 처음 사용해보았다.
// ----------------------------------------
idAndNickname.append(userid)
idAndNickname.append(nickname)
searchedList.append(profileImg)
searchedList.append(idAndNickname)
searchPopup.append(searchedList)
}
navSearch.addEventListener('input', e => {
if (e.target.value.length === 0) {
searchPopup.innerHTML = ''
} else {
for (i = 0; i < userIds.length; i++) {
if (userIds[i].startsWith(e.target.value)) {
createSearchLists(userIds[i])
break
} else {
searchPopup.innerHTML = ''
}
}
// ------------------------------------------------
// forEach 사용시 break 가 되지 않아서 for loop을 돌렸다.
// ------------------------------------------------
}
})
navSearch.addEventListener('blur', () => {
searchPopup.innerHTML = ''
})