본문 바로가기

Javascript/활용팁&실전예제

프로토타입으로 별점 댓글 기능 구현하기

반응형

쇼핑몰, 또는 커뮤니티 게시판의 리뷰 평점, 또는 후기 평점 기능을 자바스크립트 프로토타입으로 구현해보겠습니다.


별점이라고도 하는데, 대부분은 별 5개로된 평가 점수를 선택하고, 댓글 내용을 입력한 후 저장하는 방식으로 구현합니다.

기능의 핵심은 별 갯수를 선택하는 방식이며, 4번째 별을 클릭하면 1 ~ 4까지의 별이 선택되어 보여야 합니다.

부가적으로는 별점의 평균을 구해 평점만큼 별을 채워 표시하는 것을 구현합니다.



별점 기능을 구현하기 위해서는 디자인 이미지와 CSS의 힘을 필요로 합니다. 

여기서는 미리 이미지와 구조가 만들어진 디자인 샘플을 이용해 사용자 클릭에 따라 이벤트 리스너가 적절한 동작을 하는 것만을 구현합니다.


먼저 별점을 부여하는데 필요한 디자인 이미지와 CSS에 대해 이해를 해야 합니다.

별점용 이미지는 가운데 별모양이 투명하게 뚤린 PNG 이미지입니다.

첨부된 압축파일을 다운로드 받아 압축 풀면 별모양이 투명하게 뚤린 png 파일을 사용할 수 있습니다.


starrate.zip



별 이미지를 배경이미지로 사용한 라벨 태그(<label></label>)의 배경색을 이용해 별의 색상을 조정합니다.

            

라벨 태그는 체크박스에 붙은 라벨이며, 라벨을 클릭하면 실행하는 이벤트 리스너를 이용해 체크 박스를 같이 체크합니다.

CSS는 아래처럼 체크 박스가 체크된 경우와 아닌 경우로 만들어서 체크박스만 체크하면 별의 색상이 자동으로 적용되도록 합니다.


이미지를 사용하는 체크박스를 이용해 다중 선택을 하는 용도로 많이 사용하는 기법이므로 꼭 알아둘 필요가 있습니다.


.rating .rate_radio + label {
    positionrelative;
    displayinline-block;
    margin-left-4px;
    z-index10;
    width60px;
    height60px;
    background-imageurl('./img/starrate.png');
    background-repeatno-repeat;
    background-size60px 60px;
    cursorpointer;
    background-color#f0f0f0;
}
.rating .rate_radio:checked + label {
    background-color#ff8;
}



HTML 페이지는 아래와 같이 만듭니다.

중요한 것은 별표를 표시하는 체크박스와 체크박스에 달린 라벨 태그입니다.

위 CSS와 조합해서 별표를 표시하게 됩니다.


<div class="wrap">
    <h1>후기</h1>
    <form name="reviewform" class="reviewform" method="post" action="/save">
        <input type="hidden" name="rate" id="rate" value="0"/>
        <p class="title_star">별점과 리뷰를 남겨주세요.</p>
 
        <div class="review_rating">
            <div class="warning_msg">별점을 선택해 주세요.</div>
            <div class="rating">
                <!-- 해당 별점을 클릭하면 해당 별과 그 왼쪽의 모든 별의 체크박스에 checked 적용 -->
                <input type="checkbox" name="rating" id="rating1" value="1" class="rate_radio" title="1점">
                <label for="rating1"></label>
                <input type="checkbox" name="rating" id="rating2" value="2" class="rate_radio" title="2점">
                <label for="rating2"></label>
                <input type="checkbox" name="rating" id="rating3" value="3" class="rate_radio" title="3점" >
                <label for="rating3"></label>
                <input type="checkbox" name="rating" id="rating4" value="4" class="rate_radio" title="4점">
                <label for="rating4"></label>
                <input type="checkbox" name="rating" id="rating5" value="5" class="rate_radio" title="5점">
                <label for="rating5"></label>
            </div>
        </div>
        <div class="review_contents">
            <div class="warning_msg">5자 이상으로 작성해 주세요.</div>
            <textarea rows="10" class="review_textarea"></textarea>
        </div>   
        <div class="cmd">
            <input type="button" name="save" id="save" value="등록">
        </div>
    </form>
</div>



CSS 를 적용해 별점 체크박스의 이미지와 리뷰 내용 작성 텍스트영역을 배치합니다.

여기서 중요한 것은 별점 기능이기 때문에 크게 관련이 없는 CSS는 생략했습니다.


