[프로젝트] 인스타그램 클론코딩 #7.AJAX

UkiUkhui·2022년 8월 21일
0

Project 해보자!

목록 보기
8/8

7. Ajax

  • 비동기적인 자바스크립트와 xml
  • astnchronous javascript and xml
    • 비동기적인 방식 : 여러 일들을 분업화하여 처리
    • 동기적인 방식 : 서버와 연결하지 않고 웹 사이트 만듦
  • ex) sns앱의 경우
    • 프로세스 : 앱 열기 / 페이지 내리기 / 포스트 로딩 / 댓글 업데이트 등
    • 비동기 : 여러 프로세스들이 독립적으로 작동
    • 동기 : 다른일이 끝날 때까지 대기함
  • 서버 연결이 필수적임
    • php, python 등 이용
    • 로컬 호스트 서버 활용

➡️ vscode 이용 시

  • front만 작성
    • open window만 적용하였었음
    • option + b
  • Live Server 사용
    • 설치 후 live server open
    • 서버 포트 자동 오픈되면서 로컬 호스트 서버를 하나 받음

1) 좋아요 클릭 시 값 변경 기능 추가

✔️ JQuery DOM에 추가하기

  • 임시방편으로 jquery를 사용
  • Jquery 엔진 가져와서 html에 다운로드 경로 넣어주기
    • 최신버전 사용하기
        </section>
        <script src="https://code.jquery.com/jquery-latest.js"></script>
    
        <script src="js/main.js"></script>

✔️ Ajax 통신

  • jquery 이용
    • $.ajax로 시작함
      1) type 지정(=Method)
      • URL 데이터타입을 서버측으로 보내는 경우
      • GET : 데이터를 url 경로를 뒤에 붙여서 보냄
      • POST : 데이터 보낼 때, url 경로 생략해 보냄

✔️ 코드

    if (elem.matches('[data-name="heartbeat"')) {
        console.log('하트누름');
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/like.json',
            data: 37,
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {//통신에 성공한 데이터가 response로 들어옴
                let likeCount = document.querySelector('#like-count-37');
                likeCount.innerHTML = '좋아요' + response.like_count + '개';
            }
        })
    } else if (elem.matches('[data-name="bookmark"')) {
        console.log('북마크누름');
    } else if (elem.matches('[data-name="share"')) {
        console.log('공유누름');
    } if (elem.matches('[data-name="more"')) {
        console.log('더보기누름');
    }

    elem.classList.toggle('on'); //on 클래스 주기
}
  • data: 37, let likeCount = document.querySelector('#like-count-37');
    • data:[pk], ('#like-count-')+pk임
    • 각 유저들이 가진 고유한 번호를 찍어주거나 연결
    • 아직 백엔드 구현이 안되어 임시방편으로 하드코딩
  • 중복되는 글자 제거

                            <div class="likes m_text">
                                <span id="like-count-37">1,203</span>
                            </div>

  • Ajax 통신 확인 : Network 탭
    • 서버와 어떤 통신을 하였는지 확인 가능
    • Ajax 통신 이용 및 하트 클릭 시 like.json 폴더가 나옴

✔️ ajax 통신 에러 코드 추가

    if (elem.matches('[data-name="heartbeat"')) {
        console.log('하트누름');
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/like.json',
            data: 37,
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {//통신에 성공한 데이터가 response로 들어옴
                let likeCount = document.querySelector('#like-count-37');
                likeCount.innerHTML = '좋아요' + response.like_count + '개';
            },
            error: function(request, status, error){
                alert('로그인 필요');
                window.location.replace('https://www.naver.com');//임시 에러 웹페이지
            }
        })
    } 

2) 북마크 기능 추가

  • pk 값을 통해 좋아요, 북마크 기능 수정
  • backend 구현 전이므로 임시방편으로 기능 추가
    • html id, name 값 = 37
    • 이후 backend 구현 시, name="{{pk}}"로 변경

✔️ 코드

index.html

 <div class="bottom_icons">
                                <div class="left_icons">
                                    <div class="heart_btn">
                                        <div class="sprite_heart_icon_outline" name ="37" data-name="heartbeat"></div>
                                        <div class="sprite_bubble_icon"></div>
                                        <div class="sprite_share_icon" data-name="share"></div>

                                    </div>
                                </div>
                                <div class="right-icon">
                                    <div class="sprite_bookmark_outline" name=""37" data-name="bookmark"></div>
                                </div>
                            </div>

                            <div class="likes m_text">
                                <span id="like-count-37">1,203</span>
                                <span id="bookmark-count-37"></span>
                            </div>
  • heart icon과 bookmark
    • name = 37로 변경 및 추가
  • class="likes"
    • span id="bookmark..." 추가

