728x90
<div class="input_wrap input_item_area">
  <select class="select" onchange="num(this.value)">
    <option value="1">평수로 입력</option>
    <option value="2">가로 X 세로로 입력</option>
    <option value="3">㎡로 입력</option>
  </select>
  
  <!-- 평수로 입력 -->
  <div class="wrap" id="1">
    <div>
      <input type="text" class="input" placeholder="10" id="areaInput" oninput="convertToSquareMeters()"> <span class="txt">평</span>
    </div>
  </div>
  
  <!-- 가로세로로 입력 -->
  <div class="wrap" style="display: none;" id="2">
    <div>
      <span class="txt">가로</span>
      <input type="text" class="input" placeholder="6.8" id="widthInput" oninput="calculateArea()">
      <span class="txt">m</span>
    </div>
    <div class="divider">
      <span class="txt">세로</span>
      <input type="text" class="input" placeholder="7.15" id="heightInput" oninput="calculateArea()">
      <span class="txt">m</span>
    </div>
    <div>
      <span class="txt">총 면적</span>
      <input type="text" class="input" id="squareMeterInput" readonly> <span class="txt">㎡</span>
    </div>
  </div>
  
  <!-- ㎡로 입력 -->
  <div class="wrap" style="display:none" id="3">
    <div>
      <input type="text" class="input" placeholder="48.6" id="squareMeterInput2" oninput="convertToPyeong()"> <span class="txt">㎡</span>
    </div>
  </div>
</div>
function num(value) {
  // 모든 입력 필드를 숨김
  document.getElementById('1').style.display = 'none';
  document.getElementById('2').style.display = 'none';
  document.getElementById('3').style.display = 'none';

  // 선택한 값에 따라 해당 입력 필드 보이기
  document.getElementById(value).style.display = 'block';
}

function calculateArea() {
  const width = parseFloat(document.getElementById('widthInput').value) || 0;
  const height = parseFloat(document.getElementById('heightInput').value) || 0;
  const areaInSquareMeters = width * height;
  
  // 평으로 변환 (1평 = 3.3㎡)
  const areaInPyeong = areaInSquareMeters / 3.3; // 제곱미터를 평으로 변환
  
  // 평수 입력란에 결과 표시
  document.getElementById('areaInput').value = areaInPyeong.toFixed(2);
  
  // 제곱미터 입력란에 결과 표시
  document.getElementById('squareMeterInput').value = areaInSquareMeters.toFixed(2);
}

function convertToPyeong() {
  const squareMeters = parseFloat(document.getElementById('squareMeterInput2').value) || 0;
  
  // 평으로 변환 (1평 = 3.3㎡)
  const areaInPyeong = squareMeters / 3.3; // 제곱미터를 평으로 변환
  
  // 평수 입력란에 결과 표시
  document.getElementById('areaInput').value = areaInPyeong.toFixed(2);
}

function convertToSquareMeters() {
  const pyeong = parseFloat(document.getElementById('areaInput').value) || 0;
  
  // 제곱미터로 변환 (1평 = 3.3㎡)
  const areaInSquareMeters = pyeong * 3.3; // 평을 제곱미터로 변환
  
  // 제곱미터 입력란에 결과 표시
  document.getElementById('squareMeterInput').value = areaInSquareMeters.toFixed(2);
}
728x90
728x90

1. 비동기 처리

문제: 주어진 두 개의 비동기 함수 fetchData1과 fetchData2를 호출하여 그 결과를 배열로 반환하는 fetchAllData 함수를 작성하세요. 두 함수는 각각 1초 후에 값을 반환합니다.

 

function fetchData1() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('Data from fetchData1');
        }, 1000);
    });
}

function fetchData2() {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve('Data from fetchData2');
        }, 1000);
    });
}

async function fetchAllData() {
    // 여기에 코드를 작성하세요.
}

 

정답 

async function fetchAllData() {
    const results = await Promise.all([fetchData1(), fetchData2()]);
    return results;
}

 

