'Javascript'에 해당되는 글 112건

  1. 2012.04.16 CSS 조작 함수
  2. 2012.04.16 자바스크립트 비활성화를 위한 <noscript> 사용
  3. 2012.04.11 자바스크립트 이벤트 - EVENT API -
  4. 2012.04.11 자바스크립트 이벤트 - DOM Lelvel 2 Event Model
  5. 2012.04.11 자바스크립트 이벤트 - Element 기본 동작 막기
  6. 2012.04.11 자바스크립트 이벤트 - EVENT Bubbling or Capture
  7. 2012.04.11 자바스크립트 이벤트 - Dom Level 1 Event Model
  8. 2012.04.10 DOM 조작 API
  9. 2012.04.06 innerHTML 속성
  10. 2012.04.05 HTML DOM 로딩 함수

CSS 조작 함수



CSS 조작 함수



지난 포스트에 이어 attr() 함수와 비슷한 구조로 해당 엘리먼트의 style 값을 조작하는 기능을 작성해 보았습니다.


작성된 함수는 아래와 같습니다.


  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <TITLE> New Document </TITLE>
  4. <META NAME="Generator" CONTENT="EditPlus">
  5. <META NAME="Author" CONTENT="">
  6. <META NAME="Keywords" CONTENT="">
  7. <META NAME="Description" CONTENT="">
  8. </HEAD>
  9. <BODY style="margin:0;padding:0;">
  10. <script type="text/javascript">
  11. //<![CDATA[
  12.  
  13. var Element = (function(win, doc){
  14.      
  15.    return new (function(){
  16.      
  17.        function init(){  
  18.          
  19.            return this;
  20.        }
  21.  
  22.        init.prototype = {
  23.            css: css
  24.        };
  25.  
  26.  
  27.        return init;
  28.  
  29.    }());
  30.  
  31.    // 속성 가져오기/변경하기
  32.    function css(elem, args, value)
  33.    {
  34.        elem = elem || top.document.documentElement;
  35.        args = args || (args && args.constructor === Object ? {} : '');
  36.        value = value || '';
  37.  
  38.        if (args.constructor === Object){
  39.          
  40.            for (var n in args){
  41.                 elem.style[n] = args[n];
  42.            }
  43.  
  44.            return elem;
  45.        }
  46.        else if (args.constructor === String){
  47.          
  48.            if (value)
  49.            {
  50.                elem.style[args] = value;
  51.              
  52.                return elem;
  53.            }
  54.            else
  55.            {
  56.                 if (top.document.defaultView && top.document.defaultView.getComputedStyle){
  57.                     // element 의 스타일 객체를 생성한다.
  58.                     var style = top.document.defaultView.getComputedStyle(elem, '');
  59.                     // style 객체의 getPropertyValue는 textAlign이 아닌 text-align 과 같은 속성 이름으로 값을 가져온다.
  60.                     return style && style.getPropertyValue(args.replace(/([A-Z])/g, '-$1').toLowerCase());
  61.                 }
  62.                 else if (elem.style[args]){
  63.                     return elem.style[args];
  64.                 }
  65.                 else if (elem.currentStyle){
  66.                     return elem.currentStyle[args];
  67.                 }
  68.            }
  69.        }
  70.    };  
  71.      
  72. }(window, document));
  73.  
  74.  
  75. window.onload = function()
  76. {
  77.     var elem = document.getElementsByTagName('div')[0];
  78.    
  79.     // 해당 엘리먼트에 style 설정
  80.     Element.css(elem, {
  81.         position:'absolute',
  82.         color:'red',
  83.         textAlign:'center'
  84.     });
  85.    
  86.     // position 설정을 변경한다.
  87.     Element.css(elem, 'position', 'relative');
  88.  
  89.     // 정의된 position 값을 가져온다.
  90.     alert(Element.css(elem, 'position')); // relative
  91.    
  92. };
  93.  
  94.  
  95. //]]>
  96. <div id="root_offset1" style="position:relative;top:100px;left:100px;width:2000px;height:2200px;">dada
  97.     <div id="root_offset2" style="position:relative;top:100px;left:100px">sadasd
  98.         <div id="root_offset3" style="position:relative;top:100px;left:200px;width:200px;height:200px;">test</div>
  99.     <div>
  100. <div>
  101. </BODY>
  102. </HTML>



  1. if (top.document.defaultView && top.document.defaultView.getComputedStyle){
  2.     // element 의 스타일 객체를 생성한다.
  3.     var style = top.document.defaultView.getComputedStyle(elem, '');
  4.     // style 객체의 getPropertyValue는 textAlign이 아닌 text-align 과 같은 속성 이름으로 값을 가져온다.
  5.     return style && style.getPropertyValue(args.replace(/([A-Z])/g, '-$1').toLowerCase());
  6. }


위 코드는 파이어폭스 브라우저만을 위한 코드이며, 해당 엘리먼트의 스타일 객체를 생성하여 그에 따른 스타일 속성값을 가져오는 코드입니다. 

또한, 속성값을 가져오기 위한 getPropertyValue() 함수의 첫 번째 매개변수로 속성 이름을 전달하는데,


