터치이벤트 확인할때는 모바일 개발자도구로 확인
touchstart
: 터치 시작 이벤트touchmove
: 터치 중 이벤트touchend
: 터치 끝 이벤트- 터치 시작, 중일때의 x좌표로 효과준다.
- 손가락따라 움직이게 만들 때는
container.style.transform
에 값 주기
<h1>Carousel</h1>
<style>
/* frame */
#frame{
width : 200px;
height: 200px;
position: relative;
overflow-x: hidden;
}
/* container and images */
#container{
display : flex;
width : 600px;
transition: transform 0.2s;
}
.image{
width : 200px;
height : 200px;
font-size : 2rem;
background-image: linear-gradient(to right, #333, #222);
display : flex;
justify-content: center;
align-items: center;
color : #fff;
}
/* button */
#prev, #next{
position : absolute;
top : 0;
height: 100%;
background-color: transparent;
border : none; font-size: 2rem;
color : rgba(255 255 255 / 0.5);
cursor: pointer;
}
#prev{
left : 0;
}
#next{
right : 0;
}
/* indicator */
.indicator{
position: absolute;
bottom : 12px;
width : 100%; display: flex; justify-content: center;
}
.dot{
display : block;
width : 8px; height : 8px;
background-color: #fff;
border-radius: 99px;
margin : 0 2px; opacity : 0.5;
}
/* toggle class */
.hidden{
display : none;
}
.active{
opacity : 1;
}
</style>
<div id="frame">
<div id="container">
<div class="image">1</div>
<div class="image">2</div>
<div class="image">3</div>
</div>
<button id="prev" class="hidden" onclick="turnover(-1)">❮</button>
<button id="next" onclick="turnover(1)">❯</button>
<div class="indicator">
<span class="dot active"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
</div>
<script>
// container and images
var frame = document.getElementById("frame");
var container = document.getElementById("container");
var images = document.getElementsByClassName("image");
var imageWidth = 200;
// buttons
var prev = document.getElementById("prev");
var next = document.getElementById("next");
// indicator
var dots = document.getElementsByClassName("dot");
// index and left
var index = 0;
var firstIndex = 0;
var lastIndex = images.length - 1 ;
var previousIndex = 0;
var left = 0;
// 터치 관련 변수
var x1, x2 = 0;
var turnoverPoint = 50;
function turnover(data){
index += data;
console.log(index);
left = -(index * imageWidth);
console.log(left);
// 다음 이미지로 이동
container.style.transform = `translate(${left}px)`;
// 이전버튼
if(index === firstIndex){ // 첫번째 이미지인 경우
prev.classList.add('hidden');
}else{
prev.classList.remove('hidden');
}
// 다음버튼
if(index === lastIndex){ // 마지막 이미지인 경우
next.classList.add('hidden');
}else{
next.classList.remove('hidden');
}
// indicator
dots[previousIndex].classList.remove('active');
dots[index].classList.add('active');
previousIndex = index;
}
// 터치 이벤트
// touchstart : 터치 시작 이벤트
frame.addEventListener("touchstart", touchStartHandler);
// touchmove : 터치 중 이벤트
frame.addEventListener("touchmove", touchMoveHandler);
// touchend : 터치 끝 이벤트
frame.addEventListener("touchend", touchEndHandler);
function touchStartHandler(e){
console.log("터치 시작")
// 터치 시작지점의 x좌표
x1 = e.touches[0].clientX;
};
function touchMoveHandler(e){
console.log("터치 중")
// 터치 중인 지점의 x좌표
x2 = e.touches[0].clientX;
console.log(x2 - x1);
// 오른쪽으로 움직이는지 확인
var movingToright = x2 - x1 > 0;
// 왼쪽으로 움직이는지 확인
var movingToleft = x2 - x1 < 0;
// 첫번째 사진일 때 오른쪽으로 움직일 수 없게 한다.
if(index === firstIndex && movingToright) return;
// 마지막 사진일 때 왼쪽으로 움직일 수 없게 한다.
if(index === lastIndex && movingToleft) return;
// 손가락 따라 움직이게 만든다.
container.style.transform = `translateX(${left + (x2 - x1)}px)`;
};
function touchEndHandler(){
console.log("터치 끝")
// 터치 무브 이벤트가 발생하지 않은 경우(드래그 안했을 때)
if(!x2) return;
// 다음 이미지로 이동하기 위해 충분히 당겼을 때
var drawEnoughToNext = -(x2 - x1) > turnoverPoint;
// 이전 이미지로 이동하기 위해 충분히 당겼을 때
var drawEnoughToPrev = (x2 - x1) > turnoverPoint;
// 이전 이미지로 이동
if(index > firstIndex && drawEnoughToPrev){
turnover(-1)
}
// 다음 이미지로 이동
if(index < lastIndex && drawEnoughToNext){
turnover(1)
}
// 충분히 움직이지 않은 경우 원래의 이미지로 돌아온다.
container.style.transform = `translateX(${left}px)`;
// 터치중인 지점의 x좌표(x2)를 초기화 한다.
x2 = 0;
};
</script>
"keyup"이벤트
: 키에서 손을 땠을 때 (input칸에 한 글자 입력했을 때로 알고있자)`var lowerCaseLetters = /[a-z]/
: a~z까지의 소문자.match()
: 문자열 매치 메서드 코드 : "keyup"이벤트이기 때문에 input값에 입력할때마다 입력값이 대문자인지 소문자인지 숫자인지 8글자가 넘었는지 try-catch안의 if문으로 검사하고 아닐시 throw로 지정한 오류메시지를 던져서 message에 .innerHTML로 문자열값 저장한뒤 catch에서 출력.
<style>
label{
display : block;
margin-bottom : 0.25rem;
}
#input{
width: 20rem;
box-sizing: border-box;
padding: 0.5rem;
}
.success{
color : #0a0;
}
.warning{
color : #f00;
}
</style>
<label for="input">Password</label>
<input type="password" id="input">
<p id="message"></p>
<script>
var input = document.getElementById("input");
var message = document.getElementById("message");
// keyup 이벤트 : 키에서 손을 뗐을 때
input.addEventListener("keyup", function(){
try{
var password = this.value;
console.log(password);
/*
정규식(Regular expression)
문자열을 검색하기 위한 패턴
* 사용방법
/패턴/
*/
var lowerCaseLetters = /[a-z]/
var upperCaseLetters = /[A-Z]/
var numbers = /[0-9]/
if(!password){
throw "비밀번호는 필수입니다.";
}
if(!password.match(lowerCaseLetters)){
throw "비밀번호는 최소 한개 이상의 알파벳 소문자를 포합해야 합니다";
}
if(!password.match(upperCaseLetters)){
throw "비밀번호는 최소 한개 이상의 알파벳 대문자를 포합해야 합니다";
}
if(!password.match(numbers)){
throw "비밀번호는 숫자를 포함해야 합니다.";
}
if(password.length < 8){
throw "비밀번호는 8글자 이상이어야 합니다.";
}
console.log("사용가능한 비밀번호입니다.");
message.innerHTML = `<span class="success">사용가능합니다.</span>`
}catch(error){
message.innerHTML = `<span class="warning">${error}</span>`;
console.error(error);
}
})
</script>
indexOf()
메서드는 문자열에서 값이 처음 나타나는 위치를 반환하는데 값을 찾을 수 없으면 -1을 반환한다.코드 :
- 내가 입력한 값을
var q = this.value;
로 q로 받는다. 그리고 list 요소들의 문자열을 itemName에 넣고 q와 비교하여 있는지 찾는다. 비교하여 없으면 hidden으로 없애고 있다면 hidden삭제하여 유지(애초에 없지만 삭제).- 그 후 대문자 소문자 상관없이 찾고싶기 때문에 q와 itemName에
.toLowerCase()
붙여주면서 둘다 소문자로 변환한다.
<style>
#input{
width : 400px; padding : 0.5rem;
box-sizing: border-box;
font-size: 1rem;
}
ul{
list-style: none;
padding: 0; margin: 0;
}
.item{
padding : 0.5rem;
}
.hidden{
display: none;
}
</style>
<input type="text" name="" id="input" placeholder="Search">
<ul>
<li class="item">Guiness</li>
<li class="item">Heineken</li>
<li class="item">Budwiser</li>
<li class="item">Kloud</li>
<li class="item">Asahi</li>
</ul>
<script>
var input = document.getElementById("input");
var items = document.getElementsByClassName("item");
input.addEventListener("keyup", function(){
// 검색어에 접근 뒤 소문자로 변환
var q = this.value.toLowerCase();
console.log("검색어 : ", q);
for(var i=0; i<items.length; i++){
// 아이템에 접근 뒤 소문자로 변환
var itemName = items[i].textContent.toLowerCase();
if(itemName.indexOf(q) > -1){ // 아이템이 검색어를 포함한 경우
items[i].classList.remove("hidden");
}else{ // 검색어를 포함하지 않은 경우
items[i].classList.add("hidden");
}
}
})
</script>
"submit"
: 폼 제출 이벤트 e.preventDefault();
: 이벤트의 기본값을 실행하지 않는다.form.elements[접근할 input의 name]
: name으로 form에 속한 input에 접근할 수 있다..trim()
: 빈칸(공백)없이 텍스트를 붙인다.코드 :
- server가 없기 때문에
e.preventDefault();
로 오류 막는다.var email = form.elements["email"].value;
로 name="email"을 가진 form의 input값을 받고 그 값을.trim()
으로 공백없이 만든다.if(!email.trim())
: 공백이라면 error에 "이메일을 입력하세요" 문자열입력. 값 있다면 form숨기고 감사메시지 띄운다.
<Style>
.container{
display: flex;
}
input{
padding : 0.5rem;
flex-grow: 1;
}
.warning{
color : #f00;
}
.hidden{
display : none;
}
</Style>
<form action="/server" id="form">
<div class="container">
<input type="text" name="email" placeholder="JohnDoe@example.com">
<button class="btn">Subscribe</button>
</div>
<p id="error" class="warning"></p>
</form>
<p id="done" class="hidden">
Thank you for subscribing us!
</p>
<script>
var form = document.getElementById("form");
var done = document.getElementById("done");
var error = document.getElementById("error");
// submit : 폼 제출 이벤트
form.addEventListener("submit",function(e){
// 이벤트의 기본값을 실행하지 않는다.
e.preventDefault();
// console.log("폼 제출 방지됨")
// form.elements[접근할 input의 name]
// name으로 form에 속한 input에 접근할 수 있다.
var email = form.elements["email"].value;
if(!email.trim()) {
error.textContent = "이메일을 입력하세요";
return;
}
// AJAX 요청..
// 새로고침 없이 서버에 요청하는 기술
// 폼을 숨긴다.
form.classList.add("hidden");
// 땡큐메시지를 사용자에게 보여준다.
done.classList.remove("hidden");
})
</script>