2. 배열 및 객체조작

문제: 주어진 배열에서 중복된 값을 제거하고, 각 값의 출현 횟수를 객체 형태로 반환하는 countOccurrences 함수를 작성하세요.

function countOccurrences(arr) {
    // 여기에 코드를 작성하세요.
}

 

정답

function countOccurrences(arr) {
    return arr.reduce((acc, item) => {
        acc[item] = (acc[item] || 0) + 1;
        return acc;
    }, {});
}
728x90
728x90

이 예제에서는 버튼 요소에 data-action과 data-target 속성을 추가하여 버튼의 동작과 대상 폼을 지정했습니다. JavaScript에서는 이 data- 속성을 읽어 적절한 동작을 수행하도록 구현했습니다.

data- 속성은 이처럼 HTML과 JavaScript 간의 데이터 전달에 유용하게 사용될 수 있습니다.

<div id="myElement" data-color="blue" data-size="large">...</div>

const myElement = document.getElementById('myElement');
console.log(myElement.dataset.color); // "blue"
console.log(myElement.dataset.size); // "large"
<button id="myButton" data-action="submit" data-target="#myForm">Submit</button>
<form id="myForm">
  <!-- form fields -->
</form>
<script>
const myButton = document.getElementById('myButton');
myButton.addEventListener('click', () => {
  const action = myButton.dataset.action;
  const target = myButton.dataset.target;

  if (action === 'submit') {
    const form = document.querySelector(target);
    form.submit();
  }
});

</script>
728x90
728x90

첨부파일을 드래그로 순서 변경 가능하게 구현한 스크립트 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Drag and Drop</title>
    <style>
        .file-list-box {
            display: flex;
            flex-wrap: wrap;
            gap: 10px;
            justify-content: flex-start;
            align-items: center;
            border: 2px dashed #ccc;
            padding: 10px;
            min-height: 100px;
        }

        .file-list-box .img-box {
            width: 100px;
            height: 100px;
            border-radius: 8px;
            overflow: hidden;
        }

        .file-list-box .img-box img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }

        .over {
            border: 2px dashed #000;
        }
    </style>
</head>
<body>
    <div class="file-box" data-max-files="5" id="file-box-1">
        <div class="file-s-tit">사진올리기</div>
        <div class="file-list-box attachBookingList" data-id="1"></div>
        <button class="btn-file" type="button" onclick="openFileInput(1)">사진추가</button>
        <input type="file" name="addFile" id="fileInput-1" class="file-input" style="display: none;" accept="image/*" multiple>
    </div>

    <div class="file-box" data-max-files="5" id="file-box-2">
        <div class="file-s-tit">사진올리기</div>
        <div class="file-list-box attachBookingList" data-id="2"></div>
        <button class="btn-file" type="button" onclick="openFileInput(2)">사진추가</button>
        <input type="file" name="addFile" id="fileInput-2" class="file-input" style="display: none;" accept="image/*" multiple>
    </div>

    <script>
        function openFileInput(id) {
            document.getElementById(`fileInput-${id}`).click();
        }

        function handleFiles(files, targetBox) {
            const maxFiles = parseInt(targetBox.closest('.file-box').dataset.maxFiles);
            const currentFiles = targetBox.querySelectorAll('.img-box').length;
            const totalFiles = currentFiles + files.length;

            if (totalFiles > maxFiles) {
                alert(`최대 ${maxFiles}개의 파일만 업로드할 수 있습니다.`);
                return;
            }

            Array.from(files).forEach(file => {
                if (!file.type.startsWith('image/')) return;

                const reader = new FileReader();
                reader.onload = function(e) {
                    const newImage = document.createElement('div');
                    newImage.classList.add('img-box');
                    newImage.innerHTML = `<img src="${e.target.result}" alt="이미지">`;
                    targetBox.appendChild(newImage);
                };
                reader.readAsDataURL(file);
            });
        }

        document.addEventListener('DOMContentLoaded', () => {
            document.querySelectorAll('.file-input').forEach(input => {
                input.addEventListener('change', function(event) {
                    const targetBox = document.querySelector(`.file-list-box[data-id="${this.id.split('-')[1]}"]`);
                    handleFiles(event.target.files, targetBox);
                    this.value = '';
                });
            });

            document.querySelectorAll('.file-list-box').forEach(box => {
                box.addEventListener('dragover', function(event) {
                    event.preventDefault();
                    event.stopPropagation();
                    this.classList.add('over');
                });

                box.addEventListener('dragleave', function(event) {
                    event.preventDefault();
                    event.stopPropagation();
                    this.classList.remove('over');
                });

                box.addEventListener('drop', function(event) {
                    event.preventDefault();
                    event.stopPropagation();
                    this.classList.remove('over');
                    const files = event.dataTransfer.files;
                    handleFiles(files, this);
                });
            });
        });
    </script>
