DEVELOP

1. 01, 모듈이란? 

# 모듈 

: 간단하게, 자바스크립트 파일 하나 

 

# 모듈화

: 복잡하고 많은 양의 코드를 기능에 따라 각각의 파일(모듈)로 나누어 관리

- 더 효율적인 코드 관리 가능

- 비슷한 기능이 필요할 때 다른 프로그램에서 재사용 가능


2. 02. 모듈 파일의 조건 

# 모듈 스코프

: 모듈 파일이 가지는 독립적인 스코프 

- 모듈 파일 내에서 선언한 함수나 변수는 모듈 파일 내에서만 사용이 가능 

- HTML 파일에서 JS 파일을 불러올 때 모듈 스코프를 갖게 하려면 script 태그에 type 속성을 module로 지정해줘야 함

<html />
<body> <script type="module" src="index.js"></script> <script type="module" src="printer.js"></script> </body>

3. 03. Live Server 설치하기 

- 모듈 문법을 활용할 때에는 브라우저에서 직접 파일을 불러오는 방식이 아니라 서버를  통해 html 파일을 실행해야 함 

 => VS code 에서 extentions -> live server 설치 -> go live 버튼 


4. 05. 모듈 문법 

# export 키워드 

- 모듈 스코프를 가진 파일에서 외부로 내보내고자 하는 변수나 함수를 export 키워드를 통해 내보냄

# import 키우드

- 모듈 파일에서 내보낸 변수나 함수들은 다른 파일에서 import 키워드를 통해 가져옴 

<javascript />
export const title = 'CodeItPrinter'; export function print(value){ console.log(value); }
<javascript />
import {title, print} from './printer.js'; print(title);

- 모듈화 된 모듈은 모듈 문법을 통해 서로 연결될 수 밖에 없기 때문에 html 파일에서는 js의 진입점 역할을 하는 파일 하나만 불러옴 

<html />
<script type="module" src="index.js"></script>

06. 메뉴 추가 기능 붙이기 

- index.js

  - && 연산자 :  왼쪽이 true면 오른쪽 항 실행 (if문을 대신함)

<javascript />
import { addMenu } from "./add.js"; const data = []; const addBtn = document.querySelector('.add-btn'); const addInput = document.querySelector('.add-input'); addBtn.addEventListener('click', () => addMenu(data)); addInput.addEventListener('keypress', (e) => e.code === 'Enter' && addMenu(data));

- add.js

<javascript />
const addInput = document.querySelector('.add-input'); const list = document.querySelector('.list'); function add(data) { const inputValue = addInput.value; const index = data.length; console.log(inputValue,index); const li = document.createElement('li'); li.classList.add('item'); li.innerHTML = `<b>${index+1}</b>${inputValue}<button class="del-btn" data-index="${index}">x</div>`; list.append(li); data.push(inputValue); addInput.value = ''; addInput.focus(); } function emptyAlert() { alert('고민되는 메뉴를 입력해 주세요.'); addInput.focus(); } function maxAlert() { alert('메뉴는 최대 5개까지만 고민할 수 있습니다.'); addInput.value = ''; } export function addMenu(data) { const inputValue = addInput.value; if (inputValue === '') { emptyAlert(); } else if (data.length > 4) { maxAlert(); } else { add(data); } }

- index.html

<html />
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <title>오늘 뭐 먹지?</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="circle1"></div> <div class="circle2"></div> <div class="main"> <div class="container"> <h2 class="title">오늘 뭐 먹지?</h2> <div class="add-column"> <input class="add-input" type="text"> <button class="add-btn">Add</button> </div> </div> <ul class="list"></ul> <button class="roll-btn">Roll</button> </div> <script type="module" src="index.js"></script> </body> </html>

- style.css

