얼마전에 기획자분으로부터 input을 입력할때마다 1000단위로 콤마(,)가 찍히도록 해달라는 요청을 받았습니다. 구글링을 해서 찾아보니 keyup이벤트에 listener를 걸어서 value를 제어하라는 내용이 있더군요.

그대로 해보니 몇가지 문제가 있었습니다.

* 숫자가 replace되는게 화면에서 슬쩍슬쩍 보여서 거슬린다.
* 입력 가능한 키값에 숫자 뿐아니라, 방향키, tab, cmd + c, cmd + v 등도 추가해줘야 하는데... 짜친다...
* 한글은 몬가 이상하다. 조합형으로 글자가 완성되다보니 이전에 입력한 값을 기억하고 있는것같다. ㅜ

이래서 포기하려고 했는데.. 우연히 oninput이라는 이벤트를 발견했습니다.

oninput

oninput은 input, textarea 엘리먼트의 값이 변경되었을때 반응하여 실행됩니다. 방향키나 복사는 입력이 아니기 때문에 반응하지 않죠. 또한 keyup이벤트보다 먼저 발생하기 때문에 input요소가 바뀌는 부자연스러운 것도 없어집니다.

만들어보죠.

천단위 콤마찍기
1
<input type="text" id="i">
1
2
3
4
5
6
7
document.getElementById("i").addEventListener('input', (e) => {
const i = e.target;
const startPosition = i.value.length - i.selectionEnd;
i.value = i.value.replace(/^0+|\D+/g, '').replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');
const len = Math.max(i.value.length - startPosition, 0);
i.setSelectionRange(len, len);
});

소스가 길지만 핵심은 javascript4번째 줄입니다. 숫자가 아니거나, 첫 글자가 0이면 지워버립니다(/^0+|\D+/g). 그리고 1000단위로 콤마를 찍죠(/(\d)(?=(?:\d{3})+(?!\d))/g).
나머지 위아래는 커서를 맞취기 위한 소스입니다. 기본적으로 text를 replace하고 나면 커서가 맨 오른쪽으로 이동해 버립니다. 따라서 입력할때의 커서 위치를 기억해서 replace 후에 다시 해당 위치로 커서를 보내는 거죠.

input 값 가져오기

값을 입력하는 것을 했으니 이제 값을 가져오는 것을 구해봅시다. 그냥 값을 가져오게 되면 input요소의 값에 콤마가 찍혀있으므로 우리가 원하는 number형태가 아닙니다. 따라서 해당 엘리먼트에 getter 요소를 만들어서 값을 가져와 봅시다.

천단위 콤마찍기Go to jsfiddle
1
2
<input type="text" id="i">
<button id="b">Get Number</button>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const input = document.getElementById("i");
i.addEventListener('input', (e) => {
const i = e.target;
const startPosition = i.setSelectionRange && (i.value.length - i.selectionEnd);
i.value = i.value.replace(/^0+|\D+/g, '').replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');
const len = Math.max(i.value.length - startPosition, 0);
i.setSelectionRange && i.setSelectionRange(len, len);
});
Object.defineProperty(i, "numVar", {
get (){ return parseInt(i.value.replace(/^0+|\D+/g, ''))},
enumerable: true,
configurable: true
})
document.getElementById("b").addEventListener('click', (e) => alert(input.numVar))

참조

API Reference