</body>
</html>

 

// 파일 업로드 처리 함수
function handleFileUpload(event, listBoxSelector) {
  const files = event.target.files;
  const fileListBox = document.querySelector(listBoxSelector);

  // 파일 목록 표시
  for (let i = 0; i < files.length; i++) {
    const fileItem = document.createElement('div');
    fileItem.classList.add('file-item');
    fileItem.textContent = files[i].name;
    fileItem.draggable = true;
    fileItem.addEventListener('dragstart', handleDragStart);
    fileItem.addEventListener('dragover', handleDragOver);
    fileItem.addEventListener('drop', handleDrop);
    fileListBox.appendChild(fileItem);
  }
}

// 드래그 시작 이벤트 핸들러
function handleDragStart(event) {
  event.dataTransfer.setData('text/plain', null);
  event.currentTarget.classList.add('dragging');
}

// 드래그 오버 이벤트 핸들러
function handleDragOver(event) {
  event.preventDefault();
  event.currentTarget.classList.add('drag-over');
}

// 드롭 이벤트 핸들러
function handleDrop(event) {
  event.preventDefault();
  event.currentTarget.classList.remove('drag-over');

  const draggedItem = document.querySelector('.dragging');
  const dropTarget = event.currentTarget;
  const fileListBox = event.currentTarget.parentNode;

  // 파일 목록 순서 변경
  fileListBox.insertBefore(draggedItem, dropTarget);
}

// 파일 추가 버튼 클릭 이벤트 핸들러
document.querySelectorAll('.btn-file').forEach(button => {
  button.addEventListener('click', () => {
    const fileInput = button.parentNode.querySelector('.file-input');
    fileInput.click();
  });
});

// 파일 선택 이벤트 핸들러
document.querySelectorAll('.file-input').forEach(input => {
  input.addEventListener('change', (event) => {
    const listBoxSelector = event.target.parentNode.parentNode.querySelector('.file-list-box').classList[1];
    handleFileUpload(event, `.${listBoxSelector}`);
  });
});
728x90
728x90

canvas 를 이용해 낙서장 만들기 스크립트 및 html 태그 예시

 