main.js

if (elem.matches('[data-name="heartbeat"')) {
        //console.log('하트누름');
        let pk = elem.getAttribute('name'); //pk값을 받아옴
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/like.json',
            data: { pk },
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {//통신에 성공한 데이터가 response로 들어옴
                let likeCount = document.querySelector('#like-count-37');
                likeCount.innerHTML = '좋아요' + response.like_count + '개';
            },
            error: function (request, status, error) {
                alert('로그인 필요');
                window.location.replace('https://www.naver.com');//임시 에러 웹페이지
            }
        })
    } else if (elem.matches('[data-name="bookmark"')) {
        //console.log('북마크누름');
        let pk = elem.getAttribute('name'); //pk값을 받아옴
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/bookmark.json',
            data: { pk },
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {//통신에 성공한 데이터가 response로 들어옴
                let likeCount = document.querySelector('#bookmark-count-37');
                likeCount.innerHTML = '북마크' + response.bookmark_count + '개';
            },
            error: function (request, status, error) {
                alert('로그인 필요');
                window.location.replace('https://www.naver.com');//임시 에러 웹페이지
            }
        })
  • 북마크에도 ajax 추가
  • data를 pk로 통일
    • data = 현재는 html의 name값
  • bookmark.json 추가

3) 댓글 기능

  • data-name : HTML 파일과 JS 파일에 추가
    • comment : 게시
    • comment_delete : 삭제

index.html

<div class="comment_field" id="add-comment-post37">
                                <input type="text" placeholder="댓글달기...">
                                <div class="upload_btn m_text" data-name="comment">게시</div>
                            </div>
<div class="comment_container">
...

                                <div class="comment" id="comment-list-ajax-post37">
                                    <div class="nick_name m_text">JANG</div>
                                    <div>nice</div>
                                </div>
  • id와 data-name 추가
  • ajax와 연결되는 comment부

style.css

.contents .comment_field .upload_btn{
    color:#3897f0;
    position: absolute;
    right: 20px;
    top: 50%;
    transform:translateY(-50%);/*y축 중앙정렬*/
    cursor: pointer;
    /*pointer-events: none;/*클릭 금지*/
    opacity: 0.6;
}


.contents .comment_container .comment{
    display:flex;/*가로배치*/
    flex-direction: column;
    font-size: 14px;
}

.contents .comment_container .comment-detail{
    display : flex;/*가로배치*/
}
  • 글자 입력했을 때 게시 버튼이 클릭되는 부분 구현이 안되어 있음
  • 임시적으로 pointer-events 부분 주석처리
  • contents .comment_container 가로배치가 되므로 세로배치되도록 추가

main.js

else if (elem.matches('[data-name="comment"')) {
        let content = document.querySelector('#add-comment-post37 > input[type=text]').value;

        console.log(content);
        if (content.length > 140) {
            alert('댓글 최대 140자 입력 가능. 현재 글자수 : ' + content.length);
            return;
        }
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: './comment.html',
            data: {
                'pk': 37,
                'content': content
            },
            dataType: 'html',  //어떤 데이터로 들어오는지 설정
            success: function (data) {
                document.querySelector('#comment-list-ajax-post37').insertAdjacentHTML('afterbegin', data);
            },
            error: function (request, status, error) {
                alert('에러 발생-comment');
            }
        })
    } else if (elem.matches('[data-name="comment_delete"')) {

}
  • insertAdjacentHTML : 태그 자체를 추가함
    • element.insertAdjacentHTML(position, text)
      • position : 추가할 위치
      • text : 추가할 데이터
  • 게시 버튼을 누르면 통신됨
    • 똑같은 글자가 들어옴 : comment.html에 있는 글자를 찍어내기 때문임

4) 댓글 게시 후 입력글자 초기화

main.js

