[Text Node 제어와 Document 및 스크린, 스크롤 위치 제어]



1. [ Text Node의 제어 ]

- 텍스트 데이터 확인 : ELEMENT.data or ELEMENT.nodeValue
- 텍스트 데이터 조작
-- element.appendData("추가할 텍스트 문자열") : 맨 마지막 부분에 문자열 추가
-- element.deleteData( startIndex, length ) : 해당 index부터 몇글자 지울지
-- element.insertData( startIndex, "추가할 문자열" ) : 해당 index 위치에 삽입
-- element.replaceData( startIndex, length, "바꿀 문자열" ) : 해당 index부터 length글자만큼을 새로운 바꿀 문자열로 교체
-- element.substringData( startIndex, length ) : 해당 인덱스부터 length개만큼 가져옴

1
2
3
4
5
6
7
8
9
10
<ul>
<li id="target">html</li>
<li>css</li>
<li>JavaScript</li>
</ul>
<script>
var t = document.getElementById('target').firstChild;
console.log(t.nodeValue);
console.log(t.data);
</script>

<!DOCTYPE html>
<html>
<head>
<style>
#target{
font-size:77px;
font-family: georgia;
border-bottom:1px solid black;
padding-bottom:10px;
}
p{
margin:5px;
}
</style>
</head>
<body>
<p id="target">Cording everybody!</p>
<p> data : <input type="text" id="datasource" value="JavaScript" /></p>
<p> start :<input type="text" id="start" value="5" /></p>
<p> end : <input type="text" id="end" value="5" /></p>
<p><input type="button" value="appendData(data)" onclick="callAppendData()" />
<input type="button" value="deleteData(start,end)" onclick="callDeleteData()" />
<input type="button" value="insertData(start,data)" onclick="callInsertData()" />
<input type="button" value="replaceData(start,end,data)" onclick="callReplaceData()" />
<input type="button" value="substringData(start,end)" onclick="callSubstringData()" /></p>
<script>
var target = document.getElementById('target').firstChild;
var data = document.getElementById('datasource');
var start = document.getElementById('start');
var end = document.getElementById('end');
function callAppendData(){
target.appendData(data.value);
}
function callDeleteData(){
target.deleteData(start.value, end.value);
}
function callInsertData(){
target.insertData(start.value, data.value);
}
function callReplaceData(){
target.replaceData(start.value, end.value, data.value);
}
function callSubstringData(){
alert(target.substringData(start.value, end.value));
}
</script>
</body>
</html>





2. [ Document(문서)의 Element 위치 알아내기 ]

var positionInfo = Element.getBoundingClientRect();
-> getBoundingClientRect()는 width, height, top, left, right, bottom 프러퍼티를 갖는 객체이다.
- width : element의 가로 길이
- height : 세로길이
- top : viewport(아래에서 설명) 맨 위에서부터 element까지 y축 길이
- left : viewport 맨 좌측에서부터 element까지 x축 길이
- right : viewport 맨 좌측에서 element 맨 오른쪽까지 길이
- bottom : viewport 맨 위에서 element 맨 아래까지 길이

1) -> 하지만, getBoundingClientRect()는 구버전 브라우저에서는 제공하지 않는 경우도 있다. 따라서,
element의 좌표를 구할 때 element.offsetLeft, element.offsetTop을 사용하면 된다. == element.getBoundingClientRect().left|top

- 테두리를 제외한 width와 height 값 구하기
- element.clientWidth
- element.clientHeight


2) -> 때떄로, 어떤 Element들은 해당 Element를 감싸고 있는 부모 Element가 position static인 경우 부모로 부터의 위치를 기준으로
자신의 offsetLeft, offsetTop값을 반환하게 된다.
따라서, 문서에서의 정확한 위치를 구하기 위해서는 다음과 같은 코드를 사용할 수 있다.
( 해당 Element를 포함하고 있는 부모 Element를 추적하면서 위치값을 더해감)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script type="text/javascript">
    function getX(element) {
      var x = 0; // x좌표
      while(element){
        x += element.offsetLeft;
        element = element.offsetParent; // 해당 element를 감싸고있는 부모 element
      } // 부모 element를 타고 올라가면서 x좌표값을 더해간다.
    }
 
    function getY(element) {
      var y = 0;
      while(element) {
        y += element.offsetTop;
        element = element.offsetParent;
      }
    }
  </script>



3. [ viewport란? 스크롤을 고려한 문서내의 Element의 위치 ]

- 1) Viewport(뷰포트)

: 문서 전체의 크기가 있을 때 예를들어 우리가 브라우저를 줄이게 될 경우 전체 Document가 다 보이지 않고
  창 크기에 맞춰 일부분의 문서만 보일 것이다.
  이때, 보이는 영역이 ViewPort이다.

--> 우리가 아까 위에서 element.offsetLeft, element.offsetTop 등이 viewport에서부터의 거리를 나타내고 있는 것이다.

따라서, 스크롤이 개입되게 되면, 해당 위치는 문서 전체를 기준으로했을 때 정확하지 않게 될 수 있다.

   2) 스크롤의 위치는 어떻게 구할까?

