궁금한 내용을 검색해보세요!
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
서근 개발노트
티스토리에 팔로잉
FRONT-END/TIL

[TIL] 230112 토이프로젝트 3일차

서근
QUOTE THE DAY

-
Written by SeogunSEOGUN

반응형

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형식으로 가져와 animationdelay 주면서 무한로딩이 되지 않게 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');
});


사용한 라이브러리

https://github.com/CodeSeven/toastr

https://yaireo.github.io/tagify/

'FRONT-END > TIL' 카테고리의 다른 글

[TIL] 230114 Git  (1) 2023.01.15
[TIL] 230113 토이프로젝트 4일차 끝  (0) 2023.01.15
[TIL] 230110 - 230111 토이프로젝트 1일차 - 2일차  (0) 2023.01.12
[TIL] 230111  (0) 2023.01.12
[TIL] 230110  (1) 2023.01.10

잘못된 내용이 있으면 언제든 피드백 부탁드립니다.


서근


위처럼 이미지 와 함께 댓글을 작성할 수 있습니다.