๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
JavaScript/Vanila

[Vanila js] ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

by ๐Ÿณ Laboon 2024. 7. 31.

Branch - ready/search-form-1

์•ž์„  ํฌ์ŠคํŒ…์˜ ์ž‘์—…์ด ์ œ๋Œ€๋กœ ๋˜์—ˆ๋‹ค๋ฉด main ๋ธŒ๋žœ์น˜์—์„œ

1. git checkout -b ready/search-form-1

2. ์ฝ”๋“œ ์ž‘์„ฑ

3. git add .

4. git commit -m "feat: ๋‚ด์šฉ"

5. git push origin ready/search-form-1

PR

์ดํ›„ PR ๋‚ ๋ฆฌ๊ณ  Rebase Merge ํ•˜๊ธฐ.

git bash์—์„œ ์ฝ”๋“œ๋กœ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ํ˜‘์—… ์ค‘ ์ฝ”๋“œ ๋ฆฌ๋ทฐ๋ฅผ ํ•˜๋Š” ๊ณผ์ •์ด ์žˆ์Œ.

๊ทธ๋ž˜์„œ ์ง์ ‘ github ์‚ฌ์ดํŠธ์—์„œ Mergeํ•˜๋Š” ๊ฒƒ์— ์ต์ˆ™ํ•ด์ง€๊ธฐ

 

์•ž์œผ๋กœ ๋ชจ๋“  ์ž‘์—…์€ ์œ„ ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•ด์„œ branch๋ฅผ ์—…๋ฐ์ดํŠธ ํ•  ์˜ˆ์ •

 

 

// index.html
<script type="module" src="./js/main.js"></script>
    
// main.js
document.addEventListener("DOMContentLoaded", main);

function main() {}
  1. ์ •์ ํŽ˜์ด์ง€์— module๋กœ main.js๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.
    ์ฆ‰, main์˜ ์ฝ”๋“œ๋Š” ๋งจ ์ฒ˜์Œ index.html์„ DOM์—์„œ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ, main.js์— ์ž‘์„ฑ๋œ ์ฝ”๋“œ๋“ค์„ ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.
  2. main.js ์—์„œ dom์ด load๋  ๋•Œ, main method๋ฅผ eventListener๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค.
  3. closer ๊ฐœ๋…์œผ๋กœ main method๋Š” ํ•˜๋‚˜์˜ instance๊ฐ€ ๋˜๊ณ  main method์—์„œ ์ž‘์„ฑ๋œ ์ฝ”๋“œ์— ๊ณ„์†ํ•ด์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ๋ญ ์ž‘์„ฑํ•  ์ฝ”๋“œ๊ฐ€ ์žˆ์œผ๋ฉด main method์—์„œ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋œ๋‹ค.

๊ฐ•์‚ฌ๋‹˜์€ ์ด๊ฒƒ์„ MVC ํŒจํ„ด์„ ํ™œ์šฉํ•ด์„œ ์ฒ˜๋ฆฌํ–ˆ๋‹ค.

 

ํด๋กœ์ €์˜ ์ž์„ธํ•œ ์„ค๋ช…: https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures

 

ํด๋กœ์ € - JavaScript | MDN

ํด๋กœ์ €๋Š” ์ฃผ๋ณ€ ์ƒํƒœ(์–ดํœ˜์  ํ™˜๊ฒฝ)์— ๋Œ€ํ•œ ์ฐธ์กฐ์™€ ํ•จ๊ป˜ ๋ฌถ์ธ(ํฌํ•จ๋œ) ํ•จ์ˆ˜์˜ ์กฐํ•ฉ์ž…๋‹ˆ๋‹ค. ์ฆ‰, ํด๋กœ์ €๋Š” ๋‚ด๋ถ€ ํ•จ์ˆ˜์—์„œ ์™ธ๋ถ€ ํ•จ์ˆ˜์˜ ๋ฒ”์œ„์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. JavaScript์—์„œ ํด๋กœ์ €๋Š” ํ•จ์ˆ˜ ์ƒ

developer.mozilla.org

 

export default class SearchFormView extends View {
    constructor() {
        super(qs("#search-form-view"));
        
        this.inputElement = qs("[type=text]", this.element);
        this.resetElement = qs("[type=reset]", this.element);

        this.showResetButton(false);
        this.bindEvents()
    }
}

View๋ฅผ ํ™•์žฅ๋ฐ›๋Š” ๊ฒ€์ƒ‰ View๋ฅผ ์‚ดํŽด๋ณด์ž 

 

1. ์ •์ ํŽ˜์ด์ง€์— ์ž‘์„ฑ๋œ ๊ฒ€์ƒ‰ ํผ ํƒœ๊ทธ๋ฅผ ์„ ํƒํ•œ๋‹ค.

2. ํ•ด๋‹น ํƒœ๊ทธ์— ์†ํ•ด์žˆ๋Š” ๋…€์„ ์ค‘ type ์†์„ฑ์ด text์™€ reset์ธ ๊ฒƒ์„ ๊ฐ€์ ธ์˜จ๋‹ค.

3. ๊ทธ๋ฆฌ๊ณ  ํ•ด๋‹น ํƒœ๊ทธ๋“ค์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์ž‘์„ฑํ•œ๋‹ค. -> ๊ธฐ๋Šฅ๋ณ„๋กœ ์ž˜ ๋ถ„๋ฆฌ๋œ ์ฝ”๋“œ

 

    bindEvents() {
        on(this.inputElement, "keyup", () => this.handleKeyup());
        on(this.element, "submit", event => this.handleSubmit(event));
        on(this.resetElement, "click", () => this.handleReset());
    }

    handleSubmit(event) {
        event.preventDefault();

        const {value} = this.inputElement;
        this.emit("@submit", {value});
    }