-> window.pageYoffset
: y축 스크롤을 움직인 거리(문서가 가려진 y축 길이)
-> window.pageXoffset
: x축 스크롤을 움직인 거리(문서가 가려진 x축 길이)

    3) viewport에서부터의 거리와 스크롤과의 관계

-> 스크롤을 내릴 수록 pageYoffset값은 커질 것이다. 그러면 offsetTop값을 기준으로 보면 어떻게 될까?

    스크롤이 내려간만큼 그 길이는 짧아지게 된다.

예를들어, A라는 Element의 offsetTop값이 맨 처음 200이고 pageYoffset이 0이었을 때
스크롤을 40px만큼 내려 pageYoffset이 40이 되면

offsetTop값은 200 - 40 인 160이 되게 된다.

전체문서에서 보이는 viewport를 기준으로 하기 때문이다.

따라서, 전체 문서에서의 위치를 구하려면 어떻게 해야할까?

--> element.offsetTop(뷰포트좌표) + window.pageYoffset(스크롤된 정도)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<style>
body{
padding:0;
margin:0;
}
div{
border:50px solid #1065e6;
padding:50px;
margin:50px;
}
#target{
width:100px;
height:2000px;
}
</style>
<div>
<div id="target">
Coding
</div>
</div>
<script>
var t = document.getElementById('target');
setInterval(function(){
console.log('getBoundingClientRect : ', t.getBoundingClientRect().top, 'pageYOffset:', window.pageYOffset);
}, 1000)
</script>




4. [ 스크롤 제어 ]

: 스크롤을 특정 위치로 이동시키는 방법

-> window.scrollTop(x, y); // x축, y축

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style>
body{
padding:0;
margin:0;
}
div{
border:50px solid #1065e6;
padding:50px;
margin:50px;
}
#target{
width:100px;
height:2000px;
}
</style>
<input type="button" id="scrollBtn" value="scroll(0, 1000)" />
<script>
document.getElementById('scrollBtn').addEventListener('click', function(){
window.scrollTo(0, 1000);
})
</script>
<div>
<div id="target">
Coding
</div>
</div>



5. [ Viewport의 크기와 사용자 모니터 크기 구하기 ]

- Viewport 크기

: window.innerWidth
  window.innerHeight

- 사용자 모니터 크기

: screen.width
: screen.height

[   Node 객체에 대하여(NODE 객체와 NODE객체 컨트롤하기)   ]



-> 자바스크립트의 모든 DOM ELEMENT들은 최상위로 NODE를 상속하고 있기 때문에 NODE가 가지고 있는 속성을 사용할 수 있다.


Node 객체는 Node 간의 관계 정보를 담고 있는 일련의 API를 가지고 있다. 다음은 관계와 관련된 프로퍼티들이다.


[ 1. Node의 자식 및 형제 Node에 접근하는 프러퍼티 ]

  • Node.childNodes
        자식노드들을 유사배열에 담아서 리턴한다.
  • Node.firstChild
        첫번째 자식노드
  • Node.lastChild
        마지막 자식노드
  • Node.nextSibling
        다음 형제 노드
  • Node.previousSibling
        이전 형제 노드

-> 이렇게 노드에 접근할 때 중요한 점은 줄바꿈 텍스트 또한 NODE를 상속하기 때문에 자식으로 가져올 때 주의해야 한다는 점이다. 아래의 크롬브라우저의 테스트 창을 보면서
    이해하기 바란다

   EX) Crome Browser 개발자도구(F12) console창에서 테스트하는 예
<body id="start">
<ul>
<li><a href="./532">html</a></li>
<li><a href="./533">css</a></li>
<li><a href="./534">JavaScript</a>
<ul>
<li><a href="./535">JavaScript Core</a></li>
<li><a href="./536">DOM</a></li>
<li><a href="./537">BOM</a></li>
</ul>
</li>
</ul>
</body>





[    2. Node의 타입을 알 수 있는 nodeType속성과 Node 이름을 알 수 이는 nodeName 속성    ]


노드 작업을 하게 되면 현재 선택된 노드가 어떤 타입인지를 판단해야 하는 경우가 있다. 이런 경우에 사용할 수 있는 API가 nodeType, nodeName이다. 


  • Node.nodeType
        node의 타입을 의미한다.  -> 타입값은 숫자로 나오게 된다. 주로 1(element), 3(TextNode), 9(document node) 를 주로 사용하게 된다.
  • Node.nodeName
        node의 이름 (태그명을 의미한다.)


  [ nodeType의 종류 ]


EX)


-> nodeType의 경우 1,2,3 숫자를 기억하기 어려울 수 있음으로 상수로 이를 대체하여 사용할 수도 있다.

EX)



[    노드 추가관련 프러퍼티    ]

노드의 추가와 관련된 API들은 아래와 같다.