<css />
* { margin: 0; padding: 0; box-sizing: border-box; font-family: sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-image: linear-gradient(to right top, #FFC9C9, #8CD3F9); } .circle1, .circle2 { width: 200px; height: 200px; position: absolute; border-radius: 50%; background-image: linear-gradient(to right bottom, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.1)); } .circle1 { bottom: calc(50% + 160px); left: calc(50% + 110px); } .circle2 { top: calc(50% + 120px); right: calc(50% + 130px); } .main { display: flex; flex-direction: column; justify-content: space-between; align-items: center; width: 360px; height: 530px; border-radius: 15px; background-image: linear-gradient(to right bottom, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.3)); z-index: 1; } .container { width: 100%; padding: 25px; background-image: linear-gradient(to right bottom, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.3)); border-radius: 15px; color: #658EC6; } .title { font-size: 30px; color: #426696; text-align: center; opacity: 0.8; } .add-column { display: flex; justify-content: center; margin-top: 15px; } .add-input { width: 200px; padding: 10px; background-color: linear-gradient(to right bottom, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.3)); border: none; border-radius: 5px; } .add-btn { padding: 10px; color: #FFFFFF; background-color: #8CD3F9; border: none; border-radius: 5px; font-weight: 600; } .list { display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%; height: 333px; } .item { position: relative; display: flex; align-items: center; width: 80%; height: 48px; margin: 7px; padding: 5px; color: #658EC6; background-image: linear-gradient(to right bottom, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.3)); border-radius: 45px; list-style: none; transition: all 1s ease-in-out; } .item b { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; margin-right: 15px; color: #FFFFFF; text-align: center; background-color: #FFC9C9; border-radius: 40px; } .del-btn { position: absolute; top: -5px; right: -10px; width: 30px; height: 30px; border: none; border-radius: 50%; color: #FF00D9; font-weight: 900; background-color: transparent; background-image: linear-gradient(to right bottom, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.3)); transition: all 0.3s ease-in-out; cursor: pointer; opacity: 0; } .item:hover .del-btn { opacity: 1; } .roll-btn { width: 100px; height: 45px; padding: 10px; margin-bottom: 15px; font-size: 18px; color: #FFFFFF; background-color: #8CD3F9; border: none; border-radius: 5px; font-weight: 900; cursor: pointer; } @keyframes roll { 0% { transform: rotateX(0deg); } 50% { transform: rotateX(180deg); } 100% { transform: rotateX(0deg); } } .rolling .item { height: 0; margin: 0; padding: 0 5px; animation: roll .5s infinite linear; } .item.selected { animation: roll .4s 2 linear; }

5. 07. 이름 바꾸기 

# as 키워드 

- import 키워드로 모듈을 불러올 때 as 키워드를 활용하면 import 하는 대상들의 이름 변경 가능 

- 이름을 바꿔서 import하면 여러 파일에서 불러오는 대상들의 이름이 중복되는 문제 해결 가능 

<javascript />
import {title as printerTitle, print} from './printer.js'; const title = 'Codeit'; print(title);

6. 08. 이름 바꿔 붙이기 

- index.js

<javascript />
import { addMenu } from './add.js'; import { deleteMenuByIndex as deleteMenu } from './delete.js'; const data = []; const addBtn = document.querySelector('.add-btn'); const addInput = document.querySelector('.add-input'); const list = document.querySelector('.list'); addBtn.addEventListener('click', () => addMenu(data)); addInput.addEventListener('keypress', (e) => e.code === 'Enter' && addMenu(data)); list.addEventListener('click', ({ target }) => target.tagName === 'BUTTON' && deleteMenu(data, target.dataset.index));

- delete.js

  - splice(start[, deleteCount[, item1[, item2[, ...]]]]) : 배열의 기존 요소를 삭제 또는 교체하거나 새 요소를 추가하여 원본 배열의 내용을 변경

  - data.splice(index,1) : data 배열 index에 해당하는 위치부터 요소 1개 삭제

<javascript />
const list = document.querySelector('.list'); function reloadMenu(data) { list.innerHTML = ''; data.forEach((title, index) => { const li = document.createElement('li'); li.classList.add('item'); li.innerHTML = `<b>${index + 1}</b>${title}<button class="del-btn" data-index="${index}">x</div>`; list.append(li); }); } export function deleteMenuByIndex(data, index) { data.splice(index, 1); reloadMenu(data); };

- style.css / add.js 파일은 06. 메뉴 추가 기능 붙이기 와 동일 


7. 09. 한꺼번에 다루기 

# 한꺼번에 import

- import 할 때 와일드카드 문자(*) 와 as를 활용하면 모듈 파일에서 export하는 모든 대상을 하나의 객체로 불러올 수 있음

<javascript />
import * as printerJS from './printer.js';

# 한꺼번에 export 

-  중괄호로 선언된 변수나 함수를 하나의 객체로 모아 한꺼번에 export 가능  

<javascript />
export {title as printerTitle, print};

8. 10. 태그 정리하기 

- index.html

<javascript />
import { addMenu } from './add.js'; import { deleteMenuByIndex as deleteMenu } from './delete.js'; import {addBtn,addInput,list} from './tag.js'; const data = []; addBtn.addEventListener('click', () => addMenu(data)); addInput.addEventListener('keypress', (e) => e.code === 'Enter' && addMenu(data)); list.addEventListener('click', ({ target }) => target.tagName === 'BUTTON' && deleteMenu(data, target.dataset.index));

- tag.js

<javascript />
const addBtn = document.querySelector('.add-btn'); const addInput = document.querySelector('.add-input'); const list = document.querySelector('.list'); export {addBtn,addInput,list};

- add.js

<javascript />
import{addInput,list} from './tag.js'; function add(data) { const inputValue = addInput.value; const index = data.length; console.log(inputValue,index); const li = document.createElement('li'); li.classList.add('item'); li.innerHTML = `<b>${index+1}</b>${inputValue}<button class="del-btn" data-index="${index}">x</div>`; list.append(li); data.push(inputValue); addInput.value = ''; addInput.focus(); } function emptyAlert() { alert('고민되는 메뉴를 입력해 주세요.'); addInput.focus(); } function maxAlert() { alert('메뉴는 최대 5개까지만 고민할 수 있습니다.'); addInput.value = ''; } // 아래 코드를 수정해 주세요. export function addMenu(data) { const inputValue = addInput.value; if (inputValue === '') { emptyAlert(); } else if (data.length > 4) { maxAlert(); } else { add(data); } }

- delete.js

<javascript />
import { list } from "./tag.js"; function reloadMenu(data) { list.innerHTML = ''; data.forEach((title, index) => { const li = document.createElement('li'); li.classList.add('item'); li.innerHTML = `<b>${index + 1}</b>${title}<button class="del-btn" data-index="${index}">x</div>`; list.append(li); }); } export function deleteMenuByIndex(data, index) { data.splice(index, 1); reloadMenu(data); };

9. 11. default export

# default export 

- 모듈 파일에서 export 대상이 하나일 경우 

<javascript />
const title = 'CodeitPrinter'; function print(value) { console.log(value); } export default print;

- import 시 default as 로 불러올 수 있음 

<javascript />
import { default as printerJS } from './printer.js'; console.log(printerJS.title); // CodeitPrinter console.log(printerJS.print); // ƒ print(value) { console.log(value); }

- 아래와 같이 축약형으로 불러오는 것도 가능 

<javascript />
import printerJS from './printer.js'; console.log(printerJS.title); // CodeitPrinter console.log(printerJS.print); // ƒ print(value) { console.log(value); }

10. 12. 간결하게 기능 붙이기 

- index.js 

  - || 연산자 : 왼쪽 항이 false이면 오른쪽 항을 실행 (if문을 대신함)

<javascript />
import { addBtn, addInput, list, rollBtn } from './tags.js'; import addMenu from './add.js'; import rollMenu from './roll.js'; import deleteMenu from './delete.js'; const data = []; addBtn.addEventListener('click', () => addMenu(data)); addInput.addEventListener('keypress', (e) => e.code === 'Enter' && addMenu(data)); list.addEventListener('click', ({ target }) => target.tagName === 'BUTTON' && deleteMenu(data, target.dataset.index)); rollBtn.addEventListener('click', () => list.classList.contains('rolling') || rollMenu(data));

-  delete.js 의 export 

<javascript />
export default deleteMenuByIndex;

- add.js의 export

<javascript />
export default addMenu;

- roll.js

<javascript />
import { addInput, list, rollBtn } from './tags.js'; function selectMenu(data) { list.classList.remove('rolling'); list.innerHTML = ''; const selectedIndex = (Math.floor(Math.random() * data.length)); const li = document.createElement('li'); li.classList.add('item', 'selected'); li.innerHTML = `<b>${selectedIndex + 1}</b>${data[selectedIndex]}`; list.append(li); rollBtn.textContent = 'Clear'; } function minAlert() { alert('최소 1개 이상의 메뉴를 입력해 주세요.'); addInput.focus(); } function clearMenu(data) { data.splice(0); list.innerHTML = ''; rollBtn.textContent = 'Roll'; } function rollMenu(data) { if (data.length === 0) { minAlert(); } else if (rollBtn.textContent === 'Clear') { clearMenu(data); } else { list.classList.add('rolling'); setTimeout(() => selectMenu(data), 1200); } } export default rollMenu;

11. 13.  복습과 활용 

- 여러 개의 기능으로 잘게 나누어진 모듈을 import한 다음 다시 export하는 모듈 파일 생성 가능 

- 비슷한 특징을 가진 여러 모듈 파일들을 다시 하나의 모듈 파일로 만들 수 있어 파일관리 유용 

<javascript />
// (modules.js) import module1 from './sub-module1.js'; import module2 from './sub-module2.js'; import module3 from './sub-module3.js'; export { module1, module2, module3 };
<javascript />
// index.js import { module1, module2, module3 } from 'modules.js';

14. 가져와서 다시 내보내기

- functions.js

<javascript />
import addMenu from "./functions/add.js"; import deleteMenuByIndex from "./functions/delete.js"; import rollMenu from "./functions/roll.js"; export {addMenu,deleteMenuByIndex,rollMenu};

- index.js

<javascript />
import { addBtn, addInput, list, rollBtn } from './tags.js'; import { addMenu,deleteMenuByIndex as deleteMenu,rollMenu } from './functions.js'; const data = []; addBtn.addEventListener('click', () => addMenu(data)); addInput.addEventListener('keypress', (e) => e.code === 'Enter' && addMenu(data)); list.addEventListener('click', ({ target }) => target.tagName === 'BUTTON' && deleteMenu(data, target.dataset.index)); rollBtn.addEventListener('click', () => list.classList.contains('rolling') || rollMenu(data));

 

profile

DEVELOP

@JUNGY00N