html5 에 있는 canvas 태그를 이용하면 낙서장, 서명란 등을 간단하게 구현 할 수 있다. 스크립트를 적용하면 마우스나 터치팬에서도 잘 작동 한다. 처음 작업 했을때는 width:100px, height:100px 처럼 사이즈가 정의된 경우만 적용이 되어서 반응형을 못맞췄었는데 스크립트로 화면의 가로 세로 사이즈를 체크해서 가로 세로 값을 계산해서 canvas.width 에 적용해 주면 화면이 유동적이어도 적용이 잘 된다. 단 임의로 화면 사이즈를 줄였을때도 적응이 되게 하려면 리사이징 시에도 가로세로 값을 체크 하는 함수를 한번 더 호출해주어야 한다. 아래 예시는 부분은 작업 되어 있지 않다. 

 

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Canvas Drawing and Erasing</title>
    <style>
        canvas {
            border: 1px solid black;
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <button id="toggleEraser">Toggle Eraser</button>
    <canvas id="drawCanvas"></canvas>
    <script src="script.js"></script>
</body>
</html>

 

const canvas = document.getElementById('drawCanvas');
const context = canvas.getContext('2d');
let isDrawing = false;
let isErasing = false;

function resizeCanvas() {
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
}

function getPosition(e) {
    if (e.touches) {
        return {
            x: e.touches[0].clientX - canvas.offsetLeft,
            y: e.touches[0].clientY - canvas.offsetTop
        };
    } else {
        return {
            x: e.clientX - canvas.offsetLeft,
            y: e.clientY - canvas.offsetTop
        };
    }
}

function startDrawing(e) {
    e.preventDefault();
    isDrawing = true;
    draw(e);
}

function stopDrawing() {
    isDrawing = false;
    context.beginPath();  // 경로 초기화
}

function draw(e) {
    if (!isDrawing) return;

    const pos = getPosition(e);

    context.lineWidth = 10;
    context.lineCap = 'round';

    if (isErasing) {
        context.globalCompositeOperation = 'destination-out';
        context.strokeStyle = 'rgba(0,0,0,1)';
    } else {
        context.globalCompositeOperation = 'source-over';
        context.strokeStyle = '#000';
    }

    context.lineTo(pos.x, pos.y);
    context.stroke();
    context.beginPath();  // 새로운 경로 시작
    context.moveTo(pos.x, pos.y);
}

function toggleEraser() {
    isErasing = !isErasing;
    const button = document.getElementById('toggleEraser');
    button.textContent = isErasing ? 'Switch to Draw' : 'Switch to Erase';
}

function clickDrawReset() {
    context.clearRect(0, 0, canvas.width, canvas.height);
}

canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchmove', function (e) {
    e.preventDefault();
    draw(e);
});
canvas.addEventListener('touchend', stopDrawing);

document.getElementById('toggleEraser').addEventListener('click', toggleEraser);
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
728x90
728x90

특정 div 일부만 이미지로 저장하고 싶다면 html2cnvas  스크립트로 가능하다. pdf 로 다운로드는 구현이 조금 까다롭지만 스크립트로는 아래와 같이 코드 몇줄만 적으면 다운로드 파일 이름도 정의할 수 있고 jpg 파일로 저장 할수 있다.

<div class="com_btn_wrap right"> 
  <button class="com_btn l point btn_download" type="button" onclick="downloadImage()"><i class="icon svg_icon before icon_download white"></i>다운로드</button>
</div>

<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script>
  function downloadImage() {
    // Get the target div
    var divToCapture = document.getElementById('mindScoreBody');

    // Use html2canvas to capture the div as an image
    html2canvas(divToCapture).then(function (canvas) {
      // Convert the canvas to a data URL
      var imageData = canvas.toDataURL('image/jpeg');

      // Create a link element and trigger a download
      var link = document.createElement('a');
      link.href = imageData;
      link.download = 'output.jpg';
      link.click();
    });
  }
</script>
728x90
728x90

영상이 종료 되는 시점을 체크 하는 스크립트 

 

if ($("#video").prop("ended") && !alertTriggered) 

 

video 태그에 아이디 값을 주고 ended 로 값이 매칭 될때 다른 영상을 플레이 할 수 있다. jquery 를 사용한 문법이라 jqeury 를 기본적으로 가지고 있어야 가능한 문법이다.

 

<div class="wrap">
	<div class="video-wrap">
		<video id="video" autoplay controls muted playsinline class="normal-video">
			<source id="normalloop1" src="영상주소" type='video/mp4'/>
		</video>
	</div>
	<div class="video-wrap">
		<video id="video2" controls muted playsinline class="normal-video">
			<source id="normalloop2" src="영상주소" type='video/mp4'/>
		</video>
	</div>
</div>

