편집 요약 없음 태그: 수동 되돌리기 |
편집 요약 없음 |
||
23번째 줄: | 23번째 줄: | ||
------ | ------ | ||
<span style="padding: 0 7px; padding-bottom: 3px; border-left: 5px solid #466DFA; color: #3757C7; font-size: 13.8pt;">'''이브위키 추천 세계관'''</span> {{글씨 색|#929294|이브위키 운영진이 추천하는 세계관입니다.}} | <span style="padding: 0 7px; padding-bottom: 3px; border-left: 5px solid #466DFA; color: #3757C7; font-size: 13.8pt;">'''이브위키 추천 세계관'''</span> {{글씨 색|#929294|이브위키 운영진이 추천하는 세계관입니다.}} | ||
<html> | |||
<head> | |||
<meta charset="UTF-8" /> | |||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||
<title>Vanilla js auto loop slide</title> | |||
</head> | |||
<body> | |||
<div class="container"> | |||
<div class="slide slide_wrap"> | |||
<div class="slide_item item1"> | |||
<div id="banner" class="flora" onclick="location.href='/w/index.php/분류:플로라_유니버스'"> | |||
<div class="main-banner-body"> | |||
<div class="flora-1"> | |||
<img id="img-550" alt="플로라.svg" src="https://evewiki.kr/w/images/1/18/플로라.svg" style="width: auto; height: 5.5vw;"> | |||
</div> | |||
<div class="flora-2"> | |||
<span style="font-size: 1.75rem; font-weight: 700;">플로라 유니버스</span><br> | |||
<span style="font-size: 1.0rem; font-weight: 700;">한국 정치를 우리들 생각대로 만들어보자!</span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="slide_item item2"> | |||
<div id="banner" class="hannara" onclick="location.href='/w/index.php/한나라닷컴'"> | |||
<div class="main-banner-body"> | |||
<div class="hannara-1"> | |||
<img id="img-225" alt="한나라닷컴.png" src="https://evewiki.kr/w/images/2/23/Hannara_w.png" style="width: auto; height: 2.25vw;"> | |||
</div> | |||
<div class="hannara-2"> | |||
<span style="font-size: 1.0rem; font-weight: 700;">종신집권을 향해 나아가는 여전사 나경원의 국회 분투기</span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="slide_item item3"> | |||
<div id="banner" class="ana" onclick="location.href='/w/index.php/아름다운_나라'"> | |||
<div class="main-banner-body"> | |||
<div class="ana-1"> | |||
<img id="img-550" alt="아름다운나라.png" src="/w/images/f/fc/아나_로고.png" style="width: auto; height: 5.5vw;"> | |||
</div> | |||
<div class="ana-2"> | |||
<span style="font-size: 1.0rem; font-weight: 700;">새로운 설정, 새로운 아나</span> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div class="slide_prev_button slide_button"></div> | |||
<div class="slide_next_button slide_button"></div> | |||
<ul class="slide_pagination"></ul> | |||
</div> | |||
<div> | |||
</body> | |||
<style> | |||
#catlinks { display: none; } | |||
.container { | |||
width: calc(100% + 30px); | |||
margin-left: -1.0rem; | |||
} | |||
.container { | |||
padding: 0; | |||
list-style: none; | |||
font-size: 13px; | |||
font-weight: 500; | |||
box-sizing: border-box; | |||
} | |||
@media screen and (max-width: 1023px) { .container { margin-left: -0.5rem !important; } } | |||
.slide { | |||
/* layout */ | |||
display: flex; | |||
flex-wrap: nowrap; | |||
/* 컨테이너의 내용물이 컨테이너 크기(width, height)를 넘어설 때 보이지 않도록 하기 위해 hidden을 준다. */ | |||
overflow: hidden; | |||
/* position */ | |||
/* slide_button의 position absolute가 컨테이너 안쪽에서 top, left, right offset이 적용될 수 있도록 relative를 준다. (기본값이 static인데, static인 경우 그 상위 컨테이너로 나가면서 현재 코드에선 html을 기준으로 offset을 적용시키기 때문) */ | |||
position: relative; | |||
/* size */ | |||
width: 100%; | |||
/* slide drag를 위해 DOM요소가 드래그로 선택되는것을 방지 */ | |||
user-select: none; | |||
} | |||
.slide_item { | |||
/* layout */ | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
/* position - 버튼 클릭시 left offset값을 적용시키기 위해 */ | |||
position: relative; | |||
left: 0px; | |||
/* size */ | |||
width: 100%; | |||
height: 300px; | |||
/* flex item의 flex-shrink는 기본값이 1이므로 컨테이너 크기에 맞게 줄어드는데, 슬라이드를 구현할 것이므로 줄어들지 않도록 0을 준다. */ | |||
flex-shrink: 0; | |||
/* transition */ | |||
transition: left 300ms; | |||
} | |||
.slide_button { | |||
/* layout */ | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
/* position */ | |||
position: absolute; | |||
/* 버튼이 중앙에 위치하게 하기위해 계산 */ | |||
top: calc(50% - 16px); | |||
/* size */ | |||
width: 32px; | |||
height: 32px; | |||
/* style */ | |||
border-radius: 100%; | |||
background-color: #FFF; | |||
color: #222; | |||
border: 1px solid #bbb; | |||
cursor: pointer; | |||
} | |||
.slide_prev_button { | |||
left: 25px; | |||
} | |||
.slide_next_button { | |||
right: 25px; | |||
} | |||
.slide_prev_button:after { | |||
content: '◀'; | |||
} | |||
.slide_next_button:after { | |||
content: '▶'; | |||
} | |||
/* 슬라이드 */ | |||
#banner { | |||
cursor: pointer; | |||
} | |||
.flora { | |||
width: 100%; | |||
height: 100%; | |||
background-color: #00A366; | |||
color: #FFF; | |||
} | |||
.main-banner-body { | |||
width: 1290px; | |||
height: 100%; | |||
margin: 0 auto; | |||
position: relative; | |||
} | |||
.flora-1 { | |||
margin: 3.5vw 5.25vw 0 5.25vw; | |||
width: 100%; | |||
height: 5.5vw; | |||
} | |||
.flora-2 { | |||
margin: 0.5vw 5.25vw; | |||
} | |||
.hannara { | |||
width: 100%; | |||
height: 100%; | |||
background: linear-gradient(to right, rgba(0, 46, 109, 1) 0%, rgba(0, 46, 109, 0) 50%), url(/w/images/2/2d/나경원_내각총리대신_취임연설.jpg); | |||
background-repeat: no-repeat; | |||
background-size: cover; | |||
color: #FFF; | |||
} | |||
.hannara-1 { | |||
margin: 3.5vw 5.25vw 0 5.25vw; | |||
width: 100%; | |||
height: 2.25vw; | |||
} | |||
.hannara-2 { | |||
margin: 0.5vw 5.25vw; | |||
} | |||
.ana { | |||
width: 100%; | |||
height: 100%; | |||
background-color: #000070; | |||
color: #FFF; | |||
} | |||
.ana-1 { | |||
margin: 3.5vw 5.25vw 0 5.25vw; | |||
width: 100%; | |||
height: 5.5vw; | |||
} | |||
.ana-2 { | |||
margin: 0.5vw 5.25vw; | |||
} | |||
@media screen and (max-width: 1023px) { .slide_button { display: none !important; } } | |||
@media screen and (max-width: 1023px) { #img-550 { height: 50px !important; } .flora-1, .ana-1 { height: 60px !important; } } | |||
@media screen and (max-width: 1023px) { #img-225 { height: 20px !important; } .hannara-1 { height: 30px !important; } } | |||
@media screen and (max-width: 1023px) { .slide_item { height: auto !important; } #banner { padding-top: 15px !important; padding-bottom: 20px !important; } } | |||
/* 페이지네이션 스타일 */ | |||
ul, | |||
li { | |||
list-style: none; | |||
padding: 0; | |||
margin: 0; | |||
} | |||
.slide_pagination { | |||
/* layout */ | |||
margin: 0 !important; | |||
display: flex; | |||
gap: 5px; | |||
/* left:50%, translateX(-50%)를 하면 가로 가운데로 위치시킬 수 있다. */ | |||
left: 50%; | |||
transform: translateX(-50%); | |||
/* position */ | |||
position: absolute; | |||
bottom: 0.25rem; | |||
} | |||
.slide_pagination > li { | |||
/* 현재 슬라이드가 아닌 것은 투명도 부여 */ | |||
color: #FFF; | |||
cursor: pointer; | |||
font-size: 30px; | |||
} | |||
.slide_pagination > li.active { | |||
/* 현재 슬라이드 색상은 투명도 없이 */ | |||
color: red; | |||
} | |||
.slide_item_duplicate { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
position: relative; | |||
left: 0px; | |||
width: 100%; | |||
height: 300px; | |||
flex-shrink: 0; | |||
transition: left 300ms; | |||
} | |||
</style> | |||
<script> | |||
// 슬라이크 전체 크기(width 구하기) | |||
const slide = document.querySelector(".slide"); | |||
let slideWidth = slide.clientWidth; | |||
// 버튼 엘리먼트 선택하기 | |||
const prevBtn = document.querySelector(".slide_prev_button"); | |||
const nextBtn = document.querySelector(".slide_next_button"); | |||
// 슬라이드 전체를 선택해 값을 변경해주기 위해 슬라이드 전체 선택하기 | |||
let slideItems = document.querySelectorAll(".slide_item"); | |||
// 현재 슬라이드 위치가 슬라이드 개수를 넘기지 않게 하기 위한 변수 | |||
const maxSlide = slideItems.length; | |||
// 버튼 클릭할 때 마다 현재 슬라이드가 어디인지 알려주기 위한 변수 | |||
let currSlide = 1; | |||
// 페이지네이션 생성 | |||
const pagination = document.querySelector(".slide_pagination"); | |||
for (let i = 0; i < maxSlide; i++) { | |||
if (i === 0) pagination.innerHTML += `<li class="active">•</li>`; | |||
else pagination.innerHTML += `<li>•</li>`; | |||
} | |||
const paginationItems = document.querySelectorAll(".slide_pagination > li"); | |||
// 무한 슬라이드를 위해 start, end 슬라이드 복사하기 | |||
const startSlide = slideItems[0]; | |||
const endSlide = slideItems[slideItems.length - 1]; | |||
const startElem = document.createElement("div"); | |||
const endElem = document.createElement("div"); | |||
endSlide.classList.forEach((c) => endElem.classList.add(c)); | |||
endElem.innerHTML = endSlide.innerHTML; | |||
startSlide.classList.forEach((c) => startElem.classList.add(c)); | |||
startElem.innerHTML = startSlide.innerHTML; | |||
// 각 복제한 엘리먼트 추가하기 | |||
slideItems[0].before(endElem); | |||
slideItems[slideItems.length - 1].after(startElem); | |||
// 슬라이드 전체를 선택해 값을 변경해주기 위해 슬라이드 전체 선택하기 | |||
slideItems = document.querySelectorAll(".slide_item"); | |||
// | |||
let offset = slideWidth + currSlide; | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `left: ${-offset}px`); | |||
}); | |||
function nextMove() { | |||
currSlide++; | |||
// 마지막 슬라이드 이상으로 넘어가지 않게 하기 위해서 | |||
if (currSlide <= maxSlide) { | |||
// 슬라이드를 이동시키기 위한 offset 계산 | |||
const offset = slideWidth * currSlide; | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `left: ${-offset}px`); | |||
}); | |||
// 슬라이드 이동 시 현재 활성화된 pagination 변경 | |||
paginationItems.forEach((i) => i.classList.remove("active")); | |||
paginationItems[currSlide - 1].classList.add("active"); | |||
} else { | |||
// 무한 슬라이드 기능 - currSlide 값만 변경해줘도 되지만 시각적으로 자연스럽게 하기 위해 아래 코드 작성 | |||
currSlide = 0; | |||
let offset = slideWidth * currSlide; | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `transition: ${0}s; left: ${-offset}px`); | |||
}); | |||
currSlide++; | |||
offset = slideWidth * currSlide; | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
setTimeout(() => { | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
// i.setAttribute("style", `transition: ${0}s; left: ${-offset}px`); | |||
i.setAttribute("style", `transition: ${0.15}s; left: ${-offset}px`); | |||
}); | |||
}, 0); | |||
// // 슬라이드 이동 시 현재 활성화된 pagination 변경 | |||
paginationItems.forEach((i) => i.classList.remove("active")); | |||
paginationItems[currSlide - 1].classList.add("active"); | |||
} | |||
} | |||
function prevMove() { | |||
currSlide--; | |||
// 1번째 슬라이드 이하로 넘어가지 않게 하기 위해서 | |||
if (currSlide > 0) { | |||
// 슬라이드를 이동시키기 위한 offset 계산 | |||
const offset = slideWidth * currSlide; | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `left: ${-offset}px`); | |||
}); | |||
// 슬라이드 이동 시 현재 활성화된 pagination 변경 | |||
paginationItems.forEach((i) => i.classList.remove("active")); | |||
paginationItems[currSlide - 1].classList.add("active"); | |||
} else { | |||
// 무한 슬라이드 기능 - currSlide 값만 변경해줘도 되지만 시각적으로 자연스럽게 하기 위해 아래 코드 작성 | |||
currSlide = maxSlide + 1; | |||
let offset = slideWidth * currSlide; | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `transition: ${0}s; left: ${-offset}px`); | |||
}); | |||
currSlide--; | |||
offset = slideWidth * currSlide; | |||
setTimeout(() => { | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
// i.setAttribute("style", `transition: ${0}s; left: ${-offset}px`); | |||
i.setAttribute("style", `transition: ${0.15}s; left: ${-offset}px`); | |||
}); | |||
}, 0); | |||
// 슬라이드 이동 시 현재 활성화된 pagination 변경 | |||
paginationItems.forEach((i) => i.classList.remove("active")); | |||
paginationItems[currSlide - 1].classList.add("active"); | |||
} | |||
} | |||
// 버튼 엘리먼트에 클릭 이벤트 추가하기 | |||
nextBtn.addEventListener("click", () => { | |||
// 이후 버튼 누를 경우 현재 슬라이드를 변경 | |||
nextMove(); | |||
}); | |||
// 버튼 엘리먼트에 클릭 이벤트 추가하기 | |||
prevBtn.addEventListener("click", () => { | |||
// 이전 버튼 누를 경우 현재 슬라이드를 변경 | |||
prevMove(); | |||
}); | |||
// 브라우저 화면이 조정될 때 마다 slideWidth를 변경하기 위해 | |||
window.addEventListener("resize", () => { | |||
slideWidth = slide.clientWidth; | |||
}); | |||
// 각 페이지네이션 클릭 시 해당 슬라이드로 이동하기 | |||
for (let i = 0; i < maxSlide; i++) { | |||
// 각 페이지네이션마다 클릭 이벤트 추가하기 | |||
paginationItems[i].addEventListener("click", () => { | |||
// 클릭한 페이지네이션에 따라 현재 슬라이드 변경해주기(currSlide는 시작 위치가 1이기 때문에 + 1) | |||
currSlide = i + 1; | |||
// 슬라이드를 이동시키기 위한 offset 계산 | |||
const offset = slideWidth * currSlide; | |||
// 각 슬라이드 아이템의 left에 offset 적용 | |||
slideItems.forEach((i) => { | |||
i.setAttribute("style", `left: ${-offset}px`); | |||
}); | |||
// 슬라이드 이동 시 현재 활성화된 pagination 변경 | |||
paginationItems.forEach((i) => i.classList.remove("active")); | |||
paginationItems[currSlide - 1].classList.add("active"); | |||
}); | |||
} | |||
// 드래그(스와이프) 이벤트를 위한 변수 초기화 | |||
let startPoint = 0; | |||
let endPoint = 0; | |||
// PC 클릭 이벤트 (드래그) | |||
slide.addEventListener("mousedown", (e) => { | |||
startPoint = e.pageX; // 마우스 드래그 시작 위치 저장 | |||
}); | |||
slide.addEventListener("mouseup", (e) => { | |||
endPoint = e.pageX; // 마우스 드래그 끝 위치 저장 | |||
if (startPoint < endPoint) { | |||
// 마우스가 오른쪽으로 드래그 된 경우 | |||
prevMove(); | |||
} else if (startPoint > endPoint) { | |||
// 마우스가 왼쪽으로 드래그 된 경우 | |||
nextMove(); | |||
} | |||
}); | |||
// 모바일 터치 이벤트 (스와이프) | |||
slide.addEventListener("touchstart", (e) => { | |||
startPoint = e.touches[0].pageX; // 터치가 시작되는 위치 저장 | |||
}); | |||
slide.addEventListener("touchend", (e) => { | |||
endPoint = e.changedTouches[0].pageX; // 터치가 끝나는 위치 저장 | |||
if (startPoint < endPoint) { | |||
// 오른쪽으로 스와이프 된 경우 | |||
prevMove(); | |||
} else if (startPoint > endPoint) { | |||
// 왼쪽으로 스와이프 된 경우 | |||
nextMove(); | |||
} | |||
}); | |||
// 기본적으로 슬라이드 루프 시작하기 | |||
let loopInterval = setInterval(() => { | |||
nextMove(); | |||
}, 3000); | |||
// 슬라이드에 마우스가 올라간 경우 루프 멈추기 | |||
slide.addEventListener("mouseover", () => { | |||
clearInterval(loopInterval); | |||
}); | |||
// 슬라이드에서 마우스가 나온 경우 루프 재시작하기 | |||
slide.addEventListener("mouseout", () => { | |||
loopInterval = setInterval(() => { | |||
nextMove(); | |||
}, 3000); | |||
}); | |||
</script> | |||
</html> | |||
------ | ------ | ||
<span style="padding: 0 7px; padding-bottom: 3px; border-left: 5px solid #466DFA; color: #3757C7; font-size: 13.8pt;">'''운영알림'''</span> {{글씨 색|#929294|이브위키에서 알려드립니다.}} | <span style="padding: 0 7px; padding-bottom: 3px; border-left: 5px solid #466DFA; color: #3757C7; font-size: 13.8pt;">'''운영알림'''</span> {{글씨 색|#929294|이브위키에서 알려드립니다.}} |