์ด๋Ÿฐ์‹์œผ๋กœ ๊ฐ ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ event๋ฅผ helper.js์—์„œ utility๋กœ ๊ตฌํ˜„ํ•œ on ๋ฉ”์†Œ๋“œ๋กœ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ํ•ธ๋“ค๋Ÿฌ ์ž‘์—…์„ ํ•œ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ HTML์—๋Š” ํŠน์ • ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ์ž‘์—…์ด ๋˜์–ด์žˆ๋‹ค. ์ถ”๊ฐ€์ ์ธ ์ž‘์—…์ด๋‚˜ ๊ธฐ์กด ์ž‘์—…์„ ์—†์•จ ๊ฒฝ์šฐ, ํ•ธ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•œ๋‹ค.

 

emit ๋˜ํ•œ, helper.js์—์„œ ๊ตฌํ˜„๋œ utility์ด๋‹ค.

์ƒˆ๋กœ์šด ์ด๋ฒคํŠธ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ „๋‹ฌํ•œ๋‹ค.

 

export default class Controller {
  constructor(store, {searchFormView}) {
    this.store = store;
    
    this.searchFormView = searchFormView;

    this.subscribeViewEvents();
  }

  subscribeViewEvents() {
    this.searchFormView
    .on('@submit', (event) => this.search(event.detail.value))
    .on('@reset', () => this.reset());
  }
}

View์—์„œ ์ „๋‹ฌ๋œ ์ž‘์—…์€ Controller์—์„œ Catchํ•˜์—ฌ ์ƒ์„ธ ์ž‘์—…์„ ํ•œ๋‹ค.

๊ถ๊ธˆํ•œ ์ 

1. Controller์—์„œ Business Logic์„ ์ž‘์„ฑํ• ๊นŒ?

2. Model์—์„œ Business Logic์„ ์ž‘์„ฑํ•˜๊ณ  Controller์—์„œ store ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด ์„œ๋น„์Šค ์ž‘์—…์„ ํ• ๊นŒ?

3. ๊ทธ ๋‹ค์Œ ์ž‘์—…์ด ๋๋‚œ ๋’ค ๋ฐ˜ํ™˜ํ•  ๋•Œ๋Š” View์—๊ฒŒ ๋‹ค์‹œ Event๋ฅผ ์ฃผ๋Š”๊ฑธ๊นŒ? 

4. Controller์—์„œ ๋ณ€ํ™”๋œ ๋ Œ๋”๋ง ์ž‘์—…์„ ํ• ๊นŒ?


ํ€˜์ŠคํŠธ

๊ฒ€์ƒ‰์–ด Reset ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ๊ฒ€์ƒ‰ ๋‚ด์šฉ ์ œ๊ฑฐ ๋ฐ ๊ฒ€์ƒ‰์–ด ์ง€์šฐ๋Š” ์ž‘์—…

// View

    bindEvents() {
        on(this.resetElement, "click", () => this.handleReset());
    }
    
    
    handleReset() {
        this.emit("@reset");
        this.showResetButton(false);
    }
    
 // Controller
 
  subscribeViewEvents() {
    this.searchFormView
    .on('@reset', () => this.reset());
  }
  
  reset() {
    console.log("reset");
  }

 

1. input tag์˜ ์†์„ฑ์ธ reset type์€ HTML์—์„œ ์ œ๊ณตํ•˜๋Š” form data๋ฅผ ๋ชจ๋‘ ์ง€์šด๋‹ค.

-> ๊ทธ๋ž˜์„œ ๋”ฐ๋กœ ์ง€์šฐ๋Š” ์ž‘์—…์„ ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

2. ์ดํ›„ ๊ฒ€์ƒ‰ ๋‚ด์šฉ์„ ์ง€์šฐ๊ธฐ ์œ„ํ•ด์„œ Controller์—์„œ ์ž‘์—…์ด ๋ฐœ์ƒํ• ํ…Œ๋‹ˆ๊นŒ, ์ด๋ฒคํŠธ๋ฅผ ํ•ธ๋“ค๋Ÿฌ๋กœ ๋ฐ”์ธ๋”ฉํ•ด๋‘์—ˆ๋‹ค.

3. ๋ฐ”์ธ๋”ฉ๋œ ํ•ธ๋“ค๋Ÿฌ ์ด๋ฒคํŠธ๋Š” Controller์—์„œ ์ž‘์—…์ด ์ง„ํ–‰๋œ๋‹ค.

4. ์ž‘์—…์ด ๋๋‚˜๋ฉด View ๋‹จ์—์„œ ๋ณด์—ฌ์ง„ Btn์„ ์ˆจ๊ธฐ๊ธฐ์œ„ํ•ด showResetButton ๋ฉ”์†Œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

 

    handleKeyup() {
        const {value} = this.inputElement;

        if (value.length <= 0) this.handleReset();
    }

๊ฐ•์‚ฌ๋Š” ๊ฒ€์ƒ‰๋‚ด์šฉ์„ ์ž‘์„ฑํ•˜๋‹ค ์ง€์šธ ๋•Œ๋„ Reset์„ ํ•˜๋„๋ก ํ–ˆ๋‹ค.