<style>
.wrap {position:absolute;top:0;left:0;width:100%;height:100%;}
.video-wrap {position:relative;height:50%;background:#000;overflow:hidden;}
.video-wrap video {position:absolute;top:0;left:50%;transform:translateX(-50%);height:100%;}
       
@media all and (max-width:1199px){
	.video-wrap video {width:100%;height:auto;top:50%;left:0;transform:translate(0,-50%);}	
}
</style>
<script src="/application/assets/common/js/jquery-1.12.4.min.js"></script>
<script>
$(window).on("load",function(){
	
    //윈도우 로드 시 비디오 플레이
    $("#video").get(0).play();
	
    //작동하는지 콘솔창에서 확인
    console.log("test");
})
    
var alertTriggered = false; // Flag variable to track whether the alert has been triggered

setInterval(function () {
    if ($("#video").prop("ended") && !alertTriggered) {

        //영상종료 후 어떤행동을 할건지 작성
        alert('영상종료');

        alertTriggered = true; // Set the flag to true to indicate that the alert has been triggered
    }
}, 200);
</script>
728x90
728x90

location.reload 함수는 새로고침에 많이 사용하지만 이렇게만 하면 ? 물음표 뒤에 파라메터값은 하나도 들어 오지 않는다. 그래서 가끔 당황하게 되는데 아래와 같이 params 를 달고 가는 방법을 메모해 본다. 

//location.href=location.reload();

var url = new URL(window.location.href);
var params = new URLSearchParams(url.search);
location.href = url.origin + url.pathname + '?' + params.toString() + url.hash;

 

 

728x90
728x90

selectableDays 배열 값으로 원하는 요일만 선택이 가능하게 설정 하는 스크립트 예제 

 

요일은 일요일이 0 부터 시작 되게 해서 작성 하면 됩니다. 

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
</head>
<body>

<input type="text" id="datepicker">

<script>
$(document).ready(function() {
  var selectableDays = [1, 2, 3]; // 월요일, 화요일, 수요일
  
  $("#datepicker").datepicker({
    beforeShowDay: function(date) {
      var day = date.getDay();
      
      if ($.inArray(day, selectableDays) >= 0) {
        return [true];
      }
      
      return [false];
    }
  });
});
</script>

</body>
</html>

beforeShowDay 함수에서 date 에 true, false 로 속성을 주어서 수정할 수 있는 부분으로 유용하게 사용 할수 있습니다. 

jquery 사용이 많이 줄어들고 있는 추세 지만 달력 스크립트는 간단하게 붙이고 수정이 용이해서 아직 까지는 장점도 있는거 같습니다. 

728x90
728x90

MIME 타입 (MIME type, Multipurpose Internet Mail Extensions type) 의 약자로

인터넷에서 전송되는 파일의 형식을 식별하기 위한 식별자이다.

 

파일 업로드시 파일 확장자로 체크 하기도 하고 

MIME 타입으로 파일 확장자를 체크 해서 

입력 받아야할 파일 타입을 한번 더 걸러 준다. 

 

아래는 파일 확장자에 대한 MIME 타입과 

javascript 에서 체크 하는 로직을 예제로 보여 주고 있다.

 

pdf 파일

'application/pdf'

 

excel 파일

.xls 파일

'application/vnd.ms-excel'

.xlsx 파일

'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'

 

hwp 한글 파일

'application/x-hwp'

doc 파일

'application/msword'

 

docx 파일

'application/vnd.openxmlformats-officedocument.wordprocessingml.document'

word파일

'application/msword'

이미지파일

image/jpeg : JPEG 이미지
image/png : PNG 이미지
image/gif : GIF 이미지
image/webp : WebP 이미지
image/bmp : BMP 이미지
image/svg+xml : SVG 이미지
image/tiff : TIFF 이미지

 

 

const fileTypes = ['application/pdf', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];

 

 

스크립트 예제>

script ex>

if (fileTypes.includes(file.type)) {
  // 업로드된 파일이 허용된 MIME 타입에 해당하는 경우 
} else {
  // 업로드된 파일이 허용되지 않은 MIME 타입에 해당하는 경우 
}

 

728x90

+ Recent posts