노드를 추가하기 위해서는 추가할 엘리먼트를 생성해야 하는데 이것은 document 객체의 기능이다. 아래 API는 노드를 생성하는 API이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
   
    <ul id="target">
      <li>HTML</li>
      <li>CSS</li>
    </ul>
    <input type="button" onclick="callAppendChild();" value="appendChild()" />
    <input type="button" onclick="callInsertBefore();" value="insertBefore()" />
 
    <script type="text/javascript">
      function callAppendChild() {
        var target = document.getElementById("target");
 
        // id="target"인 ul에 삽입할 li태그를 생성한다.
        var new_li = document.createElement("li"); // <li></li>
        // 새로 생성한 li태그에 넣을 텍스트 엘리먼트를 생성한다.
        var new_txt = document.createTextNode("insert after");
        // li에 텍스트 노드를 붙인다.
        new_li.appendChild(new_txt); // <li>insert after</li>
 
        // li를 target의 마지막 자식 <li>CSS</li> 뒤에 붙인다.
        target.appendChild(new_li);
      }
 
      function callInsertBefore() {
        var target = document.getElementById("target");
 
        // id="target"인 ul에 삽입할 li태그를 생성한다.
        var new_li = document.createElement("li"); // <li></li>
        // 새로 생성한 li태그에 넣을 텍스트 엘리먼트를 생성한다.
        var new_txt = document.createTextNode("insert before");
        // li에 텍스트 노드를 붙인다.
        new_li.appendChild(new_txt); // <li>insert after</li>
 
        // li를 target의 마지막 자식 <li>CSS</li> 뒤에 붙인다.
        target.insertBefore(new_li, target.firstChild.nextSibling); // insertBefore(붙일node, 어떤대상 앞에 붙일지)
        // 여기서 target.firstChid.nextSibling은 <li>HTML</li>를 의미하게 된다. 즉 그 앞에 붙게됨
      }
    </script>
  


[    노드 제거    ]

노드 제거를 위해서는 아래 API를 사용한다. 이 때 메소드는 삭제 대상의 부모 노드 객체의 것을 실행해야 한다는 점에 유의하자.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
   
    <ul>
      <li>HTML</li>
      <li>CSS</li>
    <li id="target">JavaScript</li>
    </ul>
    <input type="button" onclick="callRemoveChild();" value="removeChild()" />
    <script>
        function callRemoveChild(){
            var target = document.getElementById('target');
            // target의 부모임으로 body태그를 가리키게 되고 body태그 자식인 target element를 지우게 된다.
            target.parentNode.removeChild(target);
        }
    </script>
  



[    노드 바꾸기    ]

노드 바꾸기에는 아래 API가 사용된다.



<ul>
<li>HTML</li>
<li>CSS</li>
<li id="target">JavaScript</li>
</ul>
<input type="button" onclick="callReplaceChild();" value="replaceChild()" />
<script>
function callReplaceChild(){
var a = document.createElement('a');
a.setAttribute('href', 'http://opentutorials.org/module/904/6701');
a.appendChild(document.createTextNode('Web browser JavaScript'));
var target = document.getElementById('target');
target.replaceChild(a,target.firstChild); // 새로 만든 a태그를 target의 첫번째 자식 엘리먼트와 교체한다.(즉 텍스트 JavaScript를 대체)
}
</script>



문자열로 노드 제어



위의 예들은 Node 객체를 생성한 뒤 제어했지만, 문자열로 붙이고 지우고 등을 할 수 있다. 아래는 그와 관련된 프러퍼티와 메서드이다.

1. innerHTML

innerHTML는 문자열로 자식 노드를 만들 수 있는 기능을 제공한다. 또한 자식 노드의 값을 읽어올 수도 있다. 


2. outerHTML

outerHTML은 선택한 엘리먼트를 포함해서 문자열로 가지고 오거나, 자신을 포함해서 문자열로 노드를 대체할 수 있다.


3. insertAdjacentHTML()

좀 더 정교하게 문자열을 이용해서 노드를 변경하고 싶을 때 사용한다.


EX) innerHTML

<ul id="target">
<li>HTML</li>
<li>CSS</li>
</ul>
<input type="button" onclick="get();" value="get" />
<input type="button" onclick="set();" value="set" />
<script>
function get(){
var target = document.getElementById('target');
alert(target.innerHTML); // target 내부의 HTML과 CSS li를 가지고 오게 된다.(문자열로)
}
function set(){
var target = document.getElementById('target');
target.innerHTML = "<li>JavaScript Core</li><li>BOM</li><li>DOM</li>";
}
</script>


EX) outerHTML

<ul id="target">
<li>HTML</li>
<li>CSS</li>
</ul>
<input type="button" onclick="get();" value="get" />
<input type="button" onclick="set();" value="set" />
<script>
function get(){
var target = document.getElementById('target');
alert(target.outerHTML); // target 전체를 가지고 오게 된다.(문자열로)
}
function set(){
var target = document.getElementById('target');
target.outerHTML = "<ol><li>JavaScript Core</li><li>BOM</li><li>DOM</li></ol>";
// ul태그 전체가 통째로 ol로 대체되게 된다.
}
</script>


EX) insertAdjacentHTML(arg1, arg2)

<ul id="target">
<li>CSS</li>
</ul>
<input type="button" onclick="beforebegin();" value="beforebegin" />
<input type="button" onclick="afterbegin();" value="afterbegin" />
<input type="button" onclick="beforeend();" value="beforeend" />
<input type="button" onclick="afterend();" value="afterend" />
<script>
function beforebegin(){
var target = document.getElementById('target');
target.insertAdjacentHTML('beforebegin','<h1>Client Side</h1>'); // 맨 첫번째 자식 앞에 삽입
}
function afterbegin(){
var target = document.getElementById('target');
target.insertAdjacentHTML('afterbegin','<li>HTML</li>'); // 첫번째 자식 뒤에 삽입
}
function beforeend(){
var target = document.getElementById('target');
target.insertAdjacentHTML('beforeend','<li>JavaScript</li>'); // 끝 자식 전에 삽입
}
function afterend(){
var target = document.getElementById('target');
target.insertAdjacentHTML('afterend','<h1>Server Side</h1>'); // 끝 자식 뒤에 삽입
}
</script>


[    이벤트(EVENT)    ]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
   
    <!--
      [ 이벤트 등록 방식 ]
      1. inline 방식 :
            이벤트를 이벤트 대상의 태그 속성으로 지정하는 것.
         - 단점)
              : 정적인 html과 동적(제어역할)인 javascript를 분리시킬 수 없다.
         - 장점)
              : 쉽고, 가독성이 좋다.
    -->
    <!-- 자기자신을 참조하는 불편한 방법 -->
    <input type="button" id="target" onclick="alert('Hello, ' + document.getElementById('target').value);"
      value="button" />
    <!--this를 통해서 간편하게 참조할 수 있다. -->
    <input type="button" onclick="alert('Hello, ' + this.value);" value="button2" />
 
    <!--
      2. 프로퍼티 리스너를 통한 이벤트 등록 방식
        : 이벤트 대상에 해당하는 객체의 프로퍼티로 이벤트를 등록하는 방식이다.
        장점)
          : inline방식에 비해 HTML과 Javascript를 분리할 수 있어서 선호되지만,
            addEventListener 방식을 더욱 추천한다.!
    -->
    <input type="button" id="target2" value="button" />
    <script type="text/javascript">
      var t = document.getElementById("target2");
      t.onclick = function(event) {
        // event객체를 통해서 현재 발생한 이벤트에 대한
        // 다양한 정보를 얻을 수 있다.
        // event의 target속성을 통해 클릭한 객체를 가져올 수 있다.
        alert('Hello, ' + event.target.value);
        // 하지만, IE8 이하 버전에서는 인자로 event객체를 받지 않아 동작하지 않는다.
        console.dir(event); // .dir : 객체의 프러퍼티를 보기 쉽게 보여준다.
      }
      // 이를 해결하기 위해서는 다음과 같이 하면 된다.
      t.onclick = function(event) {
        // IE8이하에서는 첫번째 매개변수로 event를 받지 않아서 window에 있는 event객체
        // 를 통해 접근해야한다. 따라서
 
        // event객체가 존재하면 쓰고, 없으면 window.event를 사용한다.
        var event = event || window.event;
        // 이때, window.event에서는 target속성이 없고, srcElement속성을 쓴다.
          // event.target 속성이 존재하면 쓰고, 없으면 event.srcElement속성을 쓴다.
        var target = event.target || event.srcElement;
        alert('Hello, ' + event.target.value);
      }
    </script>
 
 
    <input type="button" id="target4" value="button" />
    <input type="button" id="target5" value="button" />
    <input type="button" id="target6" value="button" />
 
    <script type="text/javascript">
      // 3. addEventListener를 통해 이벤트를 등록하는 방법
      <!--
        위의 방식과 달리, 이 방식은 여러개의 이벤트 핸들러를 등록할 수 있다.
        프러퍼티 방식에 onclick에 동일한 메서드를 두번 등록하면 나중에 등록한
        메서드만 적용되지만, addEventListener의 경우 동일한 이벤트를 두개 등록할 수 있고
        순차적으로 수행되게 된다.
      -->
      <input type="button" id="target3" value="button3" />
      var t2 = document.getElementById('target3');
      t2.addEventListener("click",function(event){
        alert(1);
      });
      t2.addEventListener("click",function(event){
        alert(2);
      })
      // 이때, 버튼 클릭시 1과 2 순차적으로 경고창이 뜨게 된다.
      // t.onclick=function~~를 두번 등록했다면 이후에 등록된 것만 적용될 것이다!
 
 
      // 하지만, addEventListener의 경우도 IE8이하의 버전에서는 동작하지 않는다.
      // -> IE8이하에서는 attachEvent를 사용해야한다.
      // 다음은 크로스 브라우징을 고려한 코드이다.
 
      var t3 = document.getElementById('target4');
      if ( t3.addEventListener ) { // IE8 이상 버전은
        // addEventListener가 존재하지 않으면 undefined가 뜰 것이고 js에서 undefined는
        // false를 의미한다.
        t3.addEventListener("click", function(event) {
          alert(event.target.value);
        };
      }else if ( t3.attachEvent ) { // IE8 이하 버전은
        t3.attachEvent("onclick", function(event) { // attachEvent는 click이 아니라 on을 포함해 써줘야 한다.
          alert(window.event.srcElement.value); // IE8이하는 매개변수 첫번째에 event객체를 받지 않기 때문
        }
      }
 
      // EX)
      var t4 = document.getElementById('target4');
      var t5 = document.getElementById('target5');
      function btn_listener(event) {
        switch ( event.target.id ) {
          case 'target4' :
            alert(4);
            break;
          case 'target5' :
            alert(5);
            break;
        }
      }
      t4.addEventListener("click",btn_listener);
      t5.addEventListener("click",btn_listener);
 
    </script>
  


[ 이벤트(EVENT)의 전파 및 전파를 막는 방법 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<head>
    <style>
        html{border:5px solid red;padding:30px;}
        body{border:5px solid green;padding:30px;}
        fieldset{border:5px solid blue;padding:30px;}
        input{border:5px solid black;padding:30px;}
    </style>
</head>
 
    <fieldset>
        <legend>event propagation</legend>
        <input type="button" id="target" value="target">
    </fieldset>
    <script>
    function handler(event){
        var phases = ['capturing', 'target', 'bubbling']
        // event 객체의 target속성을 통해 접근하는 경우 가장 구체적으로 클릭된 element 객체를 가지고 오게된다.
        // 이때는 전파와 상관없이 클릭된 객체를 가리키게 된다.
        // 하지만, this키워드의 경우 event가 발생된 영역에 있는 element를 가리키게 되는데
        // 지금의 경우는 button을 클릭해도 그 버튼은 fieldset 이벤트 영역에 있고 이는 또 body, html 영역에 있기 때문에
        // 해당 이벤트가 발생하면서 속해 있는 영역 element를 가리키게 된다.(전파된 영역의 객체)
        // 따라서, 캡처링이기 때문에 html->body->field->button순으로 나오게 된다.
        // 이에 반해, event.target.nodeName의 경우는 button을 클릭시 button, fieldset을 클릭시 fieldset이 나오게 된다.
        console.log(event.target.nodeName, this.nodeName, phases[event.eventPhase-1]);
    }
    document.getElementById('target').addEventListener('click', handler, true);
    document.querySelector('fieldset').addEventListener('click', handler, true);
    document.querySelector('body').addEventListener('click', handler, true);
    document.querySelector('html').addEventListener('click', handler, true);
    </script>
    <script type="text/javascript">
      /*
        [ 이벤트의 전파 ]
        : 위의 코드를 보면 input 태그로 만든 button은 fieldset에 속해 있고, filedset은 body태그에 속해있다.
          또, body태그는 html태그에 속해있는데
          button, fieldset, body, html 모두에 이벤트 리스너를 등록해 놓고
          제일 안에 있는 button을 클릭하게되면, button이벤트만 동작하는 것이 아니라 이벤트가 전파되어
          fieldset, body, html 모두 이벤트가 발생하게 된다. 이를 이벤트의 전파라고 하는데
 
          [ 이벤트 전파의 종류 ] 에는 2가지가 있다.
          button을 클릭시
          1. Capturing(캡처링) : button -> fieldset -> body -> html 순으로 이벤트가 수행되는 전파
          2. Bubbling(버블링) : html -> body -> fieldset -> button 순으로 이벤트가 수행되는 전파
          -> 하지만, 캡처링은 IE의 낮은 버전에서는 지원하지 않는 경우가 많아 선호되지 않고
          주로 버블링이 선호된다.
 
          이때, element.addEventListener(첫번째,두번째,세번째) 에서 세번째 인자는 캡처링 유무를 나타내게 되는데
          캡처링 방식으로 할 경우 true를 기술해주고, 버블링 방식으로할 때는 생략하거나 false를 입력해 주면 된다.
          -> element.addEventListener("click",function(){},false)
      */
 
      /*
        [ 이벤트 전파의 방지 ]
        : 이벤트 전파를 막는 메서드는 event객체의 stopPropagation()메서드이다.
        예를들어, 전파되던 이벤트를 body에서 더이상 전파되지 않도록 한다면(버블링일 경우)
        (body element).addEventListener("click",function(event){event.stopPropagation()},false) 를 해주면 된다.
      */
    </script>



[ 태그의 기본 이벤트를 막는 방법 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
   
    /*
      [ 기본 이벤트를 막는 방법 ]
      : 예를들어 a태그는 href에 지정된 주소로 이동하는게 기본이벤트이고, form태그의 submit 버튼은 전송하는 역할처럼
        각 태그는 기본적인 이벤트를 가진 것들이 있다.
        이러한 기본 이벤트를 막는 방법에 몇가지가 있는데
 
        1. inline 방식의 경우
        2. 프로퍼티 방식의 경우
          :
        3. addEventListener 방식의 경우
          : event객체의 preventDefault() 메서드를 수행하면 된다. 단!) IE9버전 이하에서는 동작하지 않음으로
            -> event.returnValue = false;로 해주면 된다.
    */
 
    // 1. Inline 방식
    <p>
      <label>prevent event on</label><input id="prevent" type="checkbox" name="eventprevent" value="on" />
    </p>
    <p>
      // 위의 체크박스가 체크된 경우 return false하게 된다.
      <a href="http://opentutorials.org" onclick="if(document.getElementById('prevent').checked) return false;">opentutorials</a>
    </p>
    <p>
      <form action="http://opentutorials.org" onsubmit="if(document.getElementById('prevent').checked) return false;">
          <input type="submit" />
      </form>
    </p>
 
    <a id="googleA" href="http://google.com" onclick="return test();">구글로 이동</a>
    <script type="text/javascript">
      var test = function (event){
        return false; // 기본 동작을 막기 위함
      }
    </script>
 
 
 
    // 2. 프로퍼티 방식으로 기본 동작을 취소하는 방법
    <script>
      document.querySelector('a').onclick = function(event){
          if(document.getElementById('prevent').checked) // 체크가 되어 있는 경우에
              return false; // return false 하면 a태그의 기본 동작을 막을 수 있다.
      };
 
      document.querySelector('form').onclick = function(event){
          if(document.getElementById('prevent').checked)
              return false;
      };
 
    </script>
 
 
 
    // 3. addEventListener의 경우 -> event.preventDefault() or event.returnValue = false;
    <script type="text/javascript">
      var test2 = function(event){
        if ( document.getElementById('prevent').checked)
          event.preventDefault(); // 기본 동작을 막는다.
      }
      document.querySelector('a').addEventListener("click",test2,false);
      document.querySelector('form').addEventListener("click",test2,false);
    </script>
  



[ FORM 태그의 대표 이벤트 종류 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
   
    <pre>
      [ FORM 태그 관련 대표 이벤트 ]
      1. submit
        : form에서 submit 버튼을 클릭해 form내부의 데이터가 action으로 지정한 곳으로 전달될 때 발생.
      2. click
        : 클릭했을 때 발생되는 이벤트
      3. focus
        : ELEMENT가 포커스를 얻었을 때(입력가능한 상태) 가 되었을 때 발생하는 이벤트
      4. blur
        : ELEMENT가 포커스를 잃었을 때 발생하는 이벤트
    </pre>
    <!-- EX -->
    <form id="formID" action="http://www.google.com" method="post">
      이름 : <input id="nameID" type="text" value="" />
      <input type="submit" value="제출" />
    </form>
    <script type="text/javascript">
      var areaElement = document.getElementById("formID");
      // form태그에 submit 이벤트를 건다.
      areaElement.addEventListener("submit",function(event){
 
        if ( event.target.nameID.value.length < 1 ) {
          // 클릭된 폼태그의 nameID를 가진 엘리먼트의 입력된 값이 한글자보다 작은 경우
          event.preventDefault(); // 기본이벤트를 방지함 -> 즉, submit발생을 막음
          // addEventListener의 경우 기본동작을 막기 위해 return false대신 preventDefault()를 사용한다.
          alert("이름은 반드시 입력되어야 합니다.");
        }
 
      });
    </script>
 
    <script type="text/javascript">
      // focus를 얻었을 경우 이벤트를 발생
      var nameElement = document.getElementById("nameID");
      nameElement.addEventListener("focus",function(event){
        alert(event.target.id + "가 포커스를 얻었습니다.");
      });
      // focus를 잃었을 경우 이벤트를 발생
      nameElement.addEventListener("blur",function(event){
        alert(event.target.id + "가 포커스를 잃었습니다.");
      });
    </script>
  



[ 문서의 태그의 로딩과 관련된 load와 unload 이벤트 ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
    <script type="text/javascript">
      function unloadF(){
        alert("해제");
      }
    </script>
  </head>
   
    <pre>
      [ 문서의 로딩과 관련된 load 이벤트와 unload 이벤트 ]
      1. load
        : html태그가 전부 로딩되어 접근할 수 있는 상태가 되었을 때 발생하는 이벤트이다.
      2. unload
        : html 태그가 메모리에서 내려가기 직전에 호출되는 이벤트이다.
        -> 현재 창이 닫히기 직전에 특정 작업을 처리 후 닫고자 할 때 사용하면 좋다.
 
      load 이벤트가 중요한 이유는, 특정 ELEMENT에 접근하는 스크립트를 load 이벤트 없이
      선언할 때에는 접근하려는 ELEMENT보다 아래쪽에 위치시켜야 한다는 것이다.
 
      why? 아직 메모리에 올라오지도 않은 상태에서 스크립트가 접근하려하면 존재하지 않는
      ELEMENT를 참조하게 되니까 오류가 발생하게 된다.
 
      따라서, 바디태그 맨 밑쪽에 위치하는 것이 좋지만 그렇게 하지 않고도
      load 이벤트 발생시(태그가 다 로딩되면) 해당 스크립트가 동작하도록 해줘도 된다.
 
      또한, load와 unload 이벤트는 inline방식으로는 body태그에서 수행해주면 된다.
    </pre>
    <script type="text/javascript">
      // 해당 스크립트는 areaID div 보다 위에 위치해 있음으로 본래 오류가 나야하지만
      // 나지 않도록 load함수로 수행토록 하겠다.
 
      // 프러퍼티 이벤트 방식
      window.onload = function(){
        document.getElementById("areaID").innerHTML = "데이터 넣기";
      }
      // 이때, onload 프러퍼티로 이벤트를 지정할시 단점은 무엇일까?
      // -> 만약 본인이 onload 이벤트를 두번 지정할 경우 더 아래에서 지정한
      // onload이벤트로 덮어버려 이전에 선언한 onload는 동작하지 않게 된다.
      // 따라서, onload 이벤트 지정시 addEventListener를 통해 등록해주도록 하자.
      window.addEventListener("load",function(){
        document.getElementById("areaID").style.border = "1px solid red";
      });
    </script>
    <div id="areaID"></div>
 
 
  


[ 그 외 알아두면 좋은 이벤트 ]

- contextmenu event : 마우스 우클릭시 발생

-> 마우스 우클릭 방지 이벤트(요소 검사(F12)를 방지하기 위해 사용 가능)

- shift, ctrl 키와 같이 클릭했는지 유무를 알 수 있는 event 프러퍼티

event.shiftKey, event.ctrlKey

- 클릭한 곳의 마우스 좌표를 알 수 있는 event.clientX, event.clientY

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<!DOCTYPE html>
 
     
        <div id="target" style="border:1px solid red; width:100px;height:100px;"></div>
 
        <script type="text/javascript">
          /*
            1. [ contextmenu 이벤트 : 마우스 우클릭 관련 이벤트 ]
            : 해당 속성을 이용해 요소 검사를 못하도록 마우스 우클릭을 막을 수 있다.
          */
          var targetObj = document.getElementById("target");
          targetObj.addEventListener("contextmenu",function(event){
            // event.type -> 발생한 이벤트의 종류를 알 수 있다.
            if ( event.type == "contextmenu" ){ // 이벤트가 contextmenu이면
              event.preventDefault(); // 기본동작을 막음(마우스 우클릭 방지)
              alert("우클릭 불가능");
            }
          });
        </script>
 
        <!--
          2. [ change 이벤트 ]
            : select 박스, input, textarea 등의 값이 바낄때마다 호출되는 메서드
        -->
        <select id="sel">
          <option value="JAVA">JAVA</option>
          <option value="CSS">CSS</option>
        </select>
        <script type="text/javascript">
          document.getElementById("sel").addEventListener("change",function(event){
            alert("변경된 값 : " + event.target.value);
          });
        </script>
 
 
        <!--
          3. [ 클릭 이벤트시 보조키를 같이 누른지 여부를 체크하는 방법 ]
 
            1) shift키 : event.shiftKey
            2) ctrl키 : event.ctrlKey
        -->
        <div id="target2" style="border:1px solid blue;width:100px;height:100px;"></div>
        <script type="text/javascript">
          document.getElementById("target2").addEventListener("click",function(event){
            if ( event.shiftKey ) { // click시 shift키를 같이 누른 경우
              alert("click + shift key");
            }else if ( event.ctrlKey ) {
              alert("click + ctrl key");
            }else {
              alert("just click");
            }
          });
        </script>
 
        <!--
          4. [ 클릭이벤트가 발생한 마우스 좌표를 구하는 clientX, clientY ]
        -->
        <div id="target3" style="border:1px solid green;width:100px;height:100px;"></div>
        <script type="text/javascript">
          document.getElementById("target3").addEventListener("click",function(event){
            alert("클릭 좌표 : ( " + event.clientX + " , " + event.clientY + " )");
          });
        </script>
    


[    5판 7장 객체(Object)와 배열(Array)    ]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
    <script type="text/javascript">
      // [ 객체(object) ]
      // 1. 빈 객체 생성
      var book = {};
      // 2. 선언과 동시에 객체 생성
      var book2 = {
        title : 'book2의 제목',
        page : 12
      };
      // 3. 세번째 객체 생성 방법
      var book3 = new Object();
 
      // [ 동적으로 객체의 속성(프로퍼티)를 선언하기 ]
      book.title = 'book1의 제목';
      book.page = 20;
      // 동적으로 객체의 프로퍼티에 객체를 할당하기
      book2.chapter1 = {
        title : 'chapter1의 제목',
        page : 30
      };
      book.chapter1 = new Object();
      book.chapter1.title = 'book chapter1의 제목';
      book.chapter1.page = 102;
      // 이처럼 언제든지 동적으로 새로운 속성(프로퍼티)를 할당할 수 있다.
      alert("book chapter1의 제목과 페이지 : " + book.chapter1.title + " : " + book.chapter1.page);
      alert(book2["chapter1"]["title"]);
 
      // [ 객체에 특정 속성(프로퍼티)가 존재하는지 확인하기 ]
        // "프로퍼티명" in 객체명
      if ( "title" in book ) {
        alert("book객체에 title 속성이 존재합니다.");
      }
 
      // [ 객체가 어떤 객체인지 확인하기 ]
        // instanceof
      if ( book instanceof Object ) {
        alert("book은 Object의 객체입니다.")
      }
 
      // [ 객체의 속성(프로퍼티) 삭제하기 ]
        // delete 객체명.프로퍼티명
      delete book.title; // delete는 아예 속성을 제거하는 것으로 빈 문자열이 들어가는게 아니라
      // 아예 사라지게 됨 따라서 아래에서 book.title을 찍어보면 undefined가 나오는 것을 알 수 있다.
 
      // [ 배열에 접근하는 두가지 방법 ]
      // 1. 객체명.속성명
      // 2. 객체명["속성명"]
          // : 두번째 방법은 []안에 문자열이 들어오게 된다. 첫번째는 문자열이 아닌 키워드!
          // 이게 무슨 의미가 있을까?
          //  만약, 사용자나 개발자에 의해서 객체의 속성명이 정해지게 된다면 객체명.속성명으로는
          //  조회를 할 수 없을 것이다. 왜? 아직 해당 속성명이 무엇이 될지 알 수 없으니까
          //  하지만, []안에 문자열로 접근하는 이 방식은 그 것이 가능하다.
      // EX)
      var inputVar = "newProperty"; // 사용자가 속성명으로 하고 싶은 명칭을 입력 받음
      book[inputVar] = "newProperty의 값"; // book.inputVar은 불가능하지만, 이건 가능하다.
      alert(book[inputVar]);
 
      // 이때!!!, 어떤 변수명이 넘어올지 알 수 없을 때 객체 내에 있는 속성명을 조회할 수 있는 방법은??
        // (for 변수 in 객체명) 을 사용하면 된다.
        // 그러면 객체의 속성(프로퍼티)명이 변수에 하나씩 담기게 된다.
      //EX)
      for (propertyVal in book) {
        alert(propertyVal + " 속성의 값은 : " + book[propertyVal]);
      }
 
      // 값이 null이거나 undefined가 아닌 경우를 체크하는 코드
      if ( !book.title ) {
        alert("book.title은 null도 undefined도 아닙니다.");
      }
 
      //////////////////////////////////////////////////////////////////////////////////////////
 
      // [ 배열(Array) ]
      // JS의 배열은 자바와 달리 다양한 타입을 한 배열에 담을 수 있다.
 
      // 1. 배열의 선언 방식
        // 1)
          var arr1 = [1,2,3,4];
        // 2)
          var arr2 = new Array(5)[1,2,3,4,5];
      // 2. 다양한 타입을 담을 수 있는 배열
        var arr3 = [1,true,false,"string",{title:'제목',page:12}]; // 객체조차 담을 수 있다.(배열안에 배열도 가능)
 
      // 3. 배열에서 제공하는 다양한 메서드 및 리터럴
        // 1) length : 배열의 element 갯수를 반환하는 리터럴이다.
            alert("arr3배열의 element개수는 : " + arr3.length);
 
        // 2) join() : 배열의 각 element를 합쳐서 한 문자열로 반환한다.
            // join() 은 기본형으로 [1,2,3,4].join()시 => "1,2,3,4"를 반환하고
            // join("-")은 [1,2,3,4].join('-') => "1-2-3-4";를 반환한다.
            alert([1,2,3,4].join('-'));
 
        // 3) split('') : join과 반대로 특정 단위를 기준으로 배열을 반환한다.
            var arrString = "1,2,3,4";
            var arrSplit = arrString.split(",");
            alert(arrSplit.toString()); // 배열의 toString()은 각 배열원소를 ,로 묶어 문자열로 반환한다.
 
        // 4) concat() : 현재 배열에 특정 element를 추가한다.
            var arr4 = [1,2,3,4];
            arr4 = arr4.concat(5,6,7);
            alert(arr4.toString());
 
        // 5) slice(startIndex, lastIndex+1) : 시작인덱스 ~ 끝인덱스 하나 전까지 배열을 잘라낸다.
            var arr5 = [1,2,3,4,5,6];
            arr5 = arr5.slice(2,4); // 3,4
            alert(arr5.toString());
 
        // 6) splice(startIndex, lastIndex+1, 추가할 값들...)
            // : 시작인덱스 ~ 끝인덱스 까지는 배열의 값을 잘라내고 해당 배열에는 잘래내진 값들을 뺀 값들이 들어있다.
            // 만약, 3번째 인자를 입력시 startIndex부터 3번째 인덱스에 입력한 값들이 추가되게 된다.
            // EX)
            var arr6 = [1,2,3,4,5,6,7];
            var arr7 = arr6.splice(1,4); // arr7에는 2,3,4가 들어가게 되고, arr6에는 1,5,6,7이 남아 있게 된다.
            alert("arr6 : " + arr6.toString());
            alert("arr7 : " + arr7.toString());
 
            var arr8 = [1,2,3,4,5,6,7];
            arr8.splice(2,0,true,false,"string"); //2번 인덱스부터 0개 빼지 안하겠다는 거고 2번인덱스부터 true, false, String을 추가한다.
            alert("arr8 : " + arr8.toString()); // 1,2,true,false,String,3,4,5,6,7
 
        // 7) sort() : 배열의 정렬
            // : default는 문자열 오름차순이다. 따라서, 숫자를 정렬하고 싶을 땐 익명 함수를 이용해야한다.
            // EX)
              // 1) default
                var arr9 = [3,4,7,6,9,2,1];
                alert("sort : " + arr9.sort().toString());
              // 2) 숫자 기준
                var arr10 = [3,4,12,5,22];
                arr10 = arr10.sort(function(a,b){
                  return (a-b);
                });
                alert("sort : " + arr10.toString());
 
          // 8) push()와 pop()
              // push() : 마지막 배열요소에 새 element 값을 추가한다.
              // pop() : 마지막 배열요소를 꺼낸다.
            var arr11 = [1,2,3,4];
            arr11.push("true");
            alert("push : " + arr11.toString());
            var arr12 = [1,2,3,4];
            arr12 = arr12.pop();
            alert("pop : " + arr12);
    </script>
  </head>
   
 
  


+ Recent posts