본문으로 바로가기

Vanilla JS로 MVC 패턴 구현하기 1

category JavaScript 2021. 3. 4. 15:02

inflean에 있는 김정환님의 강의 실습 UI 개발로 배워보는 순수 javascript 와 VueJS 개발 에서 파트1 격인 MVC패턴를 바닐라 자바스크립트로 구현하는 강의를 보고 공부한 내용을 기록했다

이 강의에서 구현하는 것은 쇼핑몰 검색 페이지이다

폴더 구조

MVC 패턴을 적용시키니 당연히 Model, View, Controller 3가지로 나누어서 개발을 진행한다

모듈 패턴도 적용시키기 때문에 기능별로 적절하게 js를 쪼개어서 개발을 진행하고 index.html에는 app.js 하나만 등록해서 구현할 예정

View

index.html에서 html마크업은 DOM 뼈대만 작성하고 자세한 구현은 View 즉, js로 구현하게된다

views 폴더안에는 View.js라는 파일이 하나 존재한다

// in views/View.js
const tag = '[View]'

export default {
  init(el) {
    if (!el) throw el
    this.el = el
    return this
  },

  on(event, handler) {
    this.el.addEventListener(event, handler)
    return this
  },

  emit(event, data) {
    const evt = new CustomEvent(event, { detail: data })
    this.el.dispatchEvent(evt)
    return this
  },

  hide() {
    this.el.style.display = 'none'
    return this
  },

  show() {
    this.el.style.display = ''
    return this
  }
}

처음에 강의를 샀을 때 이 코드를 보고 멘붕이 와서 강의듣는 것을 3일 정도 미루었다

당최 무슨 소린지.. 어떻게 쓰는 건지.. 현업에서는 이런식으로 개발을 하는지 등등 나에게는 너무 어렵게 다가왔기 때문

간단하게 설명하면 이 View.js는 내가 사용자에게 보여주고자하는 부분을 그릴 때 자주 사용되는 기능들을 묶어놓은 파일이라고 생각하면된다

이 View.js는 나중에 뷰를 그릴 때 import해서 다른 뷰에서 쉽게 상속받을 수 있다

Model

모델은 말 그대로 모델.

애플리케이션에서 필요한 데이터들을 가지고 있다


export default {
  data: [
    { keyword: '검색기록2', date: '12.03' },
    { keyword: '검색기록1', date: '12.02'},
    { keyword: '검색기록0', date: '12.01' },
  ],

  list() {
    return Promise.resolve(this.data)
  },

  add(keyword = '') {
    keyword = keyword.trim()
    if (!keyword) return 
    if (this.data.some(item => item.keyword === keyword)) {
      this.remove(keyword)
    }

    const date = this.getCurrentDate();
    this.data = [{keyword, date}, ...this.data];
  },

  remove(keyword) {
    this.data = this.data.filter(item => item.keyword !== keyword)
  },
  getCurrentDate(){
    const month = `${new Date().getMonth()+1}`;
    const month1 = month.length === 1 ? `0${month}` : month;
    const date = `${new Date().getDate()}`;
    const date1 = date.length === 1 ? `0${date}` : date;
    return `${month1}.${date1}`;
  }
}

api를 사용해서 실제 서버에서 비동기로 받아오는 것 처럼 모델에서 list를 호출하면 프로미스 값을 반환해준다

Controller

마지막으로 컨트롤러

컨트롤러를 살펴보기 전에 먼제 index.html과 app.js를 보자

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>MVC with Vanilla.JS</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div>
    <header>
      <h2 class="container">검색</h2>
    </header>

    <div class="container">
      <form>
        <input type="text" placeholder="검색어를 입력하세요" autofocus>
        <button type="reset" class="btn-reset"></button>
      </form>
    </div>
  </div>

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

위에서 말한대로 index.html은 하나의 app.js만 불러오고 있고

import MainController from './controllers/MainController.js'

document.addEventListener('DOMContentLoaded', () => {
  MainController.init()
})

app.js에서는 메인 컨트롤러의 init() 함수를 호출하고 있다

다시 컨트롤러를 가보면

const tag = '[MainController]'

export default {
  init() {
  },
}

이렇게 기본적인 구현이 되어있다

이를 통해 유추할 수 있는 것은 뷰를 구현해서 컨트롤러의 init에 등록해주어야한다는 것

'JavaScript' 카테고리의 다른 글

IntersectionObserve API, 레이지 로딩  (0) 2021.05.13
소수, 실수 계산 오류, 부동소숫점  (0) 2021.04.16
async/await  (0) 2021.02.07
Tagged templates  (0) 2021.01.23
다차원 배열 생성시 주의점  (0) 2021.01.21