else if (elem.matches('[data-name="comment"')) {
        let content = document.querySelector('#add-comment-post37 > input[type=text]').value;

        console.log(content);
        if (content.length > 140) {
            alert('댓글 최대 140자 입력 가능. 현재 글자수 : ' + content.length);
            return;
        }
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: './comment.html',
            data: {
                'pk': 37,
                'content': content
            },
            dataType: 'html',  //어떤 데이터로 들어오는지 설정
            success: function (data) {
                document.querySelector('#comment-list-ajax-post37').insertAdjacentHTML('afterbegin', data);
            },
            error: function (request, status, error) {
                alert('에러 발생-comment');
            }
        })
        document.querySelector("#add-comment-post37 > input[type=text]").value = '';
    } else if (elem.matches('[data-name="comment_delete"')) {
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/delete.json',
            data: {
                'pk': 37
            },
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {
                if (response.status) {
                    let comt = document.querySelector('.comment-detail');
                    comt.remove();
                }
            },
            error: function (request, status, error) {
                alert('에러 발생-comment delete');
                window.location.replace('https://www.naver.com');
            }
        })
    }
  • 삭제 버튼 눌렀을 때 버튼이 삭제되고 ajax 통신이 됨

5) 팔로우 기능

main.js

else if (elem.matches('[data-name="follow"')) {
        $.ajax({
            Method: 'POST', //에러 시 GET으로 변경
            url: 'data/follow.json',
            data: {
                'pk': 37
            },
            dataType: 'json',  //어떤 데이터로 들어오는지 설정
            success: function (response) {
                if (response.status) {
                    document.querySelector('input.follow').value = "팔로잉";
                } else{
                    document.querySelector('input.follow').value = "팔로워";
                }
            },
            error: function (request, status, error) {
                alert('에러 발생-comment delete');
                window.location.replace('https://www.naver.com');
            }
        })
    } 
  • input값을 동일하게 사용
    • input의 submit 태그를 통해 값 구분할 것 : 값에 따라 글자 변경

index.html

 <div class="sprite_more_icon" data-name="more">
                                    <ul class="toggle_box">
                                        <li>
                                            <input type="submit" class="follow" value="팔로우" data-name="follow">
                                        </li>
                                        <li>수정</li>
                                        <li>삭제</li>
                                    </ul>
                                </div>
                            </header>
  • input의 submit
    • class : follow
    • data-name : follow

css

.contents .sprite_more_icon.on .toggle_box{
    display: block;
}

.contents .toggle_box{
    text-align: center;
    position:absolute;
    height: 0;
    top:20px;
    border : 1px solid rgba(0, 0, 0, 0.09);
    border-radius:3px;
    display:none;
}

.contents .toggle_box > li{
    padding: 5px 10px;
    background: #fff;
}

.contents .toggle_box > li input{
    border : none;
    font-size:inherit;
}


  • 누르는 순간 글자변경됨

6) 무한 스크롤 기능 추가

  • article 여러개 복사하여 여러 컨텐츠 나오도록 설정
  • id가 page인 input태그를 하나 만들어서 페이지 개수를 체크

main.js

function scrollFunc() {

    var scrollHeight = pageYOffset + window.innerHeight;
    var documentHeight = document.body.scrollHeight;


    // console.log(pageYOffset);

    if (pageYOffset >= 10) {
        header.classList.add('on');


        if (sidebox) {
            sidebox.classList.add('on');
        }

        resizeFunc();


    } else {
        header.classList.remove('on');

        if (sidebox) {
            sidebox.classList.remove('on');
            sidebox.removeAttribute('style');
        }

    }

    console.log('scrollHeight : ' + scrollHeight);
    console.log('documentHeight : ' + documentHeight);

    if (scrollHeight >= documentHeight) {

        var page = document.querySelector('#page').value;

        // page = parseInt(page) + 1;
        // page = parseInt(page) + 1;
        document.querySelector('#page').value = parseInt(page) + 1;
        // $('#page').val(parseInt(page) + 1);

        callMorePostAjax(page);

        if (page > 10) {
            return;
        }

    }

}

function callMorePostAjax(page) {

    if (page > 10) {
        return;
    }

    $.ajax({
        type: 'GET',
        url: "./post.html",
        data: {
            'page': page,
        },
        success: addMorePostAjax,
        dataType: 'html',
        error: function (request, status, error) {
            alert('오류발생');
            // alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
        },
    });

}

function addMorePostAjax(data) {

    delegation.insertAdjacentHTML("beforeend", data);
}
  • scrollHeight = pageYOffset + window.innerHeight;
    • pageYOffset : 화면을 어느정도 내렸는지 의미하는 y값
    • window.innerHeight : 화면의 세로값 의미
  • documentHeight = document.body.scrollHeight;
    • 스크롤의 길이값
    • scrollHeight와 동일해진 경우, 스크롤을 전부 아래로 내린 상황임
  • ajax 통신을 통해 post.html을 index.html에 추가함
  • 일정 스크롤 이상으로 내려가게 되면 ajax로 다른 포스트 전송하라는 메시지를 보내도록 함.

profile
hello world!

0개의 댓글