전달 시 속성 이름을 text-align과 같은 형태로 전달하기 위해 정규식을 활용하여 전달받은 문자열을 대체시켰습니다.





자바스크립트 비활성화를 위한 <noscript> 사용




자바스크립트의 활성/비활성 제어는 각 브라우저의 옵션에서 제어할 수 있다는 사실은 이미 알려진지 오래입니다.


즉, 각 클라이언트의 구미에 따라 자바스크립트가 브라우저에 의해 활성화 될수도 있고 비활성화될 수도 있다는 얘기입니다.



이런 상황에 맞도록 자바스크립트가 비활성화되어있는 경우를 보완하기 위한 여러 가지 방법을 이번 포스트에서 다뤄 보도록 

하겠습니다.






1. 대체 컨텐츠 기법


이는 가장 간단한 방법으로 자바스크립트 비활성화 시 해당 컨텐츠를 대체시키는 방법입니다.



  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. </HEAD>
  8.     <div id="javascript_msg" style="text-align:center;vertical-align:middle;">자바스크립트가 비활성 되었습니다.</div>
  9. </BODY>
  10. </HTML>







대체 컨텐츠 기법 2



  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. </HEAD>
  8.     <style type="text/css">
  9.     /*<![CDATA[*/
  10.  
  11.         html *{ margin: 0px; padding: 0px }
  12.         body { width: 100%; height: 100%; background:red; }
  13.  
  14.     /*]]>*/
  15.     </style>
  16. </BODY>
  17. </HTML>



대체 css(스타일)를 적용시키는 방법











2. 페이지 리디렉션 기법


자바스크립트 비활성화 시 해당 페이지를 리디렉션 시키는 방법입니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6.     <meta http-equiv="Refresh" content="0; URL=http://www.enable-javascript.com/ko/">
  7. <META NAME="Description" CONTENT="">
  8. </HEAD>
  9. </BODY>
  10. </HTML>




