jQuery로 작성된 바이트 체크 샘플
SMS 발송 관련 페이지에서 주로 사용된다.
소스코드의 자바스크립트 영역에서 2가지 방식을 지정해서 사용하면 된다.
1. const MAX_BYTES = 100;
- 허용가능한 최대 byte 수
2. const useUtf8Calculation = true;
- UTF8 형태로 byte를 계산할지 여부 (영문2, 한글3, 이모지4)
3. const textInput = $('#text-input');
- 입력 영역 지정 (textarea 를 지정한다. 이 부분은 키입력 이벤트와 이모지 등에서 사용된다)
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>실시간 바이트 체크 프로그램</title>
<!-- Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- jQuery CDN -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<style>
/* 기본 폰트 및 배경 설정 */
body {
font-family: 'Inter', sans-serif;
}
/* 이모지 팝업 기본 숨김 */
#emoji-modal {
display: none;
}
/* 스크롤바 디자인 */
#emoji-grid::-webkit-scrollbar {
width: 8px;
}
#emoji-grid::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 10px;
}
#emoji-grid::-webkit-scrollbar-thumb {
background: #888;
border-radius: 10px;
}
#emoji-grid::-webkit-scrollbar-thumb:hover {
background: #555;
}
</style>
</head>
<body class="bg-slate-100 flex items-center justify-center min-h-screen">
<div class="w-full max-w-2xl mx-auto p-6 md:p-8 bg-white rounded-2xl shadow-lg">
<h1 class="text-2xl md:text-3xl font-bold text-slate-800 mb-4 text-center">실시간 바이트 체크</h1>
<!-- 설명 문구에 ID 추가 -->
<p id="description" class="text-slate-600 mb-6 text-center"></p>
<!-- 글자 입력 폼 -->
<div class="relative">
<textarea id="text-input" class="w-full h-64 p-4 border border-slate-300 rounded-xl resize-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 transition duration-200" placeholder="여기에 텍스트를 입력하세요..."></textarea>
</div>
<!-- 바이트 표시 및 버튼 영역 -->
<div class="flex justify-between items-center mt-4">
<div class="flex gap-2">
<button id="clear-btn" class="px-4 py-2 bg-red-500 text-white font-semibold rounded-lg hover:bg-red-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition-colors duration-200">
모두 지우기
</button>
<button id="emoji-btn" class="px-4 py-2 bg-yellow-500 text-white font-semibold rounded-lg hover:bg-yellow-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-yellow-500 transition-colors duration-200">
이모지
</button>
</div>
<div id="byte-counter" class="text-lg font-semibold text-slate-700 bg-slate-200 px-4 py-2 rounded-lg">
0 / 100 byte
</div>
</div>
</div>
<!-- 이모지 선택 팝업 (Modal) -->
<div id="emoji-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div class="bg-white rounded-2xl shadow-xl p-6 w-full max-w-md">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-slate-800">이모지 선택</h3>
<button id="close-modal-btn" class="text-slate-500 hover:text-slate-800 text-2xl">×</button>
</div>
<div id="emoji-grid" class="grid grid-cols-8 gap-2 text-2xl text-center h-64 overflow-y-auto pr-2">
<!-- 이모지가 여기에 동적으로 추가됩니다. -->
</div>
</div>
</div>
<script>
$(document).ready(function() {
const MAX_BYTES = 100;
// true: UTF-8 정확한 계산 (한글 3, 이모지 4바이트)
// false: 단순 계산 (영문 외 2바이트)
const useUtf8Calculation = true;
const textInput = $('#text-input');
// 페이지 로드 시 설명 문구를 MAX_BYTES 값에 맞춰 동적으로 설정
$('#description').text(`내용을 입력하면 실시간으로 바이트를 계산합니다. (최대 ${MAX_BYTES}바이트)`);
/**
* @description 입력된 문자열의 바이트를 계산하는 함수 (UTF-8 또는 단순 계산)
* @param {string} str - 바이트를 계산할 문자열
* @returns {number} 계산된 바이트 수
*/
function checkByte(str) {
let totalBytes = 0;
if (useUtf8Calculation) {
// UTF-8 정확한 계산
for (let i = 0; i < str.length; i++) {
const charCode = str.charCodeAt(i);
if (charCode < 0x80) { // 1바이트
totalBytes += 1;
} else if (charCode < 0x800) { // 2바이트
totalBytes += 2;
} else if (charCode < 0xD800 || charCode >= 0xE000) { // 3바이트 (한글 포함)
totalBytes += 3;
} else { // 4바이트 (이모지 등)
totalBytes += 4;
i++; // 서로게이트 페어이므로 다음 문자 건너뛰기
}
}
} else {
// 단순 계산 (영문 1, 그 외 2바이트)
for (let i = 0; i < str.length; i++) {
const charCode = str.charCodeAt(i);
totalBytes += (charCode > 127) ? 2 : 1;
}
}
return totalBytes;
}
/**
* @description 최대 바이트를 초과한 경우 문자열을 잘라내는 함수
* @param {string} str - 원본 문자열
* @param {number} maxBytes - 최대 허용 바이트
* @returns {string} 최대 바이트에 맞게 잘라낸 문자열
*/
function truncateText(str, maxBytes) {
let currentBytes = 0;
let truncatedStr = '';
for (let i = 0; i < str.length; i++) {
const charCode = str.charCodeAt(i);
let charByte = 0;
if (useUtf8Calculation) {
// UTF-8 바이트 크기 결정
if (charCode < 0x80) charByte = 1;
else if (charCode < 0x800) charByte = 2;
else if (charCode < 0xD800 || charCode >= 0xE000) charByte = 3;
else { charByte = 4; }
} else {
// 단순 계산 바이트 크기 결정
charByte = (charCode > 127) ? 2 : 1;
}
if (currentBytes + charByte > maxBytes) {
break; // 최대 바이트를 넘으면 루프 종료
}
currentBytes += charByte;
truncatedStr += str.charAt(i);
// 4바이트 문자(이모지)인 경우, 서로게이트 페어의 뒷부분도 포함
if (charByte === 4) {
truncatedStr += str.charAt(i + 1);
i++;
}
}
return truncatedStr;
}
/**
* @description UI에 현재 바이트 수를 업데이트하는 함수
* @param {number} current - 현재 바이트
* @param {number} max - 최대 바이트
*/
function updateByteDisplay(current, max) {
$('#byte-counter').text(`${current} / ${max} byte`);
if (current >= max) {
$('#byte-counter').removeClass('text-slate-700').addClass('text-red-600 font-bold');
} else {
$('#byte-counter').removeClass('text-red-600 font-bold').addClass('text-slate-700');
}
}
// 텍스트 입력 영역에서 키보드 입력이 발생할 때마다 실행
textInput.on('input keyup', function() {
let content = $(this).val();
let currentBytes = checkByte(content);
if (currentBytes > MAX_BYTES) {
// 필요 시 아래 주석을 해제하여 알림창을 활성화할 수 있습니다.
// alert('허용된 글자수를 초과하였습니다');
const truncatedContent = truncateText(content, MAX_BYTES);
$(this).val(truncatedContent);
currentBytes = checkByte(truncatedContent);
}
updateByteDisplay(currentBytes, MAX_BYTES);
});
// '모두 지우기' 버튼 클릭 시 실행
$('#clear-btn').on('click', function() {
textInput.val('');
updateByteDisplay(0, MAX_BYTES);
textInput.focus();
});
const emojis = [
'😀', '😃', '😄', '😁', '😆', '😅', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😗', '😙', '😚', '😋', '😛',
'😜', '🤪', '🤨', '🧐', '🤓', '😎', '🤩', '🥳', '😏', '😒', '😞', '�', '😟', '😕', '🙁', '☹️', '😣', '😖', '😫', '😩', '🥺', '😢',
'😭', '😤', '😠', '😡', '🤬', '🤯', '😳', '🥵', '🥶', '😱', '😨', '😰', '😥', '😓', '🤗', '🤔', '🤭', '🤫', '🤥', '😶', '😐', '😑',
'😬', '🙄', '😯', '😦', '😧', '😮', '😲', '🥱', '😴', '🤤', '😪', '😵', '🤐', '🥴', '🤢', '🤮', '🤧', '😷', '🤒', '🤕', '🤑', '🤠',
'❤️', '🧡', '💛', '💚', '💙', '💜', '🤎', '🖤', '🤍', '💔', '❣️', '💕', '💞', '💓', '💗', '💖', '💘', '💝', '💟', '👍', '👎', '👌',
'👋', '🤚', '🖐️', '✋', '🖖', '👌', '🤏', '✌️', '🤞', '🤟', '🤘', '🤙', '👈', '👉', '👆', '🖕', '👇', '☝️', '👍', '👎', '✊', '👊',
'🤛', '🤜', '👏', '🙌', '👐', '🤲', '🤝', '🙏', '✍️', '💅', '🤳', '💪', '🦾', '🦵', '🦿', '🦶', '👣', '👀', '👁️', '🧠', '🦴', '🦷',
'👅', '👄', '👶', '👧', '🧒', '👦', '👩', '🧑', '👨', '👩🦱', '🧑', '👨🦱', '👩🦰', '🧑🦰', '👨🦰', '👱♀️', '👱', '👱♂️', '👩🦳', '🧑🦳', '👨🦳',
'🐶', '🐱', '🐭', '🐹', '🐰', '🦊', '🐻', '🐼', '🐨', '🐯', '🦁', '🐮', '🐷', '🐽', '🐸', '🐵', '🙈', '🙉', '🙊', '🐒', '🐔', '🐧',
'🐦', '🐤', '🐣', '🐥', '🦆', '🦅', '🦉', '🦇', '🐺', '🐗', '🐴', '🦄', '🐝', '🐛', '🦋', '🐌', '🐞', '🐜', '🦟', '🦗', '🕷️', '🕸️',
'🔥', '✨', '⭐', '🌟', '💫', '💥', '☄️', '☀️', '🌤️', '⛅', '🌥️', '🌦️', '🌈', '☁️', '🌧️', '⛈️', '🌩️', '⚡', '❄️', '🌨️', '☃️',
'⛄', '🌬️', '💨', '💧', '💦', '🌊', '🎄', '🎉', '🎊', '🎈', '🎁', '💯', '🚀', '✅', '☑️', '✔️'
];
const emojiGrid = $('#emoji-grid');
emojis.forEach(emoji => {
const emojiButton = $('<button class="p-1 rounded-lg hover:bg-slate-200 transition-colors"></button>').text(emoji);
emojiGrid.append(emojiButton);
});
$('#emoji-btn').on('click', function() {
$('#emoji-modal').fadeIn(200);
});
$('#close-modal-btn, #emoji-modal').on('click', function(e) {
if (e.target === this) {
$('#emoji-modal').fadeOut(200);
}
});
$('#emoji-grid').on('click', 'button', function() {
const emoji = $(this).text();
const textarea = textInput[0];
const start = textarea.selectionStart;
const end = textarea.selectionEnd;
const text = textInput.val();
const newText = text.substring(0, start) + emoji + text.substring(end);
textInput.val(newText);
textarea.focus();
textarea.selectionStart = textarea.selectionEnd = start + emoji.length;
textInput.trigger('input');
$('#emoji-modal').fadeOut(200);
});
// 페이지 로드 시 초기 상태 설정
updateByteDisplay(0, MAX_BYTES);
});
</script>
</body>
</html>
'Web > JS & jQuery' 카테고리의 다른 글
jQuery 를 사용한 아코디언 형태의 [상품정보 더보기] (0) | 2025.09.24 |
---|---|
jQuery + Ajax 무한 스크롤 (페이징) (0) | 2025.09.03 |
동적 form 전송 (2) | 2025.07.28 |
JS와 jQuery 를 사용한 모듈화 (0) | 2024.09.26 |
유효성 검사 (1) | 2024.09.03 |