Tempo Di Valse

[Vue.js] 커스텀 Checkbox 만들어보기 본문

개발/Web

[Vue.js] 커스텀 Checkbox 만들어보기

TempoDiValse 2022. 2. 17. 15:23

UI 를 만들다 보면, 디자이너가 그려주는 UI 에서는 시스템에서 제공해주는 UI 와는 많이 다른 신기하게 생긴 컴포넌트들이 많이 보이곤 한다.

 

게다가 기능이 이미 코어에도 존재하는 것들, <input> 계열의 checkbox 나 radio, <select> 의 경우에는 기능은 유지하되, 겉의 모습만 바뀌는 것을 많이 볼 수 있다. 하지만 <div> 레이어 같은 아이들이 아니라서 새로 스타일을 정의하기에는 많은 어려움을 가지고 있다.

 

그래서 이런 것들은 웬만하면 크게 커스터마이즈하여 디자인을 맞추곤 하는데, 이번 포스팅은 그 중에서 커스터마이즈 하기가 쉬운 Checkbox 를 Vue.js 를 통해서 만져보도록 하겠다.


먼저 일반적인 체크박스 의 구조를 보게 되면,

 

1. 라벨이 씌워지지 않은 체크박스   

 

2가지 타입의 체크박스를 볼 수 있다. 해당 타입들을 소스로 본다면,

<input type="checkbox"> 1. 라벨이 씌워지지 않은 체크박스

<label for="chk"><input id="chk" type="checkbox">2. 라벨이 씌워진 체크박스</label>

둘의 차이는, 전자는 체크박스 영역만 눌러야 ON/OFF 가 변경되고 후자는 체크박스 영역 뿐만 아니라 글씨 영역도 클릭하면 체크 ON/OFF 에 반영이 되는 것이다. 보통 후자의 방식으로 사용되곤 한다.

 

그래서, 후자의 방식으로 시작을 해보도록 하자.

 

1. Vue 컴포넌트 생성

 

먼저, 독립적인 vue 파일을 생성했고, 기본적인 골격을 삽입해준다.

<templete>
    <label for="chk">
    	<input id="chk" type="checkbox">
    </label>
</templete>

<script>
export default {
    name: 'Checkbox',
}
</script>

여기에서 prop 으로 체크박스의 값을 입력받을 변수와, 라벨에 들어갈 문자가 들어갈 변수를 추가해준다.

<templete>
    <label for="chk">
    	<input id="chk" type="checkbox" :value="checked">
        {{ label }}
    </label>
</templete>

<script>
export default {
    name: 'Checkbox',
    props: {
    	checked: {
            type: Boolean,
            default: false
        },
        
        label: String,
    },
}
</script>

그럼 외부에서는 다음의 형태로 접근할 수 있을 것이다.

<checkbox label="체크박스입니다" checked="true" />

 

이 상태에서 컴포넌트를 등록하고 사용하려 해도 데이터를 받지 못한다. 그래서 양방향 데이터 바인딩 이라는 방식을 적용해 주어야 하는데 적용을 하게되면 컴포넌트 외부에서 체크박스 컴포넌트의 상태 변경을 알 수 있다.

 

자세한 사항은 공식 홈페이지 문서를 참조하도록 한다

 

폼 입력 바인딩 — Vue.js

Vue.js - 프로그레시브 자바스크립트 프레임워크

kr.vuejs.org

지금의 소스에서양방향 데이터 바인딩을 적용해본다면,

 

1. 외부에서 컴포넌트로 접근할 수 있는 변수를 'checked' 로 지정해 준다. 

2. <input> 에 체크박스가 눌린 이벤트가 감지되면, 상태값 변경에 대해 알려준다

 

<templete>
    <label for="chk">
    	<input id="chk" type="checkbox" :value="checked" @input="$emit('input', !checked)">
        {{ label }}
    </label>
</templete>

<script>
export default {
    name: 'Checkbox',
    props: {
    	checked: {
            type: Boolean,
            default: false
        },
        
        label: String,
    },
    
    model: {
        prop: 'checked',
        event: 'input'
    }
}
</script>

1 항목의 경우는, 컴포넌트 옵션에 model 을 통해서 가능하다. model 옵션을 사용해야 외부에서 v-model 을 통해서 컴포넌트에 접근할 수 있다.

<checkbox v-model="checked" label="체크박스" />

prop 속성은 변수명을 넣어서 지정하면 되며, event 는 어떤 이벤트가 $emit 을 통해 불려지면 지정한 prop 의 값을 변경할 지 입력 하는 곳이다. 

 

예를 들어, model 의 prop 가 'selected' 이고 event 가 'changed' 라고 하면, $emit('changed', 0); 을 호출할 경우 selected 는 0 이 들어갈 것이고 컴포넌트 외부에도 0으로 알려줄 것이다. 1 이면 1을 알려줄 것이다.

 

여기까지 일단 체크박스에 대한 컴포넌트를 만들어주었다. 다음은 스타일을 입혀보자

 

2. Style 적용

 

일단, 스타일에 대해서는 사용자가 짜기 나름이기 때문에 예시가 100% 정답이 아닐 수 있는 것을 감안하자.

먼저, 기존 체크박스를 대체할 UI 를 만들기 위해서 ON/OFF 이미지를 준비한다.

그리고서 <template> 에 새 체크박스이미지가 들어갈 부분을 추가해준다.

<templete>
    <label for="chk">
    	<input id="chk" type="checkbox" :value="checked" @input="$emit('input', !checked)">
        <span class="check" :class="{ on : checked }"></span>
        {{ label }}
    </label>
</templete>

checked 값이 변경 될 때마다 on 클래스가 check 뒤에 붙고 빠지고 하면서 ON/OFF 상태 값을 변경할 것이다.

 

다음은 <style> 태그를 사용하여 UI 를 세세하게 변경을 시켜주도록 한다. 변경 하면서 다음의 명세를 코드도 함께 포함할 것이다.

1. 기존의 체크박스 UI는 사용하지 않기 때문에 보이지 않도록 한다.
2. 체크박스 ON/OFF 에 따라 이미지를 뿌려주도록 한다.
<style>

label { display:inline-block; cursor: pointer; }

/* 1번 명세 */
input[type="checkbox"] { display: none; }

/* 2번 명세 */
span.check { display:inline-block; width: 24px; height: 24px; background: url('${check_off_image}') no-repeat; background-size: 100%; }
span.check.on { background: url('${check_on_image}') no-repeat; background-size: 100%; }

</style>

 

 

3. 적용

 

적용은 별 다른 것 없이 사용할 곳에다가 컴포넌트를 추가하면 된다.

<checkbox v-model="checked" label="체크박스라벨명" />

v-model 이외에도 input 이벤트를 감지하여 사용할 수도 있다.

<checkbox label="체크박스라벨명" @input="onCheckedChange" />

대신에 메소드를 정의하여 값을 받아와야 하는 단점이 있다.

반응형
Comments