리디렉션 페이지 ( http://www.enable-javascript.com/ko/ )


위 리디렉션 페이지는 자바스크립트 활성화 방안에 대해 국가별 컨텐츠를 제공하고 있습니다.










3. 링크 및 폼 전송시 자바스크립트에 의존하지 않게 개발하기



첫 번째 예제는 앵커 태그의 어트리뷰트인 href 에 "#"을 정의하고, click 이벤트 타입에는 매개변수로 전달된 페이지로 이동시키는 자바스크립트 코드 함수를 핸들러로 할당하였습니다.


그에 따른 결과로 자바스크립트 비활성화 시 해당 태그의 어트리뷰트에 정의된 기본 동작을 수행할 것이며, 의도된 결과와는 다르게 페이지의 현재 위치를 고수할 것입니다.



p.s: #은 현재 위치를 의미합니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. </HEAD>
  8. <script type="text/javascript">
  9. //<![CDATA[
  10.     function goURL(url){       
  11.         top.location.href = url;
  12.         return false;
  13.     }
  14. //]]>
  15. <a href="#" onclick="goURL('http://www.naver.com')">goURL</a>
  16. </BODY>
  17. </HTML>



자바스크립트 비활성화 시에도 의도된 결과를 나타내기 위해 아래와 같이 해당 코드를 수정합니다.



  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. </HEAD>
  8. <script type="text/javascript">
  9. //<![CDATA[
  10.     function goURL(url){       
  11.         top.location.href = url;
  12.         return false;
  13.     }
  14. //]]>
  15. <a href="http://www.naver.com" onclick="return goURL('http://www.naver.com')">goURL</a>
  16. </BODY>
  17. </HTML>
  18.  



앵커 태그의 href 어트리뷰트에 이동시킬 URL을 정의하였고, 자바스크립트 함수 반환 값을 false로 정의하여 해당 이벤트 타입 안에서 태그의 기본동작을 막아 페이지 이동이 2번 수행되지 않게 만들었습니다.



엘리먼트의 기본동작을 막는 방법으로는 아래 링크를 참조 하시기 바랍니다.




자바스크립트 이벤트 - Element의 기본동작 막기




폼 전송시에도 마찬가지로 submit 이벤트 타입에 할당된 함수의 반환 값을 false로 정의하여 폼 태그가 가지고 있는 기본 동작을 막습니다.



아래는 폼 전송시 자바스크립트에 의존하지 않는 예제 코드 입니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. </HEAD>
  8. <script type="text/javascript">
  9. //<![CDATA[
  10. var Member = (function(){
  11.  
  12.  
  13.    return new (function(){
  14.      
  15.        function init(){  
  16.          
  17.            return this;
  18.        }
  19.  
  20.        init.prototype = {
  21.            login: login
  22.        };
  23.  
  24.  
  25.        return init;
  26.  
  27.    }());
  28.  
  29.  
  30.     function login(f){     
  31.        
  32.         var id = document.getElementById('id');
  33.         var pass = document.getElementById('pass');
  34.  
  35.         if (!id.value || !pass.value) return false;
  36.     }
  37.  
  38.  
  39. })();
  40. //]]>
  41.     <form id="login" method="post" target="login_frm" action="http://naver.com" enctype="application/x-www-form-urlencoded"  onsubmit="return Member.login(this)">
  42.         <fieldset>
  43.             <legend>로그인</legend>
  44.             <input type="text" id="id" name="id"  />
  45.             <input type="text" id="pass" name="pass"  />
  46.         </fieldset>
  47.         <input type="submit" value="폼제출" />
  48.     </form>
  49.  
  50.     <iframe id="login_frm" name="login_frm" width="0" height="0" frameborder="0"></iframe>
  51. </BODY>
  52. </HTML>


코드를 이와 같이 작성하면 자바스크립트의 활성 / 비활성 유무에 상관없이 폼전송이 가능합니다.




자바스크립트 이벤트 - EVENT API -



EVENT API



지금까지 DOM 이벤트에 관한 내용으로 강좌를 쭉~ 진행해 보았습니다.

이번시간에는 이제까지 학습한 내용을 바탕으로 간단한 EVENT API 코드를 작성하여 각 함수 호출 시 해당 엘리먼트의 이벤트 변화를 살펴보도록 하겠습니다.




아래는 작성된 EVENT API 예제 소스입니다.

  1. var Event = (function(win, doc){
  2.    
  3.     var $this = null;      
  4.  
  5.     return new (function(){
  6.        
  7.         function init(){   
  8.            
  9.             $this = this;
  10.  
  11.             return this;
  12.         }
  13.  
  14.         init.prototype = {
  15.             bind: bind,
  16.             unbind: unbind,
  17.             stopDefault: stopDefault,
  18.             stopPropagation: stopPropagation,
  19.             relatedEventBind: relatedEventBind
  20.         };
  21.  
  22.  
  23.         return init;
  24.  
  25.     }());
  26.  
  27.     // 이벤트 할당
  28.     function bind(elem, type, handler, capture)
  29.     {    
  30.         type = typeof type === 'string' && type || '';
  31.         handler = handler || function(){ ; };
  32.        
  33.         if (elem.addEventListener){
  34.             elem.addEventListener(type, handler, capture);
  35.         }
  36.         else if (elem.attachEvent){
  37.             elem.attachEvent('on' + type, handler);
  38.         }
  39.  
  40.         return elem;
  41.     };
  42.    
  43.     // 이벤트 삭제
  44.     function unbind(elem, type, handler)
  45.     {      
  46.         type = typeof type === 'string' && type || '';
  47.         handler = handler || function(){ ; };
  48.  
  49.         if (elem.removeEventListener){         
  50.             elem.removeEventListener(type, handler);
  51.         }
  52.         else if (elem.detachEvent){
  53.             elem.detachEvent('on' + type, handler);
  54.         }
  55.  
  56.         return elem;
  57.     };
  58.  
  59.  
  60.     // 엘리먼트의 기본동작 막기
  61.     function stopDefault(e)
  62.     {  
  63.         e = window.event || e;
  64.  
  65.         if (window.event) e.returnValue = false;
  66.         else if (e.preventDefault) e.preventDefault();
  67.     };
  68.    
  69.  
  70.     // 이벤트 버블링 중지
  71.     function stopPropagation(e)
  72.     {
  73.         e = window.event || e;
  74.  
  75.         if (window.event) e.cancelBubble = true;
  76.         else if (e.stopPropagation) e.stopPropagation();
  77.     };
  78.  
  79.    
  80.     // mouseover, mouseout 시 이벤트가 할당된 해당 엘리먼트만 호출하기
  81.     function relatedEventBind(e, callback)
  82.     {  
  83.         var target = window.event ? e.srcElement : e.target
  84.           , relatedTarget = window.event ? window.event.toElement : e.relatedTarget;
  85.    
  86.         callback = callback || function(){ ; };
  87.  
  88.         if (relatedTarget)
  89.         {
  90.             while (relatedTarget)
  91.             {
  92.                 if (relatedTarget === target) break;
  93.                 relatedTarget = relatedTarget.parentNode;
  94.             }
  95.         }
  96.  
  97.         callback.call(null, target);
  98.     };
  99.        
  100. }(window, document));




- 이벤트 할당


  1. Event.bind(window, 'load', function(){
  2.  
  3.  
  4.     var handler1 = function(e){
  5.        
  6.         alert('엘리먼트의 기본 동작을 막는 이벤트 할당');
  7.         Event.stopDefault(e);
  8.     };
  9.  
  10.     var handler2 = function(e){
  11.         alert('기본 이벤트 할당');
  12.     };
  13.  
  14.    
  15.     Event.bind(document.getElementById('test_object1'), 'click', handler1, false);
  16.  
  17.     Event.bind(document.getElementById('test_object2'), 'click', handler2, false);
  18.  
  19.  
  20. }, false);



해당 엘리먼트의 이벤트 타입에 핸들러가 아래와 같이 할당 되었습니다.




- 이벤트 할당 및 삭제


  1. Event.bind(window, 'load', function(){
  2.  
  3.  
  4.     var handler1 = function(e){
  5.        
  6.         alert('엘리먼트의 기본 동작을 막는 이벤트 할당');
  7.         Event.stopDefault(e);
  8.     };
  9.  
  10.     var handler2 = function(e){
  11.         alert('기본 이벤트 할당');
  12.     };
  13.  
  14.    
  15.     // 이벤트 할당
  16.  
  17.     Event.bind(document.getElementById('test_object1'), 'click', handler1, false);
  18.  
  19.     Event.bind(document.getElementById('test_object2'), 'click', handler2, false);
  20.    
  21.     // 이벤트 삭제
  22.  
  23.     Event.unbind(document.getElementById('test_object1'), 'click', handler1);
  24.  
  25.     Event.unbind(document.getElementById('test_object2'), 'click', handler2);
  26.  
  27. }, false);



해당 엘리먼트의 이벤트 타입에 핸들러가 아래와 같이 삭제 되었습니다.









추가적으로 해당 엘리먼트의 이벤트 버블링을 중지 시키는 소스 입니다.


  1. Event.bind(window, 'load', function(){
  2.  
  3.  
  4.     Event.bind(document.getElementById('test_object1'), 'click', function(e){
  5.         // 버블링 중지
  6.         Event.stopPropagation(e);
  7.     }, false);
  8.  
  9.  
  10. }, false);





자바스크립트 이벤트 - DOM Lelvel 2 Event Model




DOM Lelvel 2 이벤트 모델은 Level 1 이벤트 모델의 최대 단점이었던 이벤트 타입당 복수 핸들러 할당이 가능한 이벤트 설계 모델입니다.

즉, 해당 엘리먼트의 이벤트 타입당 하나 이상의 핸들러 할당이 가능합니다.




이벤트 할당 방법은 아래 코드와 같습니다.

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. <script>
  10.  
  11.  
  12. // DOM LEVEL 2 Event Model 처리 함수
  13. function bind(elem, type, handler, capture)
  14. {
  15.  
  16.     type = typeof type === 'string' && type || '';
  17.     handler = handler || function(){ ; };
  18.    
  19.     if (elem.addEventListener){
  20.         elem.addEventListener(type, handler, capture);
  21.     }
  22.     else if (elem.attachEvent){
  23.         elem.attachEvent('on' + type, handler);
  24.     }
  25.  
  26.     return elem;
  27. };
  28.  
  29. // 동일 엘리먼트의 동일 이벤트 타입에 복수 이벤트 할당
  30. var cnt = 0;
  31. bind(window, 'load', function(){
  32.  
  33.     bind(document.getElementById('test_object1'), 'click', function(e){
  34.                
  35.             alert(cnt++); // 0
  36.     }, false);
  37.  
  38.     bind(document.getElementById('test_object1'), 'click', function(e){
  39.                
  40.             alert(cnt++); // 1
  41.  
  42.     }, false);
  43.  
  44.  
  45. }, false);
  46.  
  47. </script>
  48.  
  49.  
  50. </HEAD>
  51. <BODY>
  52. <div id="test_object1">CLICK!!!</div>
  53. </BODY>
  54. </HTML>

위 소스는 Dom Level 2 이벤트 모델의 메서드로 작성된 소스이며, test_object1 엘리먼트의 클릭 이벤트 호출 시 전역 cnt 변수의 증감값을 대화창으로 노출시키도록 하였습니다.


자바스크립트 이벤트 - Element 기본 동작 막기




엘리먼트의 기본 동작 막기:


몇몇 이벤트들은 해당 엘리먼트가 가지고 있는 기본 동작을 자동으로 실행 시키게 됩니다.

예를 들어 앵커(<a>) 엘리먼트의 click 이벤트는 엘리먼트의 href 속성에 할당된 값을 브라우저에 실행(페이지 이동)시키며, form 엘리먼트의 submit 이벤트는 호출 시 폼을 전송(제출)하기 위한 엘리먼트의 기본 동작을 수행합니다.


또한, 엘리먼트의 기본동작을 막는 방법에는 할당된 이벤트 핸들러의 반환 값을 false로 받는 방법과 아래 예제와 같이 해당 이벤트의 속성 및 메서드를 활용한 방법이 존재합니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. <script>
  10.  
  11. // 기본 이벤트를 막지 않은 경우
  12. function msg(obj, msg, e){
  13.    
  14.     e = window.event || e;
  15.     alert(obj.nodeName);
  16.  
  17. };
  18.  
  19. // 이벤트 핸들러의 반환값을 false 받아 기본 동작을 막는 방법
  20. function msg1(obj, msg, e){
  21.    
  22.     e = window.event || e;
  23.     alert(obj.nodeName);
  24.  
  25.     return false;
  26. };
  27.  
  28.  
  29. // 해당 이벤트의 속성 및 메서드를 활용하여 기본 동작을 막는 방법
  30. function msg2(obj, msg, e){
  31.    
  32.     e = window.event || e;
  33.     alert(obj.nodeName);
  34.    
  35.     stopDefault(e);
  36. };
  37.  
  38. // 엘리먼트의 기본 동작 막기
  39. function stopDefault(e)
  40. {
  41.     if (window.event) e.returnValue = false;
  42.     else if (e.preventDefault) e.preventDefault();
  43. };
  44.  
  45. </script>
  46.  
  47.  
  48. </HEAD>
  49. <BODY>
  50. <!-- mouseover 이벤트 타입은 click 이벤트 타입과 달리 해당 엘리먼트의 기본동작이 일어나지 않는다. -->
  51. <a href="http://naver.com" onmouseover="msg(this, 'test');">mouseover(기본 동작이 일어나지 않는 이벤트 타입에 할당)</a><br /><br />
  52. <!-- click 이벤트 타입은 기본 동작이 일어난다. -->
  53. <a href="http://naver.com" onclick="msg(this, 'test');">click(기본 동작이 일어난다.)</a><br /><br />
  54. <a href="http://naver.com" onclick="return msg1(this, 'test');">click(핸들러의 false 반환값으로 기본동작 막기)</a><br /><br />
  55. <a href="http://naver.com" onclick="msg2(this, 'test');">click(이벤트 속성 및 메서드로 기본동작 막기)</a><br />
  56. </BODY>
  57. </HTML>





자바스크립트 이벤트 - EVENT Bubbling or Capture




1. 이벤트 버블링이란?


해당 엘리먼트의 이벤트 발생 시 브라우저가 시행하는 특정 이벤트 처리 절차를 가리킵니다.


- 이벤트 처리 절차는 아래와 같습니다.

1. 해당 엘리먼트의 이벤트 속성에 할당된 핸들러를 호출합니다.

2. 최초 이벤트가 발생한 엘리먼트의 위치부터 루트 엘리먼트(#document)까지의 모든 부모 엘리먼트들을 검사하여 최초 발생한 이벤트 타입과 동일한 이벤트 타입에 핸들러가 할당되어 있다면 이를 실행시킵니다.






- 아래는 버블링 전파에 대한 내용을 도식화한 그림입니다.






또한, 아래 작성된 코드로 이벤트 전파 테스트가 가능합니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML onclick="msg(this, 'test');">
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. <script>
  10.  
  11. function msg(obj, msg, e){
  12.    
  13.     e = window.event || e;
  14.     alert(obj.nodeName);
  15. };
  16.  
  17.  
  18. </script>
  19.  
  20.  
  21. </HEAD>
  22. <BODY onclick="msg(this, 'test');">
  23. <div id="test_object1" onclick="msg(this, 'test');">
  24.     <div id="test_object2" onclick="msg(this, 'test');"></div>
  25.     <!-- 방법 2: HTML 어트리뷰트에 할당하는 방법 -->
  26.     <div id="test_object3" onclick="msg(this, 'test');">CLICK!!!</div>
  27. </div>
  28. </BODY>
  29. </HTML>


위 코드의 실행 결과는 아래와 같습니다.

[test_object3] onclick handler --> [test_object1] onclick handler --> [body] onclick handler --> [html] onclick handler --> [#document] onclick handler




추가코드: 이벤트 버블링 방지하기

 function stopPropagation(e) {
    //IE or 표준 브라우저
    if (e.cancelBubble) e.cancelBubble = true;
    else if (e.stopPropagation) e.stopPropagation();
}



2. 이벤트 캡처란? 

DOM LEVEL 2 이벤트 모델부터 지원하기 시작했으며, IE 브라우저를 제외(IE 브라우저는 버블링 처리만 지원)한 표준 브라우저에서만 지원하고 버블링과는 반대되는 이벤트 처리 절차를 가집니다.

즉, 버블링 처리 절차 와는 반대로 루트 엘리먼트 부터 이벤트가 발생한 엘리먼트의 위치로 이벤트를 전파시킵니다.



아래는 버블링과 마찬가지로 캡처 시 전파에 관한 내용을 도식화한 그림입니다.



또한, 아래 작성된 코드로 이벤트 전파 테스트가 가능합니다.


  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <HTML>
  3. <HEAD>
  4. <TITLE> New Document </TITLE>
  5. <META NAME="Generator" CONTENT="EditPlus">
  6. <META NAME="Author" CONTENT="">
  7. <META NAME="Keywords" CONTENT="">
  8. <META NAME="Description" CONTENT="">
  9. <script>
  10.  
  11.  
  12. // DOM LEVEL 2 Event Model 처리 함수
  13. function bind(elem, type, handler, capture)
  14. {
  15.  
  16.     type = typeof type === 'string' && type || '';
  17.     handler = handler || function(){ ; };
  18.    
  19.     if (elem.addEventListener){
  20.         elem.addEventListener(type, handler, capture);
  21.     }
  22.     else if (elem.attachEvent){
  23.         elem.attachEvent('on' + type, handler);
  24.     }
  25.  
  26.     return elem;
  27. };
  28.  
  29. // 이벤트 할당
  30. bind(window, 'load', function(){
  31.  
  32.     bind(document, 'click', function(e){
  33.        
  34.             var e = window.event || e
  35.               , target = e.srcElement || e.target;
  36.            
  37.             alert(document.nodeName);
  38.  
  39.     }, true);
  40.  
  41.     bind(document.documentElement, 'click', function(e){
  42.        
  43.             var e = window.event || e
  44.               , target = e.srcElement || e.target;
  45.            
  46.             alert(document.documentElement.nodeName);
  47.  
  48.     }, true);
  49.  
  50.     bind(document.body, 'click', function(e){
  51.        
  52.             var e = window.event || e
  53.               , target = e.srcElement || e.target;
  54.            
  55.             alert(document.body.nodeName);
  56.  
  57.     }, true);
  58.  
  59.     bind(document.getElementById('test_object1'), 'click', function(e){
  60.        
  61.             var e = window.event || e
  62.               , target = e.srcElement || e.target;
  63.            
  64.             alert(document.getElementById('test_object1').nodeName);
  65.  
  66.     }, true);
  67.  
  68.     bind(document.getElementById('test_object2'), 'click', function(e){
  69.        
  70.             var e = window.event || e
  71.               , target = e.srcElement || e.target;
  72.            
  73.             alert(document.getElementById('test_object2').nodeName);
  74.  
  75.     }, true);
  76.  
  77.  
  78. }, false);
  79.  
  80. </script>
  81.  
  82.  
  83. </HEAD>
  84. <BODY>
  85. <div id="test_object1">
  86.     <div id="test_object2">CLICK!!!</div>
  87. </div>
  88. </BODY>
  89. </HTML>


마지막으로 앞서 말씀드린바와 같이 이벤트 캡처는 IE 브라우저를 제외한 표준 브라우저에서만 지원하므로 실행 결과는 아래와 같습니다.


IE 브라우저: 

위 소스중 bind(, , , true) 함수 호출 시 캡처 상태를 나타내는 매개변수에 true를 넘겨도 캡처를 지원하지 않으므로 이벤트 호출 시 버블링 방식으로 처리됩니다):


[test_object2] onclick handler --> [test_object1] onclick handler --> [body] onclick handler --> [html] onclick handler --> [#document] onclick handler

표준 브라우저:


[ #document ] onclick handler --> [ html ] onclick handler --> [body] onclick handler --> [ test_object1] onclick handler --> [ test_object2] onclick handler



자바스크립트 이벤트 - Dom Level 1 Event Model



DOM LEVEL 1 모델의 이벤트 할당 방법으로는 해당 엘리먼트의 속성에 할당하는 방법과 HTML 어트리뷰트에 할당하는 방법이 존재합니다.

또한, 어트리뷰트에 할당시키는 예제를 보시면 마치 alert() 함수가 해당 엘리먼트의 click 이벤트로 할당되었다고 생각할 수 있겠지만,  사실은 그렇지 않습니다.

이유는 아래 코드와 같이 할당된 어트리뷰트값(alert() 함수)을 함수 구현으로 사용하는 익명 함수(function(e){ ; })가 새로 생성되기 때문입니다.

마지막으로  DOM LEVEL 0  모델의 단점으로는 앞으로 배우게 될 DOM LEVEL 2 모델의 이벤트 설계와는 달리 해당 엘리먼트의 특정 이벤트 타입에 단 한 개의 이벤트 핸들러만 할당할 수 있다는 것입니다.

즉,  DOM LEVEL 0  이벤트 모델에선 복수 이벤트 할당이 불가능합니다.

 


그럼 아래 예제 소스 코드를 보시겠습니다.




방법 1: 엘리먼트 속성에 할당

  1. function msg(obj, msg, e){
  2.    
  3.     e = window.event || e;
  4.     alert(obj.nodeName);
  5.     alert(msg);
  6.     alert(e);
  7. };
  8.  
  9. document.getElementById('test_object3').onclick = function(e){ msg.apply(this, [this, 'test', e]); };
  10.  
  11. // Function.apply() 함수를 이용하여 해당 엘리먼트를 가리키는 this를 넘겨준다.
  12. //document.getElementById('test_object3').onclick = function(e){ msg.apply(this, ['test', e]); };



방법 2: HTML 어트리뷰트에 할당

  1. <div id="test_object3" onclick="msg(this, 'test');">CLICK!!!</div>



이벤트 실행 결과


 



DOM 조작 API



DOM 조작 API



지난번 포스트에서 다루었던 DOM 탐색 방법에 대해 기억나십니까?


이번 시간에는 지난 포스트에 이어 노드의 생성, 변경, 삭제에 대해 다뤄보겠습니다.




아래 작성된 함수들을 각각 호출하여 DOM 구조가 어떤 식으로 변경되는지 알아보겠습니다.



해당 소스 수정 및 추가 작성(2012/10/08):

http://jsfiddle.net/zEdAp/1/



var Element = (function (win, doc) {

    var init = function () {
        return this;
    }

    init.prototype = {
        first: first,
        prev: prev,
        next: next,
        last: last,
        attr: attr,
        create: create,
        before: before,
        after: after,
        append: append,
        remove: remove
    };

    return new init();




    // Core
    function first(elem) {

        elem = elem || document.documentElement;

        return elem && elem.nodeType === 1 ? elem.firstChild : next(elem);
    };

    function prev(elem) {

        elem = elem || document.documentElement;

        do {
            elem = elem && elem.previousSibling;
        }
        while (elem && elem.nodeType !== 1)

        return elem;
    };

    function next(elem) {

        elem = elem || document.documentElement;

        do {
            elem = elem && elem.nextSibling;
        }
        while (elem && elem.nodeType !== 1)

        return elem;
    };

    function last(elem) {

        elem = elem || document.documentElement;

        return elem && elem.nodeType === 1 ? elem.lastChild : prev(elem);
    };

    // 속성 가져오기/변경하기
    function attr(elem, args, value) {

        elem = elem || document.documentElement;
        args = args || (args && args.constructor === Object ? {} : '');
        value = value || '';

        if (args.constructor === Object) {

            for (var n in args) {

                var t = { 'for': 'htmlFor', 'class': 'className'}[n] || n;

                elem.setAttribute && elem.setAttribute(t, args[n]);
            }

            return elem;
        }
        else if (args.constructor === String) {

            var t = { 'for': 'htmlFor', 'class': 'className'}[args] || args;

            if (value) {
                elem.setAttribute && elem.setAttribute(t, value);

                return elem;
            }
            else {
                return elem.getAttribute && elem.getAttribute(t) ? elem.getAttribute(t) : '';
            }
        }
    };

    // 객체 생성하기
    function create(tag, opt) {

        tag = tag || '';
        opt = opt || {};

        var elem = document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml', tag) : document.createElement(tag);

        return attr(elem, opt);
    };

    // 객체 속성 존재 여부
    function hasAttr(elem, n) {

        if (!elem) return false;

        n = n || '';

        return elem.getAttribute(n) ? true : false;
    };


    // 해당 객체의 이전 형제로 객체 삽입하기
    function before(before, elem) {

        if (!before || !elem) return null;

        var parent = before && before.parentNode
        , elem = getElement(elem);

        return parent.insertBefore(elem, before);
    };

    // 해당 객체의 이후 형제로 객체 삽입하기
    function after(after, elem) {

        if (!after || !elem) return null;

        var parent = after && after.parentNode
        , elem = getElement(elem);

        return insertAfter(parent, elem, after);
    };


    function insertAfter(parent, elem, after) {
        return after ? parent.insertBefore(elem, after.nextSibling) : append(parent, elem);
    };


    function getElement(elem) {

        if (!elem) return null;

        if (elem.constructor === String) {
            var t = document.createElement('div');
            t.innerHTML = elem;
            elem = t;
        }

        return elem;
    };

    // 해당 객체의 자식 추가
    function append(parent, elem) {

        parent = parent || document.documentElement;
        elem = elem || document.body;

        elem = getElement(elem);

        return parent.appendChild(elem);
    };

    // 해당 객체 삭제
    function remove(elem) {

        var parent = elem && elem.parentNode || document.documentElement;
        elem = elem || document.body;

        return parent.removeChild(elem);
    };

})(window, document);



1. 문서의 첫 번째 div 엘리먼트의 속성을 아래와 같이 변경합니다.


  1. // 함수의 두 번째 매개변수 값으로 각각의 속성이 정의된 객체를 전달하여 호출합니다.
  2.  
  3. Element.attr(document.getElementsByTagName('div')[0], {
  4.     'id': 'test1',
  5.     'name': 'test2',
  6.     'class': 'test3'
  7. });
  8.  
  9. // 함수의 두 번째 매개변수 값으로 객체가 아닌 속성 이름 과 값을 전달하여 정의할 수도 있습니다.
  10. Element.attr(document.getElementsByTagName('div')[0], 'for', 'test4');
  11.  
  12. // 위에서 정의된 엘리먼트의 id속성값을 반환합니다.
  13. alert(Element.attr(document.getElementsByTagName('div')[0], 'id')); // test1





아래는 변경된 엘리먼트의 상태를 나타냅니다.










2. doccument.body 엘리먼트의 자식으로 신규로 생성된 div 엘리먼트를 추가 합니다.


  1. // 두 번째 매개변수 값으로 객체를 추가하여 엘리먼트의 속성을 정의 합니다.
  2. document.body.appendChild(Element.create('div', {'id': 'test1'}));





아래는 변경된 엘리먼트의 상태를 나타냅니다.











3. 해당 엘리먼트(test1)의 자식으로 div 엘리먼트를 추가 합니다.


  1. // 해당 엘리먼트(test1)의 자식으로 div 엘리먼트를 추가 합니다.
  2. var div = document.createElement('div');
  3. div.innerHTML = '<span>div test</span>';
  4.  
  5.  
  6. //Element.append(document.getElementById('test1'), '<div>div test</div>');
  7. Element.append(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.










4. 해당 엘리먼트(test1)의 다음 형제로 div 엘리먼트를 추가 합니다.


  1. var div = document.createElement('div');
  2. div.innerHTML = '<span>div test</span>';
  3.  
  4.  
  5. Element.after(document.getElementById('test1'), '<div><table><tr><td>test</td></tr></table></div>');
  6. Element.after(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.










5. 해당 엘리먼트(test1)의 이전 형제로 div 엘리먼트를 추가 합니다.


  1. var div = document.createElement('div');
  2. div.innerHTML = '<span>div test</span>';
  3.  
  4. Element.before(document.getElementById('test1'), '<div>test2</div>');
  5. Element.before(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.







6. document.body 엘리먼트를 삭제 합니다.


  1. Element.remove(document.body);





아래는 변경된 엘리먼트의 상태를 나타냅니다.



작성된 DOM API를 활용하여 문서가 각각 변경되는 것을 확인해 보았으며, 또한, 위 코드를 개선하여 더욱 효율적인 API를 만들어 보시기 바랍니다.








innerHTML 속성



innerHTML 속성



innerHTML 속성은 해당 엘리먼트 내부의 모든 HTML과 TEXT를(XML DOM 제외) 가져올 수 있는 엘리먼트 객체의 맴버입니다.


또한, innerHTML 은 속도가 매우 빠르다는 장점이 있으며, 단점으로는 표현에 대한 명확한 표준이 없어서 각 브라우저마다 전부 다르게 표현하고 있다는 것입니다.



아래는 현재 브라우저 버전을 기준으로 innerHTML 속성의 반환 값이 각 브라우저에서 어떻게 표현되고 있는지 테스트해 본 

결과입니다.




소스코드: 

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
  2. <TITLE> New Document </TITLE>
  3. <META NAME="Generator" CONTENT="EditPlus">
  4. <META NAME="Author" CONTENT="">
  5. <META NAME="Keywords" CONTENT="">
  6. <META NAME="Description" CONTENT="">
  7. <style type="text/css">
  8. /*<![CDATA*/
  9.  
  10.     html { color: red; }
  11.  
  12. /*]]>*/
  13. <!-- Defer -->
  14. </HEAD>
  15. <script type="text/javascript">
  16. //<![CDATA
  17.     alert(document.documentElement.innerHTML);
  18. //]]>
  19. </BODY>
  20. </HTML>




IE(8)+


IE 브라우저는 반환된 엘리먼트들을 모두 대문자로 표현 해준다.



파이어폭스(11.0)



크롬(18.0)



DOM 조작 시 많은 부분에서 아주 유용하게 쓰일 수 있는 속성 중 하나 입니다. 

잘 알아 두시기 바랍니다.



HTML DOM 로딩 함수



- DOM 로드 함수



자바스크립트를 활용한 DOM 조작 시 가장 먼저 염두에 둬야 할 부분은 각 엘리먼트들의 로드 여부를 알아내는 것입니다.


만약 엘리먼트가 로드되지 않은 상태에서 접근을 시도 하면 에러가 발생하기 때문입니다.


또한, 엘리먼트들의 로드 여부를 알아내기 위해서 아래와 같은 방법들이 존재하며, 그 방법들을 실행 순서로 나열하였습니다.




1. defer: 페이지 파싱이 완료된 다음 해당 스크립트를 실행합니다. (IE 6+ 전용)


2. DOMContentLoaded: DOM 요소의 로딩이 완료되면 발생합니다. 단, 이미지가 로드되기 전에 실행됩니다. (IE 미지원)


3. onreadystatechange: 아래와 같이 객체 상태(readyState)가 변경될 때 발생합니다.((IE6+, Opera 지원) readyState는 모든 브라우저가 반환)


- 3 - 1. uninitialized: 객체 데이터로 초기화되지 않았다.

- 3 - 2. loading: 객체 데이터가 로딩되고 있다.

- 3 - 3. interactive: 객체 데이터가 완전히 로딩되지 않았어도 사용자가 객체에 접근할 수 있다.

- 3 - 4. loaded: 객체 데이터 로딩이 완료되었다.

- 3 - 5. complete: 객체 초기화가 완료되었다.


4. onload: 문서의 로딩이 완료 되었을 때 발생합니다. (페이지 로딩 순서 중 가장 마지막에 위치합니다.)



아래는 위에서 언급된 속성(defer)과 이벤트(DOMContentLoaded || onreadystatechange || onload)들을 활용하여 

페이지 DOM 로드 여부를 알아낸 후 매개변수로 정의된 callback 함수를 호출하는 예제소스 입니다.




- 예제소스 IE 테스트 결과


defer:




onreadystatechange:




onload:




예제소스 크롬 테스트 결과


defer(크롬 브라우저는 defer 속성을 지원하지 않기 때문에 null을 반환합니다):



DOMContentLoaded:



onload:




테스트 결과:


IE: defer --> onreadystatechange --> onload

Chrome: defer(미지원) --> DOMContentLoaded --> onload



참고사이트:


@Pain님 블로그

http://painone7.tistory.com/37#recentTrackback">http://painone7.tistory.com/37#recentTrackback">http://painone7.tistory.com/37#recentTrackback




prev 1 ··· 3 4 5 6 7 8 9 ··· 12 next