블로그 이미지
윤영식
Frontend Application Architecter, Full Stacker, KnowHow Dispenser and Bike Rider

Publication

Statistics Graph

Recent Comment

2015.09.06 15:29 HTML5, CSS3

피곤할 때는 술 한잔을 하고 자면 풀릴까 하고 두잔을 하고 잤더니 피곤이 풀리기는 커녕 눈꺼풀만 무겁다. 7시 알람이 휴대폰에서 요란하게 울리지만 20분을 뒤척인 끝에 DOM생각에 벌떡 일어나 냉동실에 얼려 놓은 찹쌀떡을 하나 먹고 길을 나썼다. 관악산의 산바람이 시원하게 얼굴을 스치고 반바지 아래로 차가움이 감싼다. 2일차 DOM강의실로 삼양 컵라면 하나를 들고와서 따끈한 국물을 마시고 손놀릴 준비를 한다. 





Event


"다큐멘트에서 발생하는 이벤트를 설정하고 작용한다."

이벤트 설정에는 이벤트 타입이 있다. 이벤트 처리는 핸들러/리스너라 부르지만 리스너가 표준(스펙)용어이다. 캡쳐/버블은 DOM Tree와 관련이 있다. 이벤트의 버블링은 document 밑의 html 객체까지 올라간다. 기본이 이벤트 전파이기 때문에 적절히 방지를 해주어야 한다. 


"스펙을 보자. 이벤트 스펙"

이벤트 전체 스펙을 읽어보자 

Target : 이벤트가 발생한 곳

1, 2, 3 : 이벤트의 발생 Phase



"캡쳐, 버블링"

window부터 캡쳐링 된다. DOM의 path구조를 메모리상에 만들어 놓고 캡쳐/버블링 phase로 찾아간다. 예로 아래와 같이 파란색의 tr을 클릭하면 먼저 밑으로 간 후 위쪽으로 버블링된다. 3번의 버블링은 막을 수 있지만 1번 단계는 막을 수 없다. 왜 버블링을 발생하고 막게 할 수 있을까?


 

                                         그림에 대한 참조 사이트


"이벤트 설정은 element.addEventListener() 이다."

버블/캡쳐가 기본이고 캡쳐링은 모든 리스너가 무시(false) 한다. IE 6,7,8은 attachEvent() 이고 파라미터가 2개이다. 그리고 IE 6,7,8에서는 캡쳐/버블링을 하지 않는다. HTML5는 on을 넣어 이벤트 리스너를 표현한다. 예) onclick


"이벤트 리스너 사용 예제"

clickNode.addEventListener('click', handleClick, false); 소스에서 세번째 파라미터가 false 이면 버블링을 리스너가 처리하고 true이면 캡쳐링을 리스너가 처리한다. 전파(propagation)에 대해 버블링 막기는 event.stopPropagation() 호출한다. 태그에 할당된 이벤트를 막기위해 예로 <a> 태그의 화면 이동을 막기위해 event.preventDefault() 호출한다. 

DOM Event on jsbin.com 


"이벤트 해제"

이벤트 타입과 핸들러까지 해제를 해준다. 즉, 해제시 이벤트 설정과 파라미터를 같게 설정한다. element.removeEventListener, (IE, element.detachEvent)

DOM - Remove Event on jsbin.com


"메모리 누수"

설정한 이벤트를 해제하지 않았을 때 발생한다. unload 이벤트가 발생했을 때 일괄 해제한다. 설정한 이벤트 인식이 필요하다. 이벤트 설정 내역을 별도로 저장한다. 


"리스너 작성 형태"

엘리먼트에 onclick과 같이 작성할 수 있게 HTML5에서 채택함. <input type="button" onclick="handler()"> 이런 형태는 구조와 제어가 혼합되므로 비추! .js파일을 별도로 작성하여 구조와 제어를 분리한다. 

DOM onclick on jsbin.com


"버블링" 

세번째 파라미터가 false 버블링시에 핸들러 작동하고, true이면 캡쳐링시에 핸들러가 작동한다. true, false를 바꾸어 swim을 클릭하면 실행해 보면 캡쳐링할 때는 sports -> swim으로 찍히고 버블링시에는 swim -> sports가 찍힌다. 

JS Bin on jsbin.com


"버블링 방지" 

전파(propagation)에 대한 방지는 버블링시에 가능하고, 캡쳐링시에는 불가능하다. 

JS Bin on jsbin.com


