개요
저번것에 이어서 문제를 풀어보겠다
이번엔 <이미지 상세 보기 모달 관련> 란의 문제를 풀어보도록 할게요
Q.디바이스 가로 길이가 768px 이하인 경우, 모달의 가로 길이를 디바이스 가로 길이만큼 늘려야 합니다.
모달은 평소에 작게뜨는데, 화면이 많이 작을 경우 모달을 아예 전체 가로에 맞게 띄우라는듯
기존의 크기이다
가로길이 조절하는건 미디어쿼리 이용하면 되겠죠?
/*style.css*/
/* 가로길이가 768px 이하일때*/
@media screen and (max-width: 768px){
.ImageInfo .content-wrapper {
left: 0%;
top: 0%;
transform: translate(0%, 50%);
}
}
이렇게 추가해줘서 기존에 50퍼센트로 모달을 줄이는 요소를 없애줬습니다
대신에 가로길이만 늘려야한다는걸 살려서 transform에서 세로 퍼센트는 유지했어요
Q. (필수) 이미지를 검색한 후 결과로 주어진 이미지를 클릭하면 모달이 뜨는데, 모달 영역 밖을 누르거나 / 키보드의 ESC 키를 누르거나 / 모달 우측의 닫기(x) 버튼을 누르면 닫히도록 수정해야 합니다.
이벤트리스너를 추가해야되는거네요
기존의 imageInfo.js 파일을 보면 아무 이벤트리스너가 등록되어있지않습니다
그래서 질문의 세가지 행동을해도 뭘해도 모달이 닫히질 않습니다 ㅜㅜ ㅎ
하나씩 추가해보죠..
일단 모달이 닫히는 기능을 따로 만들게요
// imageInfo.js
closeModal(){
this.$imageInfo.style.display = "none";
}
일단 class안에 이렇게 메소드를 만들어봤는데 잘 동작될런지?
흠 그런데 저 3가지 조건들을 어디에서 구현해야할지 모르겠네요
1. 모달영역 밖 클릭
2. 키보드 esc keyup
3. 모달 닫기버튼 클릭
3번 말고는 imageInfo에서 안해도될거같은느낌?
그렇다고 아무데서나 하면 완전 중구난방이 되구요
일단 1번을 먼저 구현해볼게요
클릭을 하고 그 상위요소중에 imageInfo가 없으면 닫히도록 하면될거같아요
아무래도 App.js에서 하는게 나을거같습니다
1번을 구현하면서 이전 포스트인 (1)에서도 잘못 구현한 부분이 있어서 함께 고쳤습니다
기존에 closest메소드를 이용하여 searchResult에서 이벤트위임을 구현하였는데요
closest메소드를 이용하게되면 좀더 내부에 있는 요소를 클릭했을때 동작이 제대로 되지않습니다
그래서 상위 요소중에 특정 선택자가 있는지를 찾아내는 함수를 구현하였습니다
// selector.js
export default {
parentFinder($target, selector){
while($target){
if($target.matches(selector)){
return $target
}
if($target.matches("html")){
return null
}
$target = $target.parentNode
}
return null
}
}
해당 함수는 util폴더 안의 selector.js라는 파일을 따로 만들어서 구현했습니다
이 함수를 구현하고 테스트하면서 오래걸린게, 상위요소를 찾다가 없으면 target이 null이 될것이라고 생각했는데
그렇지 않고 html태그를 찾게되고, html태그에서는 matches를 이용할 수 없는 모양입니다
그래서 계속 실패하게되어 결국 html과 매칭되면 끝내도록 추가를 해야 했습니다 (코드가 지저분해진거같아 맘에 쏙들진 않습니다)
어쨋든 이 함수를 이용해서 searchResult.js를 이렇게 바꿨습니다
// searchResult.js
this.$searchResult.addEventListener("click", (e) =>{
e.stopPropagation()
const $item = selector.parentFinder(e.target,'.item')
if($item){
const index = Array.from(this.$searchResult.querySelectorAll(".item")).indexOf($item)
this.onClick(this.data[index])
}
})
그리고 원래 해결하고자했던 1번인 모달 영역 밖을 클릭했을때를 구현했습니다 (App파일에)
// App.js
this.$target.addEventListener("click", (e)=>{
if(this.imageInfo.data.visible){
const $item = selector.parentFinder(e.target, ".content-wrapper")
if(!$item){
this.imageInfo.closeModal();
}
}
})
원래는 찾는 selector로 ImageInfo를 찾았는데, ImageInfo는 화면 전체를 포함하더군요 그래서 모달영역인 content-wrapper로 바꿨습니다
그러면 이제 두가지가 남았군요
2. 키보드 esc keyup
3. 모달 닫기버튼 클릭
그런데 생각해보니
어차피 화면전체가 ImageInfo로 바뀌기때문에
1번과 2번도 모두 ImageInfo로 적용할 수 있다는 것입니다
그래서 1번은 일단 옮겨주었습니다
// imageInfo.js
this.$imageInfo.addEventListener("click", (e)=>{
const $item = selector.parentFinder(e.target, ".content-wrapper")
if(!$item){
this.closeModal();
}
})
3번을 해보겠습니다
3번도 마찬가지로 close가 class인 부모가 있으면 꺼주면 되겠죠
// ImageInfo.js
this.$imageInfo.addEventListener("click", event =>{
const $target = event.target
const $contentWrapper = selector.findSelectorInUpper($target, ".content-wrapper")
if(!$contentWrapper){
this.closeModal();
}
const $close = selector.findSelectorInUpper($target, ".close")
if($close){
this.closeModal()
}
})
더불어 1번에서 풀었던것의 식별자를 조금 바꾸었습니다
나머지 2번이네요
2. 키보드 esc keyup
이게 조금 까다로운게 요소에 초점이 맞춰진 다음에 keyup을 해야 인지를 하는데 그게 잘 안되더라구요
일단 keyup같은 경우 "해당 요소가 키보드 입력을 받을 수 있는 상태"여야지 사용할 수 있다
해당 요소가 키보드 입력을 받을 수 있는 상태로 만드는 방법은 3가지인듯
1. contenteditable 속성을 추가해서 true로 값을 주기
2. 애초에 input이나 textarea, select 태그에서 사용하기
3. focus 함수를 사용해서 초점맞춰주기
일단 1번으로 한번 해봤습니다
그러나 애초에 포커스가 안맞춰있더니 그 영역을 한번 클릭해야하는 번거로움이 있더군요
그렇다고 3번인 focus만 해주면 keyup을 못받아 들입니다
그래서 결국 두개 다 사용하였습니다
// imageInfo.js
this.$imageInfo.setAttribute("contenteditable", "true")
this.$imageInfo.focus();
this.$imageInfo.addEventListener("keyup", event =>{
console.log(event, "keyup")
if(event.key === 'Escape'){
this.closeModal()
}
})
이렇게 닫는 방식 3가지 모두 구현이 끝났네요
생각보다 헤매서 시간이 오래걸렸습니다
+++추가
contenteditable과 focus를 하게되면 모달의 제목에 커서가 나오게되네요
저는 이렇게 해결했습니다
esc이외의 키에 대한 동작을 막고 커서 스타일을 추가하여 투명하게..
// imageInfo.js
this.$imageInfo.addEventListener("keydown", e=>{
if(e.key==='Escape'){
this.closeModal()
} else {
e.preventDefault()
}
})
// style.css
.ImageInfo .content-wrapper {
caret-color: transparent;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border: 1px solid #eee;
border-radius: 5px;
}
Q.모달에서 고양이의 성격, 태생 정보를 렌더링합니다. 해당 정보는 /cats/:id 를 통해 불러와야 합니다.
이건 일단 api를 사용하게 해야겠네요
App파일에다가 구현을 했습니다
// App.js
this.searchResult = new SearchResult({
$target,
initialData: this.data,
onClick: async image => {
await api.fetchCat(image.id).then(({data})=>image=data);
this.imageInfo.setState({
visible: true,
image
});
}
});
그런데 개인적으로 좀 바꾸고싶은 것들이 여러가지 있었어요
저 input으로 들어오는 image에서 id만 받고
api의 출력을 그대로 받아서 그걸 setState에 넣는..
흠 그런데 뭔가 조화를 놓칠까봐 그냥 저렇게 해봤습니다
이렇게 성격이랑 태생이 잘 나오면돼요
Q.추가 모달 열고 닫기에 fade in/out을 적용해 주세요.
이건 열고닫는 효과겠죠? 저도 잘 몰라서 찾아보겠습니다
©TCP-tryWWW
jQuery Fade Animation #divBox { width: 100px; height: 100px; background-color: yellow; border: 5px solid orange; margin-top: 20px; } $(function() { $("#fadeInBtn").on("click", function() { $("#divBox").fadeIn(); // id가 "divBox"인 요소를 점점 나타
www.tcpschool.com
이런거라고하네요 굿!
그런데 여기서 사용하는 fadeIn()과 fadeOut()함수는 jQuery에서 지원해주는 함수라서
javascript를 이용하면 좀 까다롭다는거같아요
흠 큰일이네요..
일단 구현은 한번 해봤는데요
// Utils/selector.js
fadeIn(selector){
const $element = document.getElementsByClassName(selector)[0]
let opacity = 0
let interval = setInterval(()=>{
opacity += 0.1
$element.style.opacity = opacity
if(opacity>=1){
clearInterval(interval)
}
}, 50)
},
fadeOutAndHide(selector){
const $element = document.getElementsByClassName(selector)[0]
let opacity = 1
let interval = setInterval(()=>{
opacity -= 0.1
$element.style.opacity = opacity
if(opacity<=0){
clearInterval(interval)
$element.style.display = "none"
}
}, 50)
}
생각보다 할만한거같기도하고 애매해요
무엇보다 fadeOut에서 display= "none"이 먼저 작동되다보니 효과가 나오지않아서 합쳤습니다
그닥 맘에들진않아요 ㅜ
// imageInfo.js
closeModal(){
selector.fadeOutAndHide("ImageInfo")
}
...
this.$imageInfo.style.display = "block";
selector.fadeIn("ImageInfo")
이렇게 적용을 해주었습니다
흠.. 어떻게해야 완벽할수있을까요! 아쉬움이 남네요! ㅎ
아마 좀더 구현하면서 리팩토링할만한 요소들이 생기지 않을까싶습니다
이렇게 이미지 상세 모달 문제는 다 풀었네요
다음 포스팅에서 만나요!
'기술 > 과제테스트 연습' 카테고리의 다른 글
[프로그래머스 과제테스트 연습] 고양이 사진 검색 사이트 (5) - 프론트엔드 (스크롤 페이징 구현) (0) | 2023.06.26 |
---|---|
[프로그래머스 과제테스트 연습] 고양이 사진 검색 사이트 (+) - 프론트엔드 (기타) (0) | 2023.06.26 |
[프로그래머스 과제테스트 연습] 고양이 사진 검색 사이트 (4) - 프론트엔드 (HTML, CSS 관련) (0) | 2023.06.23 |
[프로그래머스 과제테스트 연습] 고양이 사진 검색 사이트 (3) - 프론트엔드 (검색 페이지 관련, 스크롤 페이징 구현) (0) | 2023.06.23 |
[프로그래머스 과제테스트 연습] 고양이 사진 검색 사이트 (1) - 프론트엔드 (코드 구조 관련) (0) | 2023.06.21 |