/* 레이아웃 외곽 너비 400px 제한*/
.wrap{
    max-width480px;
    margin0 auto/* 화면 가운데로 */
    background-color#fff;
    height100%;
    padding20px;
    box-sizingborder-box;

}
.reviewform textarea{
    width100%;
    padding10px;
    box-sizingborder-box;
}
.rating .rate_radio {
    positionrelative;
    displayinline-block;
    z-index20;
    opacity0.001;
    width60px;
    height60px;
    background-color#fff;
    cursorpointer;
    vertical-aligntop;
    displaynone;
}
.rating .rate_radio + label {
    positionrelative;
    displayinline-block;
    margin-left-4px;
    z-index10;
    width60px;
    height60px;
    background-imageurl('./img/starrate.png');
    background-repeatno-repeat;
    background-size60px 60px;
    cursorpointer;
    background-color#f0f0f0;
}
.rating .rate_radio:checked + label {
    background-color#ff8;
}

.warning_msg {
    displaynone;
    positionrelative;
    text-aligncenter;
    background#ffffff;
    line-height26px;
    width100%;
    colorred;
    padding10px;
    box-sizingborder-box;
    border1px solid #e0e0e0;
}



이제 자바스크립트로 별점 선택 기능을 구현해보겠습니다.

먼저 프로토타입으로 별점 모듈을 만듭니다.


//별점 마킹 모듈 프로토타입으로 생성
function Rating(){};
Rating.prototype.rate = 0;
Rating.prototype.setRate = function(newrate){
    //별점 마킹 - 클릭한 별 이하 모든 별 체크 처리
    this.rate = newrate;
    let items = document.querySelectorAll('.rate_radio');
    items.forEach(function(itemidx){
        if(idx < newrate){
            item.checked = true;
        }else{
            item.checked = false;
        }
    });
}
let rating = new Rating();//별점 인스턴스 생성


Rating.rate 는 선택한 별점 값을 저장하는 변수입니다.

setrRate() 메서드는 클릭한 별점을 포함해 그 왼쪽에 있는 모든 별점의 체크박스를 체크하는 기능을 합니다.

위 CSS 에서 정의한 것처럼 체크한 체크박스는 배경색이 다른 색으로 바뀌면서 별점 표시가 됩니다.


별점 클릭 이벤트 리스너를 등록해 별 이미지를 클릭하면 별점 모듈의 setRate() 메서드를 호출하도록 합니다.


document.addEventListener('DOMContentLoaded'function(){
    //별점선택 이벤트 리스너
    document.querySelector('.rating').addEventListener('click',function(e){
        let elem = e.target;
        if(elem.classList.contains('rate_radio')){
            rating.setRate(parseInt(elem.value));
        }
    })
});



별점 기능이 완성되었습니다.


이제 별점 선택을 하지 않았을 때, 또는 후기 내용을 5자 미만으로 입력했을 때 메시지를 표시하는 기능을 추가해 후기 작성 폼의 완성도를 높입니다.


바로 위에 작성한 초기화 이벤트 리스너에 다음 이벤트 리스너 2개를 추가합니다.


첫번째 이벤트 리스너는 후기 내용이 400자를 초과할 경우 400자 이상 입력되지 않도록 막아주는 기능을 합니다.

정규표현식 "/^.{400,}$/" 이 중요합니다. 

400자 이상인지를 체크하는 정규표현식입니다. 후기 글자수를 변경하려면 400 을 다른 값으로 변경하면 됩니다.

초과된 경우 "review.value.substr(0,400)" 함수로 400자만 잘라서 후기 내용으로 남기는 처리를 합니다.


두번째 이벤트 리스너는 "등록" 버튼을 누르면 별점과 후기 내용을 체크합니다.

별점 프로토타입 모듈의 rate 변수가 0보다 큰지 체크를 한후, 후기 내용이 5보다 큰지 확인합니다.


    //상품평 작성 글자수 초과 체크 이벤트 리스너
    document.querySelector('.review_textarea').addEventListener('keydown',function(){
        //리뷰 400자 초과 안되게 자동 자름
        let review = document.querySelector('.review_textarea');
        let lengthCheckEx = /^.{400,}$/;
        if(lengthCheckEx.test(review.value)){
            //400자 초과 컷
            review.value = review.value.substr(0,400);
        }
    });

    //저장 전송전 필드 체크 이벤트 리스너
    document.querySelector('#save').addEventListener('click'function(e){
        //별점 선택 안했으면 메시지 표시
        if(rating.rate == 0){
            rating.showMessage('rate');
            return false;
        }
        //리뷰 5자 미만이면 메시지 표시
        if(document.querySelector('.review_textarea').value.length < 5){
            rating.showMessage('review');
            return false;
        }
        //폼 서밋
    });


이벤트 리스너에 정의한 showMessage() 메서드를 프로토타입 모듈에 추가합니다.

메서드 하나로 처리하기 위해 파라메터로 메시지 타입을 구분해 표시되도록 했습니다.


타이머 함수를 사용한 것은 표시한 메시지가 지정된 시간 후 자동으로 사라지도록 하기 위한 것입니다.




Rating.prototype.showMessage = function(type){//경고메시지 표시
    switch(type){
        case 'rate':
            //안내메시지 표시
            document.querySelector('.review_rating .warning_msg').style.display = 'block';
            //지정된 시간 후 안내 메시지 감춤
            setTimeout(function(){
                document.querySelector('.review_rating .warning_msg').style.display = 'none';
            },1000);            
            break;
        case 'review':
            //안내메시지 표시
            document.querySelector('.review_contents .warning_msg').style.display = 'block';
            //지정된 시간 후 안내 메시지 감춤
            setTimeout(function(){
                document.querySelector('.review_contents .warning_msg').style.display = 'none';
            },1000);    
            break;
    }
}




추가적으로 별점 반개, 또는 소수점 숫자 만큼 별을 채우려면 개별 별 이미지 배경색을 지정하는 방식으로는 구현이 되지 않습니다.

별들 전체 배경으로 블록 태그(<div>) 를 하나 배치한 후 블록 태그 너비를 별점 숫자 만큼 늘려서 채우는 방식으로 구현해야 합니다.




소수점으로 별점 일부만 채색되도록 구현한 소스를 아래 첨부합니다.


rating2.zip





별점 선택 폼이 여러 개인 상황에 대응할 수 있도록 기본 로직을 구현한 샘플 소스 코드를 첨부합니다.


rating2-1.zip


반응형
  • 비밀댓글입니다

  • 비밀댓글입니다

  • 남풍문 2020.12.08 21:19 댓글주소 수정/삭제 댓글쓰기

    포스팅 감사합니다
    혹시 별점 반개짜리를 구현하고 싶을 때는 어떻게 하면 좋을까요??

    • 애초에 별이 5개로 갯수 선택이기 때문에 전체 평균을 소수점으로 추가로 표시하는 경우가 아니면 반개나 소수점이 의미는 없습니다.

      구조적으로는 개별 별점 이미지의 배경색을 지정하는 방식이 아니라, 별점 밑에 별점 배경색으로 채울 블록 태그를 추가해서 별점 갯수에 따라 너비를 늘리는 방식으로 구현을 해야 합니다.

      소수점 단위도 처리가 가능하기 때문에
      setRate(별점);
      메서드에 소수점 단위 숫자를 넣을 수 있습니다.

      글 끝부분에 소수점 단위로 별점을 넣을 수 있게 수정한 소스를 압축해서 붙였습니다.

      다운받아서 참고하시기 바랍니다.

  • 비밀댓글입니다

    • 질문하신 의도를 정확히 이해를 못하겠습니다.

      별점 선택폼이 여러 개 있는걸 선택자로 이벤트 처리를 구분할 수 있게 하고 싶은게 아닌가 싶은데...

      구현 방법은 여러가지가 있을텐데, 구조적으로는 자바스크립트를 손을 조금 많이 대야 합니다.

      별점 단위로 이벤트가 처리되도록 하는 소스를 글 끝에 첨부했습니다.
      주석도 좀 달았으니까 의도하신게 이게 맞으면 참고가 되실 겁니다.

      기본 개념만 구현한거라 그렇게 코드가 깔끔하지는 않습니다. 참고용으로 로직을 이해하는 용도로 보시면 됩니다.

  • test 2021.01.01 14:46 댓글주소 수정/삭제 댓글쓰기

    5자 이상의 리뷰 내용을 작성해 주세요. warning msg는 css가 제대로 안나오는데 방법을 알수있을까요 ㅠ

    • css가 안나온다는게 무슨 뜻인지 이해가 안됩니다.
      위에 글 내용의 css 정의한 예 끝에

      .warning_msg {
      }

      클래스가 경고 메시지 정의한 클래스이고 이걸 수정하면 경고 메시지 문구의 속성을 바꿀 수 있습니다.


닫기