"디폴트 액션 방지"

preventDefault() 호출. IE 경우는 event.returnValue=false로 설정한다. 이벤트 리스너를 설정하면 헨들러가 먼저 동작하므로 디폴트 액션을 막을 수 있다. 

JS Bin on jsbin.com


"이벤트 속성"

type

target : 이벤트를 설정한 엘리먼트 

currentTarget : 버블링 되면 버블링 엘리먼트로 변경 설정됨 





마우스 이벤트


"마우스 이벤트"

UX적으로 더블클릭은 제외시킨다. click은 mouseup, mousedown을 포함한다. 모바일에서는 mousemove를 쓰지말고 touchmove를 통해 하고 움직일때 x/y 좌표값을 계산하는 DOM parsing을 하지 않도록 프로퍼티를 먼저 설정해준다. 사용자의 베터리를 절약해 줘야 한다. 

mousedown -> mouseup -> click 순으로 발생한다. 

DOM Mouse Event on jsbin.com


"마우스 이벤트 프로퍼티"

altKey, ctrlKey, shiftKey, screenX/Y, clientX/Y

DOM Mouse Event Properties on jsbin.com


"마우스 over, out 이벤트는 어디서 들어왔는지 어디로 나갔는지가 중요하다"

어디는 relatedTarget 이다. margin: 20px의 영역은 마우스 over, out에서 제외된다. 즉, 나의 영역이 아니다. 

JS Bin on jsbin.com


"keypress는 되도록 사용하지 말라"

keydown, keyup 에서 input 태그에서 추천단어(suggest)를 보여주려고 할때는 keydown시 계속 누를 수 있으므로 keyup을 잡아준다. Firefox의 한글 사용 경우는 spacebar넣어야 suggest가 된다. keypress는 keydown <-> keyup 사이에 발생한다. 이를 이용해서 Firefox의 제약을 해결할 수 있다. 


"HTML 이벤트"

focus, blur, change, select, load (렌더링되면), unload (브라우저 닫을경우), resize, scroll, reset (form), submit (form)

DOMContentLoaded가 먼저 수행되어 DOM 객체 Tree 구조를 만들어 놓고, 다음으로 img 태그같은 이미지불러오기도 다 끝나면 onload가 불려지고, 다음으로 자바스크립트를 수행한다. 

JS Bin on jsbin.com

 




Mutation 이벤트


이벤트 타입: DOMNodeInserted, DOMNodeRemoved, DOMAttrModified...

해당 이벤트는 새로운 프로젝트에서 사용하지 말라. (MDN 참조) 속성값이 변한것을 인식해야 할 경우 DOMAttrModified 이벤트 타입을 사용할 수 있다. 

DOM Mutation Event on jsbin.com


신고
posted by peter yun 윤영식
2013.04.27 16:36 AngularJS/Concept

AngularJS에 구성 요소에 대한 Snippet을 살펴본다. 또한 jQuery와 통합하여 사용하는 방법을 알아보자 



1. 들어가기

  - Angular를 통해서 Client-Side에서 데이터와 애플리케이션 로직을 분리한다

  - 최초에 넣어야 할 라이브러리들 

<script type="text/javascript" src="/path/to/angular/angular.js"></script>

<script type="text/javascript" src="/path/to/angular/angular-resource.js"></script>



2. Module

  - 정의

    + Modules are used to fully encapsulate all the angular code of your application into one entry point

    + 컴포넌트와 같으면 Self living 할 수 있다

    + 큰 프로젝트를 할 때의 모듈 나누는 방법

  - 메인 레이아웃 파일에 다음과 코드를 넣는다

    + <html 태그에 넣거나 <body 에 넣거나 한다 

    + SPA를 한다면 아마도 <body> 태그 밑의 특정 부분이 Dynamic DOM 이 될 것이다 

<html data-ng-app="YOUR_APP_NAME">

또는

<html ng-app="YOUR_APP_NAME">


  - JavaScript에서 사용하기 

    + angular는 글로벌 변수이고, directive/controller/filter/service등을 만들기 위한 App 변수를 만들었다

    + ['ngResource']와 같이 의존하는 라이브러리를 설정한다  

var App = angular.module('YOUR_APP_NAME', ['ngResource']);



3. Binding, Expression

  - 양방향 data binding, 조건문, 반복문

  - {{ expression }} 데이터 표현

// html

