[코드스쿼드] MV* 1 역할나누기


코드스쿼드 프론트엔드 레벨3 웹자판기(DOM&Event) 과정 중 6번째 MV* 1 역할나누기에 대해서 정리한 글입니다.

MV*

  • Model View
    • 명확함
    • 데이터를 가지고 있음
    • 화면을 구성함
    • 중간자
      • ModelView 관계는 느슨하게 만들 필요가 있음
      • MVC 에서의 C입력장치 역할을 담당함
      • ModelView 관계를 더 느슨하게 만들어주는 것을
        • presenter 라고 일컫음 MVP



우리가 집중할 중재자

  • ModelView 역할을 명확하게 분리
  • ModelView 가 많아지면
    • 서로 참조하면서 그 관계가 복잡해짐
    • 따라서 M,V 관계를 느슨하게 만들 필요가 있음
    • 또한 Views 간에도 관계가 느슨하면 좋겠음
  • controller - M,V 관계를 구분
  • 가장 중요한 것 각 역할이 무엇인지에 집중하는 것



역할 정의

  • Model

    • 데이터 갱신 추가 변경 제거 획득
    • 데이터를 획득하는 로직 Ajax LocalStorage 이 포함될 수 있음
      • Controller에서 만들어서 줄 수도 있음
  • Controller

    전체적인 목표는 Model과 View 간 변경사항을 연결하는 것

    • event handler Listener 구현체 만들기
    • View가 렌더링을 잘 할 수 있도록 데이터 가공 viewModel
    • 데이터 변경이 필요한 경우는 Model 에 전달
  • View

    DOM조작 (View 변경) 에만 집중

    • 데이터를 받아 그대로 DOM에 추가
    • Add Event Listener



실습

  • 할일을 입력하면 ‘해야 할 일들’ 에 노출된다
  • Event Delegation를 사용한다 (Document에만 event를 등록한다)
  • Template Literal 을 활용한 View용 HTML 데이터 생성
  • Model
    • 획득
    • 일단 태그들을 획득 해오자
    • toDoInputTextBox



Event Delegation

하위요소에 각각 이벤트를 붙이지 않고, 상위요소에서 하위요소의 이벤트들을 제어하는 방식

  • Event Delegation

     - Child element 각각 이벤트 핸들러를 달지 않고
       - Parent Element에 달고 이벤트가 발생한 노드를 필터링 해서 처리함
    
       document.getElementById( 'myTable' ).addEventListener( 'click', function( e ) {
             if( e.target && e.target.nodeName == 'TD' ) {
                //you code goes here...
             }
          }, false );
    
       <HTML>
       <table id="myTable">
          <tbody>
             <tr>
                <td id="myTd">1, 1</td>
                <td>1, 2</td>
             </tr> 
             <tr>
                <td>2, 1</td>
                <td>2, 2</td>
             </tr>
          </tbody>
       </table>
    
  • Event Delegation

    사용자의 액션에 의해 이벤트 발생 시 이벤트는 Document 레벨까지 버블링되어 올라간다.

  • 왜 사용하는가?

    • 새로운 노드들이 추가되는 상황에서 (아이템 객체 등) 해당 노드들에 이벤트 리스너를 일일이 달아야 하는 번거로움이 생김
    • 리스트 아이템들이 많아지면 많아질수록 해당 작업 자체가 고문이됨
    • 그래서 번거로운 작업들을 처리할 수 있는게 이벤트 위임(Event Delegation)



Event Bubbling

특정 화면 요소에서 이벤트가 발생했을 때, 해당 이벤트가 더 상위의 화면 요소들로 전달되어 가는 특성

  • 어떤 태그에서 이벤트가 발생했을 때, 부모 태그로 올라가면서 이벤트를 발생시킴
  • 브라우저가 이벤트를 감지하는 방식 때문
    • 브라우저는 특정 화면 요소에서 이벤트가 발생했을 때, 그 이벤트를 최상위에 있는 화면요소까지 이벤트를 전파시킴
  • 하위에서 상위 요소로의 이벤트 전파 방식을 이벤트 버블링(Event Bubbling) 이라고 함
  • Bubbling



Event Capture

이벤트 버블링과 반대로 진행되는 이벤트 전파방식

  • 실제 코드에서는 거의 사용되지 않지만 때로는 유용할 수 있음

  • DOM 이벤트는 3가지 단계를 거침

    1. 캡쳐(Capture) 단계 - 이벤트가 요소로 이동함
    2. 목표(Target) 단계 - 이벤트가 대상 요소에 도달함
    3. Bubbling phase - 이벤트가 요소에서 튀어 오름 (?) the event bubbles up from the element
  • 그러나 캡쳐단계는 거의 사용되지 않아서, 일반적으로 알 수 없음

  • Handler 는 2,3 단계만 이용

  • 캡쳐 단계의 이벤트를 잡으려면 addEventListener 의 3번째 변수를 true 로 설정

    <script>
      for(let elem of document.querySelectorAll('*')) {
        elem.addEventListener("click", e => alert(`Capturing: ${elem.tagName}`), true);
        elem.addEventListener("click", e => alert(`Bubbling: ${elem.tagName}`));
      }
    </script>
    



