[TIL] 230112 토이프로젝트 3일차
20230112
토이프로젝트 북마크세이버라는 프로젝트를 진행하면서 1-2일 차에 프론트엔드에서 헤더 기능, 타이핑 기능, 메인 인덱스 UI를 백엔드에서 회원가입 기능을 추가하여 인덱스 페이지와 로그인 페이지를 마무리 지었었다.
3일 차에는 메인 화면에 URL을 추가하면 해당 URL의 meta og
태그들을 긁어 오고, 인풋의 여러 로직을 만들어 URL / 사용자가 원하는 카테고리 / 태그까지 넣어 화면에 뿌려지는 형식으로 로직을 짰다.
이과정에서는 Python
, Flask
, Pymongo
, JS, BS4
스택을 사용했다.
로그인 부분
태그 기능은 프론트엔드에서 tagify
라이브러리를 사용하여 tag
를 보여주는 기능을 구현했고,
백엔드는 토큰기능과 hash
보안 기능이 없는 부분만 구현해 주셨다.
const loginBtn = document.querySelector('#login-btn');
const signUpBtn = document.querySelector('#sign-up-btn');
const signUpCheckBtn = document.querySelector('#sign-up-check');
const signUpBackBtn = document.querySelector('#sign-up-back');
const idInput = document.querySelector('#floatingId');
const passwordInput = document.querySelector('#floatingPassword');
const passwordCheckInput = document.querySelector('#floatingPasswordCheck');
loginBtn.addEventListener('click', (e) => {
e.preventDefault();
const userId = idInput.value;
const userPassword = passwordInput.value;
if (!loginCrossCheck(userId, userPassword)) {
return;
}
// const userID = sendUserData(userId, userPassword);
if (!sendUserData(userId, userPassword)) {
return;
}
make_Token(userId, userPassword);
});
signUpBtn.addEventListener('click', (e) => {
e.preventDefault();
selectorShowOrHide(false, loginBtn, signUpBtn);
selectorShowOrHide(true, passwordCheckInput, signUpCheckBtn, signUpBackBtn);
});
signUpCheckBtn.addEventListener('click', (e) => {
e.preventDefault();
const userId = idInput.value;
const password = passwordInput.value;
const passwordCheck = passwordCheckInput.value;
if (!singupCrossCheck(userId, password, passwordCheck)) {
return;
}
if (!sendUserData(userId, password, passwordCheck)) {
return;
}
selectorShowOrHide(true, loginBtn, signUpBtn);
selectorShowOrHide(false, passwordCheckInput, signUpCheckBtn, signUpBackBtn);
});
signUpBackBtn.addEventListener('click', () => {
window.location.reload();
});
function make_Token(id, password) {
$.ajax({
type: 'POST',
url: '/token',
data: {
id_give: id,
password_give: password,
},
success: function (response) {
// jwt토큰을 가지는 쿠키 생성
console.log(response['token']);
if (response['result'] == 'success') {
$.cookie('mytoken', response['token']);
// alert('쿠키생성 성공!');
window.location.href = './main';
}
},
error: function (response) {
alert(response['msg']);
},
});
}
function singupCrossCheck(userId, password, otherPassword) {
if (userId === '' || password === '' || otherPassword === '') {
alert('공백란을 채워 주세요');
return false;
}
if (password !== otherPassword) {
alert('비밀 번호를 재입력 해주세요');
return false;
}
return true;
}
function loginCrossCheck(userId, password) {
if (userId === '' || password === '') {
alert('공백란을 채워 주세요');
return false;
}
return true;
}
function selectorShowOrHide(boolean, ...selectors) {
if (boolean === true) {
selectors.map((selector) => (selector.style.display = 'block'));
} else {
selectors.map((selector) => (selector.style.display = 'none'));
}
}
function sendUserData(id, password, passwordCheck = null) {
let checkData = true;
$.ajax({
type: 'POST',
url: '/login',
data: {
id_give: id,
pw_give: password,
pw_check_give: passwordCheck,
},
async: false,
success: function (response) {
if (response['complete']) {
response['complete'];
} else if (response['create']) {
toastr.success(response['create']);
} else if (response['fail']) {
toastr.error(response['fail']);
checkData = false;
} else {
toastr.error(response['error']);
checkData = false;
}
},
error: function () {
alert('로그인 정보가 없습니다.');
checkData = false;
},
});
return checkData;
}
그리고 Ajax
를 사용해 백엔드 쪽으로 ID와 Password를 보내, DB
와 일치하지 않으면 경고메시지가 뜰 수 있도록 Alert
를 사용해 줬는데, 기본 Alert
메서드가 아닌 Tostr
라이브러리를 사용하여 더욱 직관적이고 사용자 경험을 해치지 않도록 해줬다.
메인 프론트 부분
로그인에 성공하면 나오는 메인 페이지 부분에 프론트엔드에서 UI 적으로 심심하지 않게 로고를 SVG
형식으로 가져와 animation
을 delay
주면서 무한로딩이 되지 않게 5번의 애니메이션 효과만 로테이션될 수 있도록 해줬다.
<div class="main__section-logo">
<svg class="main__logo" version="1.1" x="0px" y="0px" viewBox="0 0 557.3 75.6" style="enable-background: new 0 0 557.3 75.6" data-aos="flip-up" data-aos-delay="200" data-aos-easing="ease-in-out" data-aos-once="true">
<g class="main__logo-text1">
<path
d="M18,55.4V25.2c0-3.6,1.8-5.4,5.4-5.4h17.4c7.1,0,10.6,3.2,10.6,9.6v3c0,3.2-1.3,5.6-3.8,7.4c0.1,0.1,0.2,0.1,0.3,0.2
c2.7,2.3,4,4.9,4,7.9v3.2c0,6.4-3.5,9.6-10.6,9.6H23.3C19.7,60.8,18,59,18,55.4z M28.3,27.8v8.1h10.2c1.7,0,2.5-0.8,2.5-2.5v-3
c0-1.7-0.9-2.5-2.5-2.5H28.3z M28.3,43.5v9.3H39c1.7,0,2.6-0.8,2.6-2.5v-4.2c0-1.7-0.9-2.6-2.6-2.6H28.3z"
data-text="B"
/>
...
</g>
<g class="main__logo-text2">
<path
d="M355.2,51.9c0-3.8,1.7-5.7,5-5.7h0.2c3.4,0,5,1.4,5,4.3c0,1.4,1,2,3.1,2h7.1c2,0,3.1-1,3.1-3.1V47c0-2-1-3.1-3.1-3.1h-9.4
c-7.4,0-11.1-3.4-11.1-10.1v-4.2c0-6.7,3.7-10.1,11.1-10.1h11.6c7.4,0,11.1,3,11.1,9.1c0,3.7-1.7,5.6-4.9,5.6h-0.2
c-3.3,0-4.9-1.4-4.9-4.2c0-1.4-1-2-3.1-2h-7.3c-2,0-3.1,1-3.1,3.1v1.7c0,2,1,3.1,3.1,3.1h9.4c7.4,0,11.1,3.4,11.1,10.1v5
c0,6.7-3.7,10.1-11.1,10.1h-11.6C358.9,61,355.2,58,355.2,51.9z"
/>
...
</g>
</svg>
</div>
.main__logo path {
transition: transform 0.5s;
animation: text 2s ease-in 5;
transform: translatez(0);
}
.main__logo > .main__logo-text1 > path:nth-child(1n) {
animation-delay: 310ms;
}
.main__logo > .main__logo-text1 > path:nth-child(2n) {
animation-delay: 370ms;
}
.main__logo > .main__logo-text1 > path:nth-child(3n) {
animation-delay: 430ms;
}
...
.main__arrow span {
border: 2px solid transparent;
border-right-color: white;
border-bottom-color: white;
border-radius: 2px;
width: 1rem;
height: 1rem;
display: block;
transform: rotate(45deg) translate(-50%, -50%);
animation: 0.6s 1s alternate arrow-down 500;
position: absolute;
top: 2rem;
left: 50%;
}
@keyframes arrow-down {
0% {
opacity: 0;
}
25% {
opacity: 0.25;
}
50% {
opacity: 0.5;
}
75% {
opacity: 0.75;
}
100% {
opacity: 1;
}
}
그리고 URL 및 기타 태그를 등록할 수 있는 Form
은 단순히 메인에 뿌리는 것보다 특정 버튼을 클릭했을 때 애니메이션 Fade-In
/Out
효과와 함께 나타나게끔 로직을 손봤다.
//=====================포스팅 팝업=========================
$(document).ready(function () {
var target = $('#postPop');
$(document).on('click', '.nav__posting', function (e) {
target
.fadeIn(300, function () {
$('#postPop__url').focus();
})
.addClass('reveal');
$('body').addClass('has-url');
});
});
$('#close__postPop').click(function () {
$(this).closest('#postPop').removeClass('reveal').fadeOut(200);
$('body').removeClass('has-url');
});