<div class="records" data-ng-repeat="record in records | orderBy:orderProp">

  <h5> {{ record.title }} </h5>

</div>


// js 

$scope.records = [{ title : 'one' }, { title : 'two' }, { title : 'three' }]; 



4. Dependency Injection

  - 코드를 조직화 하고 테스트 가능하게 만들어준다

  - controllers, module configuraitons, directives, filters, resources, routes 들을 DI 할 수 있다 

// 메소드 파라미터로 DI를 해준다

var Ctrl = function($scope, $http, $location) {

  //now you can use any of the injected variables


  //to change the URL after something has happened then you can use $location

  $location.path('/path/to/new/page');

}

//and now the injection of the variables

Ctrl.$inject = ['$scope','$http','$location'];


  - DI에 대한 개념을 제대로 잡고 싶다면 보지타님의 동영상 보라



5. Routes

  - 요청 uri path와 controller를 맵핑하는 것이다 

// 모듈의 config 에서 정의한다 

// $routeProvider 서비스를 통하여 정의한다 

// uri path에 대하여 templateUrl 과 controller를 맵핑한다 

App.config(['$routeProvider', function($routes) {


  $route.when('/',{

    templateUrl : '/templates/home.html',

    controller : HomeCtrl

  });


  $route.when('/register',{

    templateUrl : '/templates/register.html',

    controller : RegisterCtrl

  });


  $routes.otherwise({

    redirectTo : '/'

  });


}]);



6. Controller & Scope

  - 컨트롤러는 $scope와 함께하여 데이터를 연동한다 

  - controller 만들기 (ng-app의 명칭 즉, 모듈명이 없을 경우)

    + $scope.title를 변경하면 angular는 데이터 변경을 모른다 

    + 하기와 같은 예제에서는 $scope.$apply() 가 필요하다 

    + $apply() 는 일반 JavaScript Context에서 수행되는 것을 AngularJS Context로 수행 되게 해준다 (필히 참조)

    + $apply, $digest, $$phase 란 무엇인가?

// angularjs 모듈에서 파생되지 않은 컨트롤러 펑션

var SomeCtrl = function($scope, $http, $location) {

  $scope.value = 'some value';

};

// controller에게 서비스를 주입하여 준다 (DI)

SomeCtrl.$inject = ['$scope','$http','$location'];


// html에서 {{ }} 를 설정

<div class="header">{{ title }}</div>


// 하기와 같이 설정을 하면 {{ title }} 이 자동으로 바뀌어야 한다  

$scope.title = 'this is awesome';


//if a scope digestion is already going on then it will get picked up and you won't

//have to call the $scope.$apply() method

// $apply를 호출하면 $digest cycle로 들어가고 model이 변화를 감지하여 $watch 에 등록된 expression의 변경을 수행한다

// 즉, view가 re-rendering 되는 것이다 

