본문 바로가기
Vue

Vue 디렉티브(directive) - checkbox

by sinabeuro 2021. 6. 7.
728x90

Vue 디렉티브를 활용하여 제가 현업에서 쓴 코드를 일부 소개하려합니다. Vue 디렉티브 개념은 이전 글을 참고해주세요.

 

구현할 체크박스

vue 디렉티브 체크박스 구현

1. vue-js선언

// 표시할 데이터 리스트
this.dataList = [
             {key:'first', val:'01'},
             {key:'second', val:'02'},
             {key:'third', val:'03'},
             {key:'fourth', val:'04'},
             {key:'fifth', val:'05'},
         ];
         
// 체크박스의 v-model 파라미터(vue에서 체크박스 구현시 v-model 파라미터는 꼭 배열로 선언해야합니다.)
this.checkList = [];

 

2. html

<table>
<thead>
	<tr>
    	<th><input type="checkbox" v-mocheckbox:prdGroupCheckbox v-model="checkList" v-bind:value="0" v-if="dataList.length>0"></th>
        <th>key</th>
        <th>val</th>
    </tr>
</thead>
	
<tbody>    
    <tr v-for="(item,idx) in dataList">
    	<th><input type="checkbox" class="prdGroupCheckbox" v-mocheckbox:prdGroupCheckbox v-model="checkList" v-bind:value="item.val" v-if="dataList.length>0"></th>
        <th>{{item.key}}</th>
        <th>{{item.val}}</th>
    </tr>
</tbody>
</table>

<!-- 전체 체크 버튼 -->

<input type="checkbox" id="checkall" v-mocheckbox:checkitem v-model="checkList" v-bind:value="0" v-if="dataList.length>0>

전체 체크 버튼의 value를 0으로 주었고 나머지는 리스트의 값들의 value는 0이 아닌 유니크 값으로 주어야합니다.

v-mocheckbox:checkitem의 v-mocheckbox는 디렉티브명이고 뒤에 checkitem은 파라미터이며 class명을 파라미터로 넘긴 것입니다.

 

<!-- 리스트 체크 버튼 -->

<input type="checkbox" class="checkitem" v-mocheckbox:checkitem v-model="checkList" v-bind:value="item.val" v-if="dataList.length>0">

전체 체크 버튼과 동일하게 v-mocheckbox는 디렉티브명과 파라미터 checkitem를 넘겨줍니다.

주의) 태그에 v-if="dataList.length>0"를 쓴 이유는 해당 화면이 display:none과 같이 화면이 show/hide 될 경우 v-model에 relendering이 필요하기 때문에 작성한 코드입니다. 또한 해당 화면을 호출할 경우 this.dataList를 초기화해야 relendering이 됩니다.

 

3. vue-directive checkbox 구현

Vue.directive("mocheckbox",{
    bind: function(el, binding, vnode) {
        var vdirective = vnode.data.directives,
            vModel;
        for(var i = 0, vDirLength = vdirective.length ; i < vDirLength ; i++) {
            //console.log(vdirective[i].name );
            if(vdirective[i].name == "model"){
                //vModel = vdirective[i].expression;
                vModel = vdirective[i];
                break;
            }
        }
        var selected = vModel.value;
        var selectedCnt = 5;
        var childClass="checkitem";
        if(binding.arg) {
            childClass=binding.arg;
        }

        $(el).off("click").on("click", function (e) {
            if($(e.currentTarget).prop("checked") == true && $(e.currentTarget).val() == "0") {    // 전체 체크박스 클릭
                selected.splice(0,selected.length);
                selected.push($(e.currentTarget).val());
                $("."+childClass).each(function(index,item){
                    if(selected.indexOf($(item).val()) == -1) {
                        selected.push($(item).val());
                    }
                });
                selectedCnt = selected.length-1;    // 자식 체크박스 수
            } else if($(e.currentTarget).prop("checked") == false && $(e.currentTarget).val() == "0") {	// 전체 체크박스 해제
                selected.splice(selected.indexOf($(e.currentTarget).val()),1);
                //해제됨
                $("."+childClass).each(function(index,item){
                    if($(item).is(":checked")) {
                        $(item).prop("checked", false);
                        selected.splice(selected.indexOf($(item).val()),1);
                    }
                });
            } else if($(e.currentTarget).prop("checked") == true && $(e.currentTarget).val() != "0") {	// 단일 리스트 체크박스 클릭
                var temp = 0;
                try {
                    temp = $("."+childClass).length;
                } catch (e) {
                    temp = 0;
                }
                selectedCnt = temp;    // 자식 체크박스 수
                if(typeof temp != 'object') {
                    temp = 0;
                }
                if(selected.indexOf($(e.currentTarget).val()) == -1) {	// 단일 리스트 체크박스 해제
                    selected.push($(e.currentTarget).val());
                }
                if(selected.length >= selectedCnt) {
                    selected.push("0");
                }
            } else if($(e.currentTarget).prop("checked") == false && $(e.currentTarget).val() != "0") {
                var temp = selected.indexOf("0");
                if(temp > -1) {
                    selected.splice(temp,1);
                }
                selected.splice(selected.indexOf($(e.currentTarget).val()),1);
            }
        });

    },
    inserted: function(el, binding, vnode){

    },
    update: function (el, binding, vnode) {

    }
});

 

html에서 v-mocheckbox:checkitem 클래스명을 파라미터로 넘겼으며, binding.arg로 파라미터(클래스명)을 받습니다.

vnode.data.directives 프로퍼티를 통해서 바인딩된 v-model을 가져옵니다. 체크/해제 시 v-model의 값을 수정합니다. v-model은 배열로 선언했기 때문에 배열의 값을 push, splice 함수를 통해 수정합니다.

 

위의 코드는 4가지 경우의 수를 구현했습니다. - 전체 체크박스 클릭    => 모든 체크박스가 클릭됨
- 전체 체크박스 해제
   => 모든 체크박스가 해제됨
- 단일 리스트 체크박스 클릭
   => 단일 체크박스가 체크되며 모든 단일 박스가 클릭되면 전체 체크박스도 체크됩니다.
- 단일 리스트 체크박스 해제
   => 단일 체크박스가 해제되면 전체 체크박스도 해제됩니다.

 

저는 v-model과 클래스명 두가지를 이용해서 v-directive를 구현했습니다. 혹시나 클래스명말고 다른 파라미터로 구현할 수 있다면 공유해주시면 좋을 것 같습니다. ^^오늘 글은 간단한 v-directive 체크박스 구현 코드를 공유해보았습니다. 다음에 좀 더 좋은 코드가 생각나면 공유할 수 있도록 하겠습니다!!!

728x90

'Vue' 카테고리의 다른 글

Vue - Vuex  (0) 2022.03.25
Vue에서 fontawesome 설치 및 적용  (0) 2022.02.16
Vue - 팝업 창에서 뒤로가기 구현  (0) 2022.02.07
Vue 컴퍼넌트(Component) - 페이징 처리  (0) 2021.06.10
Vue 디렉티브(directive) 개념  (0) 2021.06.01

댓글