Event stopPropagation

DOM 이벤트에서 진행되는 Capture, Bubbling 을 막아주는 메서드

  • 그러나 한 이벤트에 여러 이벤트핸들러가 존재할 때
    • 그 중 하나가 버블링을 중지하더라도 다른 이벤트 핸들러는 여전히 실행됨
  • 즉, event.stopPropagation() 메서드를 사용하면 상위로의 이동은 멈추지만 (캡쳐의 경우 하위)
    • 현재 요소에서 다른 처리기가 존재한다면 실행됨
  • 버블링을 멈추고 현재 요소의 핸들러가 실행되지 않도록 하려면
    • event.stopImmediatePropagation() 을 사용하면 됨
  • 이후에는 다른 핸들러가 실행되지 않음



Template literals

내장된 표현식을 허용하는 문자열 리터럴이며, 여러 줄로 이뤄진 문자열과 문자 보간기능(?)을 사용할 수 있음

  • 템플릿 리터럴(Template Literals)은 백틱(` `)을 사용함

  • 플레이스 홀더를 이용하여 표현식을 넣을 수 있음

    • $ 와 중괄호를 이용함 $ {expression}
    • 함수로 전달됨
  • Multi-line string

    • 기존의 Multi-line String

      console.log("string text line 1\n"+
      "string text line 2);
      
    • template literlas

      console.log(`string text line 1
      string text line 2`);
      
  • Expression interpolation (표현식 삽입법)

    • 기존의 표현식(expression)을 문자열에 삽입

      var a = 5;
      var b = 10;
      console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
      // "Fifteen is 15 and
      // not 20."
      
    • template literals

      var a = 5;
      var b = 10;
      console.log(`Fifteen is ${a + b} and
      not ${2 * a + b}.`);
      // "Fiteen is 15 and
      // note 20."
      
  • Nesting templates (이건 뭔지 잘 모르겠다)

    // In ES5
    var classes = 'header'
    classes += (isLargeScreen() ?
       '' : item.isCollapsed ?
        ' icon-expander' : ' icon-collapser');
    
    // ES2015 에서 중첩(nesting) 없이 템플릿 리터럴 사용한 경우
    const classes = `header ${ isLargeScreen() ? '' :
    	(item.isCollapsed ? 'icon-expander' : 'icon-collapser')}`;
    
    // ES2015 에서 중첩된(nested) 템플릿 리터럴을 사용한 경우
    const classes = `header ${ isLargeScreen() ? '' :
    `icon-${item.isCollapsed ? 'expander' : 'collapser'}`}`;
    
  • Tagged templates

    template literals 에서 더욱 발전한 형태

    var person = 'Mike';
    var age = 28;
      
    function myTag(strings, personExp, ageExp) {
      
      var str0 = strings[0]; // "that "
      var str1 = strings[1]; // " is a "
      
      // 사실 이 예제의 string에서 표현식이 두 개 삽입되었으므로
      // ${age} 뒤에는 ''인 string이 존재하여
      // 기술적으로 strings 배열의 크기는 3이 됩니다.
      // 하지만 빈 string이므로 무시하겠습니다.
      // var str2 = strings[2];
      
      var ageStr;
      if (ageExp > 99){
        ageStr = 'centenarian';
      } else {
        ageStr = 'youngster';
      }
      
      // 심지어 이 함수내에서도 template literal을 반환할 수 있습니다.
      return str0 + personExp + str1 + ageStr;
      
    }
      
    var output = myTag`that ${ person } is a ${ age }`;
      
    console.log(output);
    // that Mike is a youngster
    
    • 함수의 첫번 째 인자는 String 배열
    • 나머지 인수는 표현식과 관련됨
    • 함수는 조작된 문자열을 반환할 수 있음
    function template(strings, ...keys) {
      return (function(...values) {
        var dict = values[values.length - 1] || {};
        var result = [strings[0]];
        keys.forEach(function(key, i) {
          var value = Number.isInteger(key) ? values[key] : dict[key];
          result.push(value, strings[i + 1]);
        });
        return result.join('');
      });
    }
      
    var t1Closure = template`${0}${1}${0}!`;
    t1Closure('Y', 'A');  // "YAY!" 
    var t2Closure = template`${0} ${'foo'}!`;
    t2Closure('Hello', {foo: 'World'});  // "Hello World!"
    
  • Raw String

    Escape Sequences 를 처리하지 않고 원시 문자열을 입력한대로 액세스 할 수 있음

    역슬래시를 가진 문자열 생성이 필요할 때 유용함

    function tag(strings) {
      console.log(strings.raw[0]);
    }
      
    tag`string text line 1 \n string text line 2`;
    // logs "string text line 1 \n string text line 2" ,
    // including the two characters '\' and 'n'
    
    • 함수를 만들지 않아도 String 에 raw 메서드가 존재함

      String.raw`Hi\n${2+3}!`
      






© 2018. by HYEON

Powered by HYEON