if(!$scope.$$phase) { //this is used to prevent an overlap of scope digestion

  $scope.$apply(); //this will kickstart angular to recognize the change

}


  - $scope는 $rootScope 상속한 것이다

    + 만일 전체 애플리케이션에서 $scope를 통하여 어떤 펑션을 사용하고 싶다면 하기와 같이 한다

    + 모듈이 로딩 될 때 config 와 run 이 자동 호출된다. run은 main메소드와 유사하다 (참조

App.run(['$rootScope', function($rootScope) {

  $rootScope.sharedFunction = function() { ... };

}]);


  - controller 사용하기 정식 방법 두가지 

    + html 태그안에서 ng-controller 통하여 설정

    + $routes의 controller 설정

// html

<div data-ng-controller="SomeCtrl">...</div>


// js

$routes.when('/some/path',{

  controller : Ctrl,

  templateUrl : '/templates/controller.html'

});



7. Services

  - 전체 애플리케이션에서 공유하는 것들

  - DI를 통하여 객체를 전달함 

//define the service

// App 모듈에 myService가 정의한 서비스의 명칭

App.factory('myService', ['myOtherService', '$location', function(myOtherService, $location) {

  return function(input) {

    //do something with the input using the myOtherService or the $location objects.

    return input;

  };

}]);


//use the service within the controller

// Controller에서 $scope와 myService DI하여 공유한다 

var HomeCtrl = function($scope, myService) {

  var input = '123';

  input = myService(input);

};

HomeCtrl.$inject = ['$scope','myService'];


//use the service a directive

// App 모듈에 directive를 정의한다. myService 서비스를 DI하여 공유한다 

App.directive('myDirective', ['myService',function(myService) {

  return {

    link: function($scope, element, attrs) {

      var input = '123';

      input = myService(input);

    }

  }

}]);



8. Models

  - RESTful Web Service를 호출을 위하여 7번의 서비스 개념으로 만들어 놓고 사용할 수 있다 

// ModelName이라고 서비스를 만든다

// $resource를 통하여 서버사이드로 호출한다 

App.factory('ModelName', ['$resource', function($resource) {

  $resource.url('/path/to/model/controller/:id',{

    id : '@id', //this binds the ID of the model to the URL param

  },{

    query : { method : 'GET', isArray : true }, //this can also be called index or all

    save : { method : 'PUT' }, //this is the update method

    create : { method : 'POST' },

    destroy : { method : 'DELETE' }

  }

}]);


// Controller 에서 ModelName 서비스를 DI 받아서 호출한다

var SomeCtrl = function($scope, $http, $location, ModelName) {

  //now you can use ModelName to do your business

};

SomeCtrl.$inject = ['$scope','$http','$location','ModelName'];


  - ModelName을 통하여 다음과 같이 사용할 수 있다 (연구필요)

    + 서비스를 CRUD query 형태로 만들어서 사용한다

    + Breeze.js 로 확장할 수도 있겠다 

//list all the records on the page

var results = ModelName.query({ search : 'all' }, onSuccessFn, onFailureFn);


//get a specific record

var record = ModelName.get({ id : 123 }, onSuccessFn, onFailureFn); //onSuccessFn and onFailureFn are optional callback functions where you can further customize the response


//create a new ModelName record

var record = new ModelName();


//update that record

record.someAttr = 'someValue';

record.$save();


//or if you prefer to submit your data in a different way

ModelName.save({

    id : record.id

  },{

  somePostObject : {

    attr1 : 'value',

    attr2 : 'value2'

  }

});


//destroy the record (and include a token)

record.destroy({ token : record.token });



9. Directives

  - HTML 코드를 통하여 만들어 놓은 플러그인과 링크를 설정해 주는 것이다. 애플리케이션내에서 블럭을 격리시켜준다. (그냥 컴포넌트 개념을 생각하며 되겠다. 화면 구성을 위하여 UI 컴포넌트 추가하는 것 처럼)

  - 웹앱을 구조화하는데 도움을 준다 

  - Plugin, Validation(유효성검사), Dynamic text properties 또는 i18n, l10n 에도 활용한다 

// link 는 Controller와 Directive가 $scope 를 통하여 데이터를 공유하는 중요 통로이다 

angular.directive('myDirective',function($compile) {

  return {

    templateUrl : '/path/to/some/template.html', //(optional) the contents of this template can be downloaded and constructed into the element

    replace : true, //whether or not to replace the inner data within the element

    link : function($scope, $element, attributes) { //this is where your magic happens

      $scope.title = '...';

    }

  };

});



10. Filters

  - 필터는 재사용 가능한 오퍼레이션이다 

  - binding operation에 내장되어 함께 수행된다 예) 정렬, 문자변형, Pagination 등

// App 모듈에서 myUppercase 명칭의 filter 정의  

App.filter('myUppercase', function(data) {

  for(var i=0; i < data.length; i++) {

    data[i].title = data[i].title.toUpperCase();

  }

  return data;

});


// html에서 사용하기 

<div data-ng-repeat="for record in records | filter:myUppercase">...</div>


// 또는 javascript 코드에서 호출가능

//be sure to inject the $filter object

var values = ['one','two','three'];

values = $filter('myUppercase')(values);



11. HTML5 Mode

  - angular app이 angular의 routing system 안에서 HTML5 history방식으로 관리되게 해준다 

  - 해당 코드만 넣으면 된다 

App.config(['$locationProvider', function($location) {

  $location.html5Mode(true); //now there won't be a hashbang within URLs for browers that support HTML5 history

}]);



12. jQuery 사용

  - 가장 간단하게 angular.js 스크립트 태그 전에 jQuery 태그를 먼저 위치시키면 된다

  - Angular.js는 jqLite를 기본 사용하나 jQuery가 먼저 설정되면 jQuery로 대체되어 사용한다 



<참조>

  - 원문 : use angularjs to power your web application

  - AngularJS 소개 ppt


저작자 표시 비영리 변경 금지
신고
posted by peter yun 윤영식
prev 1 next