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

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

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

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

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

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

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

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

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

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

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

            

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

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

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

.rating .rate_radio + label {    position: relative;    display: inline-block;    margin-left: -4px;    z-index: 10;    width: 60px;    height: 60px;    background-image: url('./backup/695/img/starrate.png');    background-repeat: no-repeat;    background-size: 60px 60px;    cursor: pointer;    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-width: 480px;    margin: 0 auto; /* 화면 가운데로 */    background-color: #fff;    height: 100%;    padding: 20px;    box-sizing: border-box;
}.reviewform textarea{    width: 100%;    padding: 10px;    box-sizing: border-box;}.rating .rate_radio {    position: relative;    display: inline-block;    z-index: 20;    opacity: 0.001;    width: 60px;    height: 60px;    background-color: #fff;    cursor: pointer;    vertical-align: top;    display: none;}.rating .rate_radio + label {    position: relative;    display: inline-block;    margin-left: -4px;    z-index: 10;    width: 60px;    height: 60px;    background-image: url('./backup/695/img/starrate.png');    background-repeat: no-repeat;    background-size: 60px 60px;    cursor: pointer;    background-color: #f0f0f0;}.rating .rate_radio:checked + label {    background-color: #ff8;}
.warning_msg {    display: none;    position: relative;    text-align: center;    background: #ffffff;    line-height: 26px;    width: 100%;    color: red;    padding: 10px;    box-sizing: border-box;    border: 1px 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(item, idx){        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다운로드