[  함수(Function) ]

  -종류)

    1. 선언적 함수 : 함수에 이름이 있는 함수로 호이스팅의 대상이 된다.(호이스팅은 별도로 정리)

      function circle(radius){

        ~~

        return something;

      }

    2. 익명 함수 : 함수에 이름이 없어 주로 변수에 대입해서 사용하는 함수(호이스팅의 대상이 되지 않음)

                    -> 따라서 순차적으로 수행되기 때문에 요즘은 익명함수로 선언하는 것이 추천됨.

      var anonymousFunc = function(raidus){

        ~~

        return something;

      }

    3. 람다 함수 : 일회성으로 사용하기 위한 목적으로 사용되는 함수

      (function(radius){

        ~~

        return something;

      })(25)


  - 매개변수가 정해지지 않은 함수 처리 방식)

    -> 자바스크립트는 arguments 라는 배열을 제공함

    -> arguments[0], arguments[1], ... 하면 각 순서대로 넘긴 매개변수 값을 가져올 수 있다.

    -> arguments.length : 실재 넘긴 매개변수 개수

    -> arguments.callee 는 함수 정의부를 의미한다.

    -> 따라서, arguments.callee.length 하면 선언된 매개변수 개수

    testFunc(10,20,30,40); // 선언적 함수는 호이스팅되기 때문에 수행 가능.

    function testFunc(a, b){

      if(arguments.callee.length != arguments.callee){

        alert("선언된 함수의 매개변수 개수와 실재 호출시 넘긴 매개변수 개수가 다릅니다.");

        alert("선언 매개변수 개수 : " + arguments.callee.length);

        alert("실재 호출시 넘긴 매개변수 개수 : " + arguments.length);

        // arguments[0] // 10

        // arguments[1] // 20

        // arguments[2] // 30

      }

    }


  - 인코딩/디코딩 내장함수)

    -> 한글 등을 넘길때 값에 문제가 생길 수 있어 인코딩에 사용되는 내장함수이다.

    escape(str) <-> unescape(str)

    encodeURIComponent(str) <-> decodeURIComponent(str)


  - 숫자 판별 내장함수)

    isNaN() : 숫자면 true 아니면 false를 return함.

  - 정수 변환 내장함수)

    parseInt()

  - 실수 변환 내장함수)

    parseFloat()

-------------------------------------------------------------------------------------------


[  객체(Object)  ]

객체 선언 방식 종류)

  1. new Object()를 통한 방식 -> 거의 사용 안함...

  2. 객체 리터럴 방식

    var circle = {

      변수 : "값",

      메서드1 : function(){

        ~~

        return something;

      },

      메서드2 : function(){}

      ...

    }


    -new 를 통해 객체를 여러개 생성할 수 없음으로 3번 생성자를 이용한 방식이 제일 자주 사용된다.

    -객체 선언 이후에 객체에 메서드, 변수를 추가하는 방법)

      circle.새변수명 = 값;

      circle.새메서드명 = function(){

         ~~

      }

      ->*** 이런 방식 말고도 변수나 문자열을 통해서도 동적으로 변수, 메서드를 추가할 수 있다.

      circle["새변수명"] = 값;

      circle["새메서드명"] = function(){};

      var newFunction = "print";

      circle[newFunction] = function(){} 처럼 동적으로 생성할 수 있다.

  3. 생성자 함수를 이용한 방식

    1) 선언적 함수를 이용하는 방식

      function constructorObject(a, b){

        this.변수명 = 값;

        this.메서드명 = function(){}

        ...

      }

    2) 익명함수를 이용하는 방식

      var constructorObject = function(a,b){

        this.변수명 = 값;

        this.메서드명 = function(){}

      }


    new constructorObject(10,20);

    처럼 new 연산자를 통해 인스턴스를 생성해서 사용하며, 이때 this는 자기 자신의 객체를 의미하게 된다.

    -> 자바스크립트에서 각 사용처 별로 this가 굉장히 다른데 추후에 정리...

    -> 일단, 생성자 함수를 통해 생성된 객체에서의 this는 자기 자신의 객체를 의미

    -> 함수 내에서 this는 window 객체를 의미


    역시 익명함수에서도 new를 통해 생성한 객체에 추가로 변수, 메서드를 추가하고 싶은 경우

    var newObject = new constructorObject(10,20);

    newObject.newVal = "새로운 값 추가";

    newObject["newMethod"] = function(){} 처럼 추가할 수 있다.


    *** [ 객체에서의 prototype ]

    -> prototype 사용 이유)

        생성자 함수를 통해 선언된 것을 new 키워드를 통해 객체 생성시 모든 인스턴스들은

        생성자 함수 내에 선언된 메서드 공간을 중복적으로 할당받게 된다.

        하지만 이러한 중복된 메서드를 공간을 객체마다 각기 할당받는 것은 비효율 적임으로

        공유될 수 있는 prototype을 통해 한군대에서만 정의될 수 있도록 해주는 방식을 사용한다.

    클래스명.prototype.변수명 = "값"; // 이 값은 해당 클래스명으로 생성되는 모든 객체에서 공유된다.

    클래스명.prototype.메서드명 = function(){}

    // 한번에 여러개를 뭉뚱그려 정의하고 싶다면...

    클래스명.prototype = {

      // 해당 클래스의 prototype을 통째로 재정의할 수도 있다.

      변수명 : "값",

      메서드1 : function(){},

      메서드2 : function(){},

      ...

    }


  - Date 내장 객체 자주사용되는 메서드)

    var date = new Date();

    date.getFullYear();

    date.getMonth() + 1; // 시작값이 0부터여서 1을 더해야함

    date.getDate(); // 일

    date.getHours();

    date.getMinutes();

    date.getSeconds();


- 콜백(Callback) 함수란? )

: 별거없다... 함수 호출시 매개변수에 함수를 넘겨서 해당 함수 내에서 특정 시점에 넘긴 함수를 수행하기 위한 목적으로 사용된다.

-> ajax등에서 success시 로딩 이미지를 없앤다거나 success가 완료된 시점에 특정 작업 등을 하려할 때 많이 사용된다.

function print(sum){

document.write(sum);

}

function testMethod(callbackF, a, b){

var sum = 0;

sum = a + b;

callbackF(sum); // 전달받은 callbackF(print메서드)를 수행한다.

}

testMethod(print, 10, 20);

[ 자바스크립트로 사용자 OS 버전 확인하는 코드(IE버전 X 운영체제 판별)]


자바스크립트로 IE8 과 같은 브라우저 버전 체크하는 코드는 많은데 막상 사용자의 운영체제가 무슨 버전인지까진 판별하는 코드가 잘 없었는데


다른분 티스토리에서 보고 유용한거같아 공유하려합니다.


조금더 덧대서 해당 윈도우 운영체제에 로그인한 사용자명의 폴더를 알아야할 경우


var net = new ActiveXObject ( "WScript.NetWork" );

var userName = net.UserName;

strFilePath = "C:\\Users\\" + userName + "\\AppData\\Local\\" + nanumTechnologiesPath; 코드를 사용하시면 로그인한 userName도 얻어올 수 있습니다.


이 아래는 자바스크립트로 운영체제 종류와 버전을 판별하는 코드입니다.


// JavaScript Document

// 만든이 : 다섯방울, THREE™ (http://the3.tistory.com)

// 주소 : http://the3.tistory.com/17

// Data : 2015. 01. 28

// Version : 0.2

// 참조 http://www.openspc2.org/userAgent/

// OS 버전 보기


var uanaVigatorOs = navigator.userAgent;

var AgentUserOs= uanaVigatorOs.replace(/ /g,'');

var Ostxt="";

var OSName="";

var OsVers="";


// This script sets OSName variable as follows:

// "Windows"    for all versions of Windows

// "MacOS"      for all versions of Macintosh OS

// "Linux"      for all versions of Linux

// "UNIX"       for all other UNIX flavors 

// "Unknown OS" indicates failure to detect the OS


new function() {

    var OsNo = navigator.userAgent.toLowerCase(); 


    jQuery.os = {

        Linux: /linux/.test(OsNo),

        Unix: /x11/.test(OsNo),

        Mac: /mac/.test(OsNo),

        Windows: /win/.test(OsNo)

    }

}


function OSInfoDev(){

if($.os.Windows) {

if(AgentUserOs.indexOf("WindowsCE") != -1) OSName="Windows CE";

else if(AgentUserOs.indexOf("Windows95") != -1) OSName="Windows 95";

else if(AgentUserOs.indexOf("Windows98") != -1) {

if (AgentUserOs.indexOf("Win9x4.90") != -1) OSName="Windows Millennium Edition (Windows Me)" 

else OSName="Windows 98"; 

}

else if(AgentUserOs.indexOf("WindowsNT4.0") != -1) OSName="Microsoft Windows NT 4.0";

else if(AgentUserOs.indexOf("WindowsNT5.0") != -1) OSName="Windows 2000";

else if(AgentUserOs.indexOf("WindowsNT5.01") != -1) OSName="Windows 2000, Service Pack 1 (SP1)";

else if(AgentUserOs.indexOf("WindowsNT5.1") != -1) OSName="Windows XP";

else if(AgentUserOs.indexOf("WindowsNT5.2") != -1) OSName="Windows 2003";

else if(AgentUserOs.indexOf("WindowsNT6.0") != -1) OSName="Windows Vista/Server 2008";

else if(AgentUserOs.indexOf("WindowsNT6.1") != -1) OSName="Windows 7";

else if(AgentUserOs.indexOf("WindowsNT6.2") != -1) OSName="Windows 8";

else if(AgentUserOs.indexOf("WindowsNT6.3") != -1) OSName="Windows 8.1";

else if(AgentUserOs.indexOf("WindowsNT6.4") != -1) OSName="Windows 10";

else if(AgentUserOs.indexOf("WindowsPhone8.0") != -1) OSName="Windows Phone 8.0";

else if(AgentUserOs.indexOf("WindowsPhoneOS7.5") != -1) OSName="Windows Phone OS 7.5";

else if(AgentUserOs.indexOf("Xbox") != -1) OSName="Xbox 360";

else if(AgentUserOs.indexOf("XboxOne") != -1) OSName="Xbox One";

else if(AgentUserOs.indexOf("Win16") != -1) OSName="Windows 3.x";

else if(AgentUserOs.indexOf("ARM") != -1) OSName="Windows RT";

else OSName="Windows (Unknown)";

if(AgentUserOs.indexOf("WOW64") != -1) OsVers=", WOW64";

else if(AgentUserOs.indexOf("Win64;x64;") != -1) OsVers=", Win64 on x64";

else if(AgentUserOs.indexOf("Win16") != -1) OsVers=" 16-bit";

else OsVers=" on x86";

} else if ($.os.Linux) {

if(AgentUserOs.indexOf("Android") != -1) { OSName = getAndroidDevName(); }

else if(AgentUserOs.indexOf("BlackBerry9000") != -1) OSName="BlackBerry9000";

else if(AgentUserOs.indexOf("BlackBerry9300") != -1) OSName="BlackBerry9300";

else if(AgentUserOs.indexOf("BlackBerry9700") != -1) OSName="BlackBerry9700";

else if(AgentUserOs.indexOf("BlackBerry9780") != -1) OSName="BlackBerry9780";

else if(AgentUserOs.indexOf("BlackBerry9900") != -1) OSName="BlackBerry9900";

else if(AgentUserOs.indexOf("BlackBerry;Opera Mini") != -1) OSName="Opera/9.80";

else if(AgentUserOs.indexOf("Symbian/3") != -1) OSName="Symbian OS3";

else if(AgentUserOs.indexOf("SymbianOS/6") != -1) OSName="Symbian OS6";

else if(AgentUserOs.indexOf("SymbianOS/9") != -1) OSName="Symbian OS9";

else if(AgentUserOs.indexOf("Ubuntu") != -1) OSName="Ubuntu";

else if(AgentUserOs.indexOf("PDA") != -1) OSName="PDA";

else if(AgentUserOs.indexOf("NintendoWii") != -1) OSName="Nintendo Wii";

else if(AgentUserOs.indexOf("PSP") != -1) OSName="PlayStation Portable";

else if(AgentUserOs.indexOf("PS2;") != -1) OSName="PlayStation 2";

else if(AgentUserOs.indexOf("PLAYSTATION3") != -1) OSName="PlayStation 3";

else OSName="Linux (Unknown)";

if(AgentUserOs.indexOf("x86_64") != -1) OsVers=", x86_64";

else if(AgentUserOs.indexOf("i686") != -1) OsVers=", i686";

else if(AgentUserOs.indexOf("i686 on x86_64") != -1) OsVers=", i686 running on x86_64";

else if(AgentUserOs.indexOf("armv7l") != -1) OsVers=" Nokia N900 Linux mobile, on the Fennec browser";

else if(AgentUserOs.indexOf("IA-32") != -1) OsVers=" 32-bit";

else OsVers="";

} else if ($.os.Unix) {

OSName="UNIX";

} else if ($.os.Mac) {

if(AgentUserOs.indexOf("iPhoneOS3") != -1) OSName="iPhone OS 3";

else if(AgentUserOs.indexOf("iPhoneOS4") != -1) OSName="iPhone OS 4";

else if(AgentUserOs.indexOf("iPhoneOS5") != -1) OSName="iPhone OS 5";

else if(AgentUserOs.indexOf("iPhoneOS6") != -1) OSName="iPhone OS 6";

else if(AgentUserOs.indexOf("iPhoneOS7") != -1) OSName="iPhone OS 7";

else if(AgentUserOs.indexOf("iPhoneOS8") != -1) OSName="iPhone OS 8";

else if(AgentUserOs.indexOf("iPad") != -1) OSName="iPad";

else if((AgentUserOs.indexOf("MacOSX10_1")||AgentUserOs.indexOf("MacOSX10.1")) != -1) OSName="Mac OS X Puma";

else if((AgentUserOs.indexOf("MacOSX10_2")||AgentUserOs.indexOf("MacOSX10.2")) != -1) OSName="Mac OS X Jaguar";

else if((AgentUserOs.indexOf("MacOSX10_3")||AgentUserOs.indexOf("MacOSX10.3")) != -1) OSName="Mac OS X Panther";

else if((AgentUserOs.indexOf("MacOSX10_4")||AgentUserOs.indexOf("MacOSX10.4")) != -1) OSName="Mac OS X Tiger";

else if((AgentUserOs.indexOf("MacOSX10_5")||AgentUserOs.indexOf("MacOSX10.5")) != -1) OSName="Mac OS X Leopard";

else if((AgentUserOs.indexOf("MacOSX10_6")||AgentUserOs.indexOf("MacOSX10.6")) != -1) OSName="Mac OS X Snow Leopard";

else if((AgentUserOs.indexOf("MacOSX10_7")||AgentUserOs.indexOf("MacOSX10.7")) != -1) OSName="Mac OS X Lion";

else if((AgentUserOs.indexOf("MacOSX10_8")||AgentUserOs.indexOf("MacOSX10.8")) != -1) OSName="Mac OS X Mountain Lion";

else if((AgentUserOs.indexOf("MacOSX10_9")||AgentUserOs.indexOf("MacOSX10.9")) != -1) OSName="Mac OS X Mavericks";

else if((AgentUserOs.indexOf("MacOSX10_10")||AgentUserOs.indexOf("MacOSX10.10")) != -1) OSName="Mac OS X Yosemite";

else OSName="MacOS (Unknown)";

if(AgentUserOs.indexOf("Intel") != -1) OsVers=" on Intel x86 or x86_64";

else if(AgentUserOs.indexOf("PPC") != -1) OsVers=" on PowerPC";

else OsVers="";

} else {

OSName="Unknown OS";

}

  var OSDev = OSName + OsVers;

  return OSDev;

}


// Android의 단말 이름을 반환

function getAndroidDevName() {

var uaAdata = navigator.userAgent;

var regex = /Android (.*);.*;\s*(.*)\sBuild/;

var match = regex.exec(uaAdata);

if(match) {

var ver = match[1];

var dev_name = match[2];

return "Android " + ver + " " + dev_name;

}

return "Android OS";

}


// OSInfoDev() 는 OS이름과 버전 출력하는 함수

// AgentUserOs 는 userAgent 출력

[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>
   
 
  


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
<!DOCTYPE html>
 
<head>
    <title></title>
</head>
 
<script type="text/javascript">
    function test(name,age){
        this.name = name;
        this.age = age;
    }
    // toString()은 자바스크립트 최상위 Object 객체의 메서드로
    // 모든 객체들은 이 toString을 가지고 있다. 따라서
    // 아래처럼하면 toString()을 재정의한 것이고
    // toString()메서드는 객체명만 기술시 출력할 수 있다.(자바와 same)
    test.prototype.toString = function(){
        return "이름 : " + this.name + " 나이 : " + this.age;
    }
 
    var f = new test("hhh",28);
    alert(f);
 
    // [ 문자열 String 관련 내장 객체 및 메서드 ]
    // 1. 문자열 생성 방법 2가지
    var str = "문자열";
    var str2 = new String("문자열2");
    // 문자열 관련 대표 메서드
        // 문자열 길이
        var strLength = str.length;
        // indexOf("찾을문자열") : 찾을 문자열 시작 인덱스를 반환한다.
        //                      찾는 문자열이 없을시 -1을 리턴한다.
        var startIndex = str.indexOf("자열");
        // replace("old","new");
        str.replace("자열","좌열");
        // match("정규표현식")
        // str.match("정규표현식") : 정규표현식에 일치하는 문자열을 리턴한다.
        // substring(시작인덱스,끝인덱스) : 시작 ~ 끝 까지의 문자열을 반환한다.
        var sub = str2.substring(1,3);
        // toLowerCase() : 소문자로 변환
        var low = str2.toLowerCase();
        // toUpperCase() : 대문자로 변환
        var up = str2.toUpperCase();
 
 
    // [ 숫자관련 내장객체 Number ]
    var num = 10;
    var s = "10";
    var num2 = Number(s); // 숫자로 변환
    // 숫자 관련 대표 메서드 : toFixed(자리수) : 자리수 이하를 버림한다.
    alert(num2.toFixed(1));
    alert(10.23456.toFixed(2));
 
 
    // [ 배열 ]
    var arr1 = [1,2,3,4,5]; // 생성과 동시에 초기화
    var arr2 = new Array(5); // 공간만 생성
    var arr3 = new Array();
 
    // [ 배열관련 메서드 ]
    var arr1Length = arr1.length;
    // push : 배열의 마지막에 데이터를 삽입
    arr1.push("newDataString"); // 자바와 달리 하나의 배열에 여러 타입을 저장할 수 있음.
    // pop : 마지막에 저장한 데이터를 빼옴
    var popData = arr1.pop(); // newDataString
    // splice(시작인덱스,갯수) : 시작인덱스부터 해당 갯수만큼 데이터를 삭제하고, 삭제한 데이터들을 반환함
    var spliceData = arr1.splice(2,3); // 3,4,5 가 spliceData 들어가 있음
    alert("spliceData : " + spliceData);
    alert(arr1); // 1,2
 
 
    // [ Date 객체]
 
        // Date 객체 생성
        var date = new Date();
        // '일' 가져오기
        alert("getData() : " + date.getDate());
        // '월' 가져오기 : 월-1 값이 출력됨을 유의(달만 이렇게...)
        alert("getMonth() : " + date.getMonth()); // 8월이면 7이 출력됨
        // '년' 가져오기
        alert("getFullYear() : " + date.getFullYear());
        // 7일 뒤의 날짜를 구하기 위한 방법
            // 현재 일을 가져와 7을 더하고 세팅
        date.setDate(date.getDate() + 7);
        alert(date);
        date.setFullYear(date.getFullYear() + 2); // 2년뒤
        alert(date);
 
        // 경과시간 구하기
    var date = new Date(); // 현재 날짜 가져오기
    date.setDate(date.getDate() + 7); // 7일 뒤 날짜
    var now = new Date(); // 현재 날짜
    var untilTime = date.getTime();
    var nowTime = now.getTime();
 
    var diffTime = untilTime - nowTime;
    diffTime = diffTime / (1000*60*60*24); // 하루단위로 나눔
    alert("오늘과 일주일뒤의 차이는 7일인가요? : " + diffTime);
 
</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
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
<!DOCTYPE html>
<html>
                                                <head>
                <script type="text/javascript">if (!window.T) { window.T = {} }
window.T.config = {"TOP_SSL_URL":"https://www.tistory.com","PREVIEW":false,"ROLE":"guest","PREV_PAGE":"","NEXT_PAGE":"","BLOG":{"id":2750468,"name":"rongscodinghistory","title":"악덕고용주의 개발 일기","isDormancy":false,"nickName":"고무곰(GomuGom)","status":"open","profileStatus":"normal"},"NEED_COMMENT_LOGIN":true,"COMMENT_LOGIN_CONFIRM_MESSAGE":"이 블로그는 로그인한 사용자에게만 댓글 작성을 허용했습니다. 지금 로그인하시겠습니까?","LOGIN_URL":"https://www.tistory.com/auth/login/?redirectUrl=https://rongscodinghistory.tistory.com/tag/javascript","DEFAULT_URL":"https://rongscodinghistory.tistory.com","USER":{"name":null,"homepage":null,"id":0,"profileImage":null},"SUBSCRIPTION":{"status":"none","isConnected":false,"isPending":false,"isWait":false,"isProcessing":false,"isNone":true},"IS_LOGIN":false,"HAS_BLOG":false,"IS_SUPPORT":false,"IS_SCRAPABLE":false,"TOP_URL":"http://www.tistory.com","JOIN_URL":"https://www.tistory.com/member/join","PHASE":"prod","ROLE_GROUP":"visitor"};
window.T.entryInfo = null;
window.appInfo = {"domain":"tistory.com","topUrl":"https://www.tistory.com","loginUrl":"https://www.tistory.com/auth/login","logoutUrl":"https://www.tistory.com/auth/logout"};
window.initData = {};
 
window.TistoryBlog = {
    basePath: "",
    token: "wK8U9QBk2mf20RtH+mwVU8VqREk9xHQo07LYpIIEhTqYx8H6anIDwQvLLUMyjLYk"
};
var servicePath = "";
var blogURL = "";</script>
 
                 
                 
                 
    <title></title>
 
                <style type="text/css">.another_category {
    border: 1px solid #E5E5E5;
    padding: 10px 10px 5px;
    margin: 10px 0;
    clear: both;
}
 
.another_category h4 {
    font-size: 12px !important;
    margin: 0 !important;
    border-bottom: 1px solid #E5E5E5 !important;
    padding: 2px 0 6px !important;
}
 
.another_category h4 a {
    font-weight: bold !important;
}
 
.another_category table {
    table-layout: fixed;
    border-collapse: collapse;
    width: 100% !important;
    margin-top: 10px !important;
}
 
* html .another_category table {
    width: auto !important;
}
 
*:first-child + html .another_category table {
    width: auto !important;
}
 
.another_category th, .another_category td {
    padding: 0 0 4px !important;
}
 
.another_category th {
    text-align: left;
    font-size: 12px !important;
    font-weight: normal;
    word-break: break-all;
    overflow: hidden;
    line-height: 1.5;
}
 
.another_category td {
    text-align: right;
    width: 80px;
    font-size: 11px;
}
 
.another_category th a {
    font-weight: normal;
    text-decoration: none;
    border: none !important;
}
 
.another_category th a.current {
    font-weight: bold;
    text-decoration: none !important;
    border-bottom: 1px solid !important;
}
 
.another_category th span {
    font-weight: normal;
    text-decoration: none;
    font: 10px Tahoma, Sans-serif;
    border: none !important;
}
 
.another_category_color_gray, .another_category_color_gray h4 {
    border-color: #E5E5E5 !important;
}
 
.another_category_color_gray * {
    color: #909090 !important;
}
 
.another_category_color_gray th a.current {
    border-color: #909090 !important;
}
 
.another_category_color_gray h4, .another_category_color_gray h4 a {
    color: #737373 !important;
}
 
.another_category_color_red, .another_category_color_red h4 {
    border-color: #F6D4D3 !important;
}
 
.another_category_color_red * {
    color: #E86869 !important;
}
 
.another_category_color_red th a.current {
    border-color: #E86869 !important;
}
 
.another_category_color_red h4, .another_category_color_red h4 a {
    color: #ED0908 !important;
}
 
.another_category_color_green, .another_category_color_green h4 {
    border-color: #CCE7C8 !important;
}
 
.another_category_color_green * {
    color: #64C05B !important;
}
 
.another_category_color_green th a.current {
    border-color: #64C05B !important;
}
 
.another_category_color_green h4, .another_category_color_green h4 a {
    color: #3EA731 !important;
}
 
.another_category_color_blue, .another_category_color_blue h4 {
    border-color: #C8DAF2 !important;
}
 
.another_category_color_blue * {
    color: #477FD6 !important;
}
 
.another_category_color_blue th a.current {
    border-color: #477FD6 !important;
}
 
.another_category_color_blue h4, .another_category_color_blue h4 a {
    color: #1960CA !important;
}
 
.another_category_color_violet, .another_category_color_violet h4 {
    border-color: #E1CEEC !important;
}
 
.another_category_color_violet * {
    color: #9D64C5 !important;
}
 
.another_category_color_violet th a.current {
    border-color: #9D64C5 !important;
}
 
.another_category_color_violet h4, .another_category_color_violet h4 a {
    color: #7E2CB5 !important;
}
</style>
 
                 
<link rel="canonical" href="https://rongscodinghistory.tistory.com"/>
 
<!-- BEGIN STRUCTURED_DATA -->
<script type="application/ld+json">
    {"@context":"http://schema.org","@type":"WebSite","url":"/","potentialAction":{"@type":"SearchAction","target":"/search/{search_term_string}","query-input":"required name=search_term_string"}}
</script>
<!-- END STRUCTURED_DATA -->
<link rel="stylesheet" type="text/css" href="//t1.daumcdn.net/tistory_admin/www/style/top/font.css"/>
 
                 
                </head>
<body>
<script type="text/javascript">
    /*
        [    캡슐화    ]
        : 내가 만든 변수에 다른 사용자에 의해 원치않는 값이 대입되는걸 막아야 할
        의도로 사용되어 진다.
        ex) 넓이를 구하는데 필요한 width,height값은 양수만 입력되어야하지만
        사용자가 음수를 입력하면 안되는데 이렇게 음수가 입력되는걸 방지하기 위해
        사용된다.
 
        방법) 외부에서 사용자가 필드변수에 접근하는 것을 막기위해 지역변수로 선언하고
            getter와 setter를 통해서만 접근할 수 있도록 한다.
    */
    function test(){
        /*
            this.nameVal2의 경우 외부에서 접근 가능
            var nameVal은 함수 내부에서 선언시 지역변수로 외부에서 접근이 불가능하다.
            따라서,
        */
        var nameVal = "";
        var ageVal = 0;
        this.nameVal2 = "";
        this.ageVal2 = 0;
         
        this.setterNameVal = function(name){
            nameVal = name;
        }
 
        this.setterAgeVal = function(age){
            if ( age <= 0){
                throw "음수 입력하지마세요";
            }else{
                ageVal = age;  
            }
        }
 
        this.getterNameVal = function(){
            return nameVal;
        }
 
        this.getterAgeVal = function(){
            return ageVal;
        }
    }
 
    test.prototype.info = function(){
        return "소개 : " + this.getterNameVal() + "님의 나이는 : "
             + this.getterAgeVal();
    }
    var f = new test();
    f.setterNameVal("황영롱");
    f.setterAgeVal(28);
 
    alert(f.info());
</script>
 
                <div style="margin:0; padding:0; border:none; background:none; float:none; clear:none; z-index:0"></div>
<script type="text/javascript">window.roosevelt_params_queue = window.roosevelt_params_queue || [{channel_id: 'dk', channel_label: '{tistory}'}]</script>
<script type="text/javascript" src="//t1.daumcdn.net/midas/rt/dk_bt/roosevelt_dk_bt.js" async="async"></script>
 
                 
                <script>window.tiara = {"svcDomain":"user.tistory.com","section":"블로그","trackPage":"태그목록_보기","page":"태그","key":"2750468","customProps":{"userId":"0","blogId":"2750468","entryId":"null","role":"guest","trackPage":"태그목록_보기","filterTarget":false},"entry":null,"kakaoAppKey":"3e6ddd834b023f24221217e370daed18","appUserId":"null"}</script>
<script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.5/polyfills-legacy.js" nomodule="true" defer="true"></script>
<script src="https://t1.daumcdn.net/tistory_admin/frontend/tiara/v1.0.5/index-legacy.js" nomodule="true" defer="true"></script>
 
                </body>
</html>

[    eclipse(이클립스) 자바스크립트(javascript) 자동완성 플러그인 설정하기    ]



이클립스에서 자바스크립트 사용시 ctrl + space 를 눌러 자동완성이 가능하도록 세팅하는 방법에 대한 포스팅입니다.


두가지 작업을 해주어야 합니다.


1. Help 탭->Eclipse Market place->Webclipse 검색 후 설치(install) 후 restart합니다.



2. 두번째로 window탭->preferences->Ant->editor->Content Assist에서 enable auto activation을 체크합니다.





추가하고 나면 아래와 같이 자동완성이 가능한 것을 볼 수 있습니다.



<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <title></title>

  </head>

  <body>

    <ul>

      <li>HTML</li>

      <li>CSS</li>

      <li id="active">JavaScript</li>

    </ul>

    <script type="text/javascript">

      // 복수개의 li가 선택됨

      var liObjs = document.getElementByTagName('li');

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

        console.log(liObjs[i].innerHTML());

      }

      // 부모 요소로 접근하기

      // jquery에서는 parent()

      var ulObj = liObjs[1].parentNode;

      // 부모요소에서 2번째 자식 요소 제거하기

      ulObj.removeChild(liObjs[1]);

      // 자식 요소 중 첫번째 요소 콘솔 찍기

      console.log(ulObj.childNodes[0]);

    </script>

  </body>

</html>



[ 자바스크립트로 제어하고 싶은 대상 선택하기(찾기) ]





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
document 문서 객체를 이용해 문서 부분에 있는 요소들을 선택해 올 수 있다.
 
    1. document.getElementByTagName
    <ul>
        <li>HTML</li>
        <li class="active" id="activeId">CSS</li>
        <li class="active">JavaScript</li>
    </ul>
    <script type="text/javascript">
        var lis = document.getElementByTagName("li");
        for(var i=0; i<lis.length; i++){
            lis[i].style.color="red";
        }
    </script>
    <script type="text/javascript">
        // 조회 대상을 조금 더 좁혀서 잡아오기
        var lis2 = document.getElementByTagname("li")[0];
    </script>
 
    2. document.getElementByClassName
    <script type="text/javascript">
        var lis3 = document.getElementByClassName("active");
        var lis4 = document.getElementByClassName("active")[1];
    </script>
 
    3. document.getElementById
    <script type="text/javascript">
        lis5 = document.getElementByid("activeid").innerHTML();
    </script>
</textaera>


<!DOCTYPE html>

<html>

<head>

<title></title>

</head>

<body>

1. Javascript Inline 방식 : 

<input onclick="alert('hello world')" type="button" name="inline"><br/>


2. <h2 id="hw">script 태그 내에 삽입하는 방식 :</h2>


<script type="text/javascript">

var hw = document.getElementById("hw");

hw.addEventListener("click",function(){

alert("hello world");

})

</script>

<br/>


3. 외부 파일로 분리하는 방식 :

<script type="text/javascript" src="./script2.js"></script>

<br/>


4. 스크립트의 위치 :


스크립트는 어느 위치에나 올 수 있지만 body 태그의 마지막 부분에 위치시키는 것이 좋다.

why??

=> 제어할려는 태그가 다 로딩된 다음에 작업이 수행되어야 하니까(로딩되지 않은 상태에서 작업시 제어 불가)


=> 위치에 상관없이 태그가 다 로딩된 후 수행토록 하려면

: javascript의 경우

=> window.onload = function(){

이 내부 코드는 태그가 다 로딩된 이후 수행하게 된다.

      }


     jquery의 경우

      => document.ready(function(){


      })



</body>

</html>


-----------------------------------------------------------------------------------------------------------------------------

script.js 파일

window.onload = function(){
// 웹브라우저의 모든 구성요소가 로딩된 이후에 수행되게 됨. window.onload = function(){}
var hw = document.getElementByid("hw");
hw.addEventListener("click",function(){
alert("외부 스크립트 파일");
});
}


[    동적으로 생성된 태그에 이벤트를 걸려면 어떻게 해야할까??    ]




가끔 ajax로 가져온 데이터를 문자열로 조합해서 태그에 append하는 경우 이런경우는 태그가 미리 생성되어 있는 경우가 아니라 동적으로


생성된 경우이다. 이런 경우에 문자열로 만든 태그에다가 id나 class준 다음에 $(선택자).on("click",function(event){}) 방식을 사용해서 이벤트를 걸어도


이벤트가 걸리지 않음을 알 수 있다.


이런 경우 어떻게 해야할까??


이런 경우는 document 객체에서 잡아와서 이벤트를 걸어야한다.


ex) $(document).on("click","선택자",function(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
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
 
  </head>
   
 
    <button type="button" id="moveBtn">이동</button>
 
 
    <script type="text/javascript">
      $(document).ready(function(){
          $(document).on("click","#moveBtn",function(event){
            // 동적으로 여러 태그가 생성된 경우라면 이런식으로 클릭된 객체를 this 키워드를 이용해서 잡아올 수 있다.
            alert($(this).text());
          });
      }); // end of ready()
 
 
    </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
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <style media="screen">
      /*
        버튼은 화면 스크롤이 아무리 내려가도 절대위치로 항상 같은 위치에 있도록 하기 위해
        스타일을 지정해 준다.
      */
      #moveBtn{
        position: fixed;
        left: 10px;
        top:10px;
      }
    </style>
  </head>
   
 
    <button type="button" id="moveBtn">이동</button>
 
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
 
    <pre id="preId">
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      글이 무수히 길게 써서 스크롤이 있다고 생각하자...
    </pre>
 
    <script type="text/javascript">
      $(document).ready(function(){
        $("#moveBtn").on("click",function(event){
          // 이동 버튼을 클릭시 pre 태그로 스크롤의 위치가 이동되도록 한다.
 
          // 1. pre태그의 위치를 가지고 있는 객체를 얻어온다. => offset 객체
          var offset = $("#preId").offset();
 
          // offset은 절대 위치를 가져온다. offset.top을 통해 상단의 좌표를 가져온다.
          // position은 부모를 기준으로한 상대위치를 가져온다.
          $("html body").animate({scrollTop:offset.top},2000);
 
        });
      }); // end of ready()
    </script>
  


[    이벤트 발생시 a 태그의 이동기능을 동작하지 않게하고 처리하기    ]




아주 가끔 a태그를 클릭시 a태그 href 에 지정된 속성으로 이동을 막고, 처리가 필요한 경우에 어떻게하는지에 대한 포스팅입니다.


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
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title></title>
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  </head>
   
    <ul>
      <li>
        <a href="국어">국어</a>
      </li>
      <li>
        <a href="영어">영어</a>
      </li>
      <li>
        <a href="수학">수학</a>
      </li>
    </ul>
    <script type="text/javascript">
      $(document).ready(function(){
        $("li a").on("click",function(event){ // a태그 클릭시 작동
          // 클릭된 태그의 본래의 기능을 막음 즉, a태그 본래 기능을 막음
          event.preventDefault();
          var txt = $(this).attr("href"); // href에 입력된 값을 가져옴 즉 클릭된 a의 국어, 영어, 수학 중 하나를 가져옴
 
          alert(txt + "가 클릭됨");
        });
      }); // end of ready()
    </script>
  


[    JQuery 애니메이션 관련 정리(fadeIn,fadeOut,hide,show,animate,stop)    ]



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
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title>animate 관련...</title>
  </head>
   
    <button type="button" id="button1">BTN1</button>
    <p id="p1">BTN1</p>
    <button type="button" id="button2">BTN2</button>
    <p id="p2">BTN2</p>
    <button type="button" id="button3">BTN3</button>
    <p id="p3">BTN3</p>
    <button type="button" id="button4">BTN4</button>
    <p id="p4">BTN4</p>
    <button type="button" id="button5">BTN5</button>
    <p id="p5">BTN5</p>
    <button type="button" id="button6">BTN5</button>
 
 
    <script type="text/javascript">
      // 1. $(선택자).hide(ms) : ms 시간에 걸쳐 사라짐(효과는 없음)
      $("#button1").on("click",function(event){
        $("#p1").hide(200);
      });
      // 2. $(선택자).show(ms) : ms 시간에 걸쳐 나타나게 함(효과 X)
      $("#button1").on("click",function(event){
        $("#p1").show(200); // 0.2초에 걸쳐 나타남
      })
      // 3. $(선택자).toogle(ms) : ms초에 걸쳐 hide상태면 show하고 show상태면 hide상태로 바꿈
      $("#button1").on("click",function(event){
        $("#p1").toogle(200);
      })
      // 4. $(선택자).fadeIn(ms) : ms 초에 걸쳐 점차적으로 나타남(효과가 O)
      $(document).on("click","#button2",function(event){
        // 동적으로 태그를 생성시에는 이런식으로 이벤트를 줘야함(그냥 써밧음...)
        $("#p2").fadeIn(2000); // 2초에 걸쳐 점차적으로 나타남
      })
      // 5. $(선택자).fadeOut(ms) : ms 초에 걸쳐 사라짐(효과O)
      $("#button2").on("click",function(event){
        $("#p2").fadeOut(2000);
      });
      // 6. $(선택자).fadeTo(ms,0~1) : ms동안 0~1 사이의 opacity(투명도) 상태가 됨 1은 완전히 보임 0은 아예 안보임
      $("#button3").on("click",function(event){
        $("#p3").fadeTo(2000,0.3);
      })
      // 7. $(선택자).slideDown(ms) : ms초에 걸쳐 펼쳐지듯이 나타남
      $("#button4").on("click",function(event){
        $("#p4").slideDown(2000);
      })
      // 8. $(선택자).slideUp(ms) : ms초에 걸쳐 접히는 효과로 사라짐
      $("#button4").on("click",function(event){
        $("#p4").slideUp(2000);
      })
///////////////////////////////////////////////////////////////////////////////////////////////
 
      // 9. $(선택자).animate({css속성},ms) : ms초에 걸쳐 css 속성을 지정된 걸 차츰 적용함(애니메이션 효과)
      $("#button5").on("click",function(event){
        $("#p5").animate({margin-left:250px,color:red},5000).animate({margin-left:0px},3000);
      });
 
      // 10. $(선택자).stop() : 수행중인 애니메이션 효과를 정지시킴
      $("#button6").on("click",function(event){
        $("#p5").stop();
      });
 
    </script>
  


[    script 선언의 위치와 수행 순서에 대해서...     ]



<script type="text/javascript">

...

</script>


이런식으로 스크립트를 작성하게 되는데 이때, 이 스크립트 블록을 어디다 수행하는게 좋을까요??


어디든 상관은 없습니다. 하지만 주의해야하는 사항이 몇가지 있죠


예를들어, head 태그 안에서 script를 선언하고 body 안에 선언해 놓은 태그에 대한 작업을 한다고 해봅시다.


그러면 어떻게 될까요? 


해당 script가 수행되는 시점에서 body 태그는 아직 파싱되기 전이기 때문에 script에서 해당 태그가 무엇인지 알 수가 없게 됩니다.


따라서 그냥 null을 가지고 작업을하게되죠...


따라서, body 태그가 다 로딩되고 body 태그 안에서 제일 밑 부분에 작성할 스크립트를 위치시켜주는 것이 best일 것입니다.


<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <title></title>

  </head>

  <body>

    <input type="text" name="" value="" id="in">

    <table>

      <tr>

        <td>dd</td>

      </tr>

    </table>


    <script type="text/javascript">

      document.getElementById("in").value = "modifyValue";

    </script>

// 이처럼 아래쪽에 위치시켜주는 것이 좋습니다. 이걸 만약 head 태그 내에 위치하거나 input 태그 위에 위치시킨다면

// 스크립트가 제대로 수행될 수 없겠죠?

  </body>

</html>

[    3. 일정주기마다 callback 함수를 실행하는 setInterval()에 대해서...    ]



Callback Function

  • 조건을 등록해 두고 그 조건을 만족한 경우, 나중에 호출되는 함수

시간을 기반으로 콜백함수를 호출하는 명령

setTimeout( function, time )

  • time 시간이 지난 경우 function 함수를 콜백하는 함수
  • time 은 millisecond (1/1000초) 단위
  • timerId를 반환함

clearTimeout( timerId )

  • setTimeout 함수 호출의 결과로 반환된 timerId를 인자로 받아 예약되어 있던 function호출을 취소
    • 이미 function이 호출된 경우(시간이 지나 이벤트가 발생한 경우)에는 효과 없음

setInterval( function, time )

  • time 시간이 경과할 때마다 function 함수를 콜백하는 함수
  • timerId를 반환함

clearInterval( intervalId )

  • setInterval 함수 호출의 결과로 반환된 intervalId를 인자로 받아 주기적으로 호출되던 function 호출을 취소


다음 예시 사진을 보면, setTimeout을 호출 했을 때 3초뒤에 callback()으로 지정한 함수가 실행된 것을 알 수 있습니다.


이때, 142를 반환했는데 이것은 setTimeout의 id라고 생각하시면 되고 지정한 setTimeout을 해제하기 위해서는 clearTimeout(setTimeout의 id)를 넣어주어야 취소가 가능합니다.


다음으로


setInterval ( 수행할 메서드, 시간) 으로 여기선 5초 마다 콜백 메서드를 수행하도록 되어 있습니다. 이것을 해제하기 위해서는 역시 callback 메서드의 id가 143번 임으로


clearInterval(143)을 통해 해제 시켜 준 것을 알 수 있습니다.


콘솔에서는 id가 몇번인지 알 수 있지만 코드상에서 작성할 때에는 바로바로 확인이 어려움으로


var setIntervalId = setInterval(callback, 5000);

clearInterval(setIntervalId); 처럼 해서 사용하시면 됩니다.




[    Javascript의 브라우저 창 Window 객체(부모창 자식창 값 주고 받기 포함)    ]



window 객체


    • Javascript 실행시 가장 상위에 존재하는 객체

        • 변수를 선언하거나 함수 선언시 window 객체안에 선언됨
        • 크롬에서 F12를 눌러 console탭에서 window 객체를 입력해서 다양한 속성들을 조회해볼 수 있음.
    • 표시된 웹 페이지의 정보에 접근하거나 변경을 할 수 있음

        • window.location : 현재 브라우저 창의 주소를 나타내는 객체
        • window.location.href : 브라우저 창에 입력된 주소, 변경 가능
          • ex) window.location.href = "이동하고자하는 url "
          • ex) window.location.replace = "이동하고자하는 url" 위의 것과 차이점은 이동하고나서 뒤로가기 버튼이 활성화되지 않음.
        • window.open : 새창 띄우기
        • window.navigator : 브라우저 자체에 대한 정보
        • window.screen : 디스플레이의 사이즈
        • window.document : 웹 페이지 문서의 HTML, CSS 등에 대한 접근 가능









    • 2. [ window 객체를 이용해 새창을 띄우고 부모창과 자식창 사이에서 값을 주고 받는 방법 ]


    • var windowObj = window.open("새창에서띄울url","창이름","창의설정(옵션값)"); 처럼하면 현재창에서 새로운 창이 뜨게 됩니다. 이때 기존의 창이 부모창이 되고 새로 뜨게된 창이 자식창이되게되는데

      이때, 부모창과 자식창 사이에서 값을 주고 받기 위해서는 띄운 창의 window 객체를 저장할 변수를 선언해 저장해 놔야합니다.(windowObj)

      그런 다음 부모 창에서는 이 windowObj 변수를 이용해 자식창에 값을 전달할 수 있습니다. 예를들어, 

      windowObj.document.text2.value = "값 입력"; 이런식으로 자식창(새창)의 document 객체에 얼마든지 접근할 수 있습니다. 

      그러면, 반대로 자식창에서 부모창으로 값을 보내기 위해서는 어떤 식으로 해야할까요??

      일단, 부모창에서 자식창을 생성하면 이 자식창은 생성과 동시에 opener 라는 객체를 가지게 되고 이 opener는 바로 부모객체의 window 객체를 가리키게 됩니다. 따라서

      opener.document.parentText.value = document.text2.value; 이런식으로 자식에 있는 값을 부모 창으로 넘기는게 가능합니다.


      먼저, windowOpen1.html 즉, 부모창 예제 코드입니다.

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
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title>부모창입니다.</title>
  </head>
   
    <input type="text" id="parentText" value="부모창의값" />
    <input type="text" id="receiveFromChild" value=""/>
    <button type="button" onclick="javascript:openChildWindow();">자식창열기</button>
    <script type="text/javascript">
      // 자식창 window 객체를 저장할 변수
      var windowObj;
      function openChildWindow(){
 
        // 새창에 대한 세팅(옵션)
        var settings ='toolbar=0,directories=0,status=no,menubar=0,scrollbars=auto,resizable=no,height=200,width=200,left=0,top=0';
        // 자식창을 열고 자식창의 window 객체를 windowObj 변수에 저장
        windowObj = window.open("windowOpen2.html","자식창",settings);
 
        // 자식창의 childText라는 id를 가진 태그 요소의 값에 부모창의 값을 넣음
        windowObj.document.getElementById("childText").value = document.getElementById('parentText').value;
      }
    </script>
  



다음으로 windowOpen2.html 즉, 자식창 예제 코드입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
 
  <head>
    <meta charset="utf-8">
    <title>자식창</title>
  </head>
   
    부모창에서 전달받은 값 : <input type="text" id="childText" />
    <button type="button" name="button" onclick="sendToParent();">부모에게 전달</button>
    <script type="text/javascript">
      function sendToParent(){
        var txt = document.getElementById("childText").value + "자식창 값을 +합니다.";
        // opener 를 이용해 부모 window 객체에 접근할 수 있습니다.
        // 부모에게서 전달받은 값에 추가로 문자열을 더해서 다시 부모의 receiveFromChild 라는 id를 갖는
        // 태그요소에 value 값을 바꾸어 주는 작업입니다.
        opener.document.getElementById("receiveFromChild").value = txt;
 
        // 창을 닫음
        window.close();
      }
    </script>
  


위의 예제는 동일 폴더 내에서 테스트한걸로 크롬 보안상 작동하지 않을 수 있지만, 웹 서버에서 할 때는 잘 작동한다는 점 참고해주시기 바랍니다.



[    스프링과 안드로이드 연동5 : Javascript에서 Android 함수를 호출하기    ]



요즘은 웹을 개발하고 웹뷰를 이용해서 안드로이드에 붙이는 식으로 해서 반응형으로 하이브리드 앱을 만드는 경우가 많은데,


이러한 경우 웹뷰에서 버튼을 클릭한다거나 했을 때 자바스크립트에서 안드로이드에 있는 함수를 호출해서 


안드로이드를 제어하고 싶은 경우가 있다.


----------------------------------------------------------------------------------------------------------------------------------


먼저, 웹뷰를 연결해 세팅부터 하자.


1. [    WebView(웹뷰) 세팅    ]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<span style="font-size: 14pt;">
/ 웹뷰 위젯 연결
        webView1 = (WebView)findViewById(R.id.webView1);
        // 클리기 새창 안뜨게...
        webView1.setWebViewClient(new WebViewClient());
        // 세부 세팅객체 가져오기
        WebSettings mWebSettings = webView1.getSettings();
        // 자바스크립트 사용 허용
        // 웹뷰 내에서 자바스크립트 실행해 자바스크립트에서 안드로이드 함수
        // 실행시킬려면 필수로 세팅필요
        mWebSettings.setJavaScriptEnabled(true);
        // 안드로이드에서 제공하는 줌 아이콘을 사용할 수 있도록 설정
        mWebSettings.setBuiltInZoomControls(true);
        // 캐시 사용 여부 설정
        mWebSettings.setAppCacheEnabled(false);
 
        // 로드할 주소를 입력
        webView1.loadUrl("http://192.168.0.8:8080/");
</span>

일단 스프링 웹 프로젝트에서 작성한 웹 페이지를 띄우는 웹뷰를 작성한다.

그 다음에 


2. 자바스크립트에서 호출시 수행할 안드로이드 메서드를 작성한다.


이때, 자바스크립트와 안드로이드를 중간에서 인터페이스 역할을 할 클래스를 작성해서 그 내부에

메서드를 정의하도록 한다.


당연히 인터넷 작업을 해야함으로

<!-- 인터넷 접속 권한 추가 -->
<uses-permission android:name="android.permission.INTERNET" />

를 manifest에 추가해주어야 하고

네트워크 작업은 백그라운드 쓰레드로 해야하며


백그라운드 쓰레드에서는 메인 뷰의 화면 제어를 할 수 없음으로

handler에게 대신해달라고 요청을 해야한다.


앞에선 계속 그렇게 해왔는데 이 2가지를 한번에 하는 것이


handler.post(new Runnable(){ run() }) 을 이용한 방식이다.


이런식으로해서 JavascriptInterface 클래스를 만들도록 한다.


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
<span style="font-size: 14pt;">
package com.example.kscs.androidspringconnection1;
 
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
 
public class WebViewActivity extends AppCompatActivity {
 
    WebView webView1;
    Handler handler = new Handler();
    TextView textView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view);
 
        // 웹뷰 위젯 연결
        webView1 = (WebView)findViewById(R.id.webView1);
        // 클리기 새창 안뜨게...
        webView1.setWebViewClient(new WebViewClient());
        // 세부 세팅객체 가져오기
        WebSettings mWebSettings = webView1.getSettings();
        // 자바스크립트 사용 허용
        // 웹뷰 내에서 자바스크립트 실행해 자바스크립트에서 안드로이드 함수
        // 실행시킬려면 필수로 세팅필요
        mWebSettings.setJavaScriptEnabled(true);
        // 안드로이드에서 제공하는 줌 아이콘을 사용할 수 있도록 설정
        mWebSettings.setBuiltInZoomControls(true);
        // 캐시 사용 여부 설정
        mWebSettings.setAppCacheEnabled(false);
 
        // 로드할 주소를 입력
        webView1.loadUrl("http://192.168.0.8:8080/");
 
        // 텍스트 뷰 위젯 연결
        textView = (TextView)findViewById(R.id.textView);
 
    }
 
    final class JavascriptInterface {
        @android.webkit.JavascriptInterface  // 최근에는 이 어노테이션을 붙여줘야 동작하게 되어 있다..
        public void callMethodName(final String str){ // 반드시 final이어야 한다.
            // 네트워크를 통한 작업임으로 백그라운드 스레드를 써서 작업해야한다.
            // 또한, 백그라운드 스레드는 직접 메인 뷰에 접근해 제어할 수 없음으로
            // 핸들러를 통해서 작업해야하는데
            // 이 때문에 한번에 handler.post()를 통해서 내부에 Runnable을 구현해 작업한다.
            handler.post(new Runnable() {
                @Override
                public void run() {
                    // handle를 통해서 화면에 접근하는 것임으로 가능함
                    textView.setText("자바스크립트에서 전달받은 문자열을 쓴다 : " + str);
                }
            });
        }
    }
 
}
 
 
 
</span>



3. 만들어준 JavascriptInterface 클래스를 웹뷰에 등록해 주어야 한다.


1
2
3
<span style="font-size: 14pt;">
webView1.addJavascriptInterface(new JavascriptInterface(),"myJSInterfaceName");
</span>

이때 중요한 점은 

webView1.addJavascriptInterface(new JavascriptInterface(),"myJSInterfaceName");

에서 두번째 매개변수란에 myJSInterfaceName 처럼 인터페이스 이름을 지정하게 되어 있는데

이 이름을 이용해서 자바스크립트에서 호출하게 된다.



4. 스프링 웹 프로젝트의 자바스크립트에서 특정 이벤트 발생시 안드로이드 함수를 호출하는 구문을 작성하자.


가장 중요한 부분은 window.myJSInterfaceName.callMethodName(str); 부분이다.

window.(지정한 javascript인터페이스명).수행할메서드명() 으로 호출하게 된다.

function callAndroid(){
    var str = document.getElementById("txtName").value;
    window.myJSInterfaceName.callMethodName(str);
}

<form id="formName" action="">
    <input id="txtName" type="text" />
    <button onclick="javascript:callAndroid()">호출하기</button>
 
</form>
1
2
3
4
5
6
7
8
9
10
11
12
<span style="font-size: 14pt;">
function callAndroid(){
    var str = document.getElementById("txtName").value;
    window.myJSInterfaceName.callMethodName(str);
}
 
<form id="formName" action="">
    <input id="txtName" type="text" />
    <button onclick="javascript:callAndroid()">호출하기</button>
  
</form>
</span>


여기까지 했다면, 


웹뷰 상에서 안드로이드 사용자가 "호출하기" 버튼을 클릭시에 callAndroid() 자바스크립트 메서드가 수행되고


해당 자바스크립트 메서드에서 window.myJSInterfaceName.callMethodName(str); 을 통해 안드로이드 메서드를 

호출하여, TextView에 있는 메시지를 웹뷰를 통해 입력한 값으로 세팅하게 된다.



안드로이드 쪽 전체 코드는 다음과 같다.



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
package com.example.kscs.androidspringconnection1;
 
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
 
public class WebViewActivity extends AppCompatActivity {
 
    WebView webView1;
    Handler handler = new Handler();
    TextView textView;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web_view);
 
        // 웹뷰 위젯 연결
        webView1 = (WebView)findViewById(R.id.webView1);
        // 클리기 새창 안뜨게...
        webView1.setWebViewClient(new WebViewClient());
        // 세부 세팅객체 가져오기
        WebSettings mWebSettings = webView1.getSettings();
        // 자바스크립트 사용 허용
        // 웹뷰 내에서 자바스크립트 실행해 자바스크립트에서 안드로이드 함수
        // 실행시킬려면 필수로 세팅필요
        mWebSettings.setJavaScriptEnabled(true);
        // 안드로이드에서 제공하는 줌 아이콘을 사용할 수 있도록 설정
        mWebSettings.setBuiltInZoomControls(true);
        // 캐시 사용 여부 설정
        mWebSettings.setAppCacheEnabled(false);
 
        // 로드할 주소를 입력
        webView1.loadUrl("http://192.168.0.8:8080/");
 
        // 텍스트 뷰 위젯 연결
        textView = (TextView)findViewById(R.id.textView);
 
        webView1.addJavascriptInterface(new JavascriptInterface(),"myJSInterfaceName");
    }
 
    final class JavascriptInterface {
        @android.webkit.JavascriptInterface
        public void callMethodName(final String str){ // 반드시 final이어야 한다.
            // 네트워크를 통한 작업임으로 백그라운드 스레드를 써서 작업해야한다.
            // 또한, 백그라운드 스레드는 직접 메인 뷰에 접근해 제어할 수 없음으로
            // 핸들러를 통해서 작업해야하는데
            // 이 때문에 한번에 handler.post()를 통해서 내부에 Runnable을 구현해 작업한다.
            handler.post(new Runnable() {
                @Override
                public void run() {
                    // handle를 통해서 화면에 접근하는 것임으로 가능함
                    textView.setText("자바스크립트에서 전달받은 문자열을 쓴다 : " + str);
                }
            });
        }
    }
 
}
[    HandleBars 적용하기    ]

: HandleBars는 Javascript 라이브러리 중 하나로, 보통 AJAX로 가져온 데이터를 JQuery에서 문자열로 조합한다음에 append해주는

  불편함을 줄여주기 위해 주로 사용됩니다.

  특징)

1. 태그를 이용해서 구성을 잡아준다.(템플릿을 만든다.)
2. 템플릿 사이사이에 데이터가 들어갈 곳에 {{ 변수 }} 로 넣어놓는다.
3. 템플릿과 데이터를 연결시 {{}} 부분에 데이터가 들어가게 된다.

이때, {{#변수}} {{/변수}} 부분에는 배열과 같은 타입의 데이터의 길이가 들어와 그 길이만큼 반복작업을 수행하게 된다.

제일먼저 사용하기 위해, HandleBars js 라이브러리를 다운로드하고, 

<script src="" 를 이용해서 임포트 해주고 사용해야 한다. 이후 설명은 아래 소스코드에서 이어가겠습니다.


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
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<!--
handlebars js 라이브러리 추가
 -->
<script type="text/javascript" src="/resources/js/handlebars-v4.0.10.js"></script>
<title>Insert title here</title>
</head>
 
    <!--
        handlebars 템플릿 작성
        : script내부에 type을 text/x-handlebars-X 식으로 작성한다. X부분에는 자신이 원하는 명칭을 넣을 수 있다.
        ex) type="text/x-handlebars-myTemplate"
        handlebars의 요점)
            1. handlebars는 태그를 이용한 템플릿을 구성하고
            2. 그 템플릿에 들어갈 데이터를 구성하고
            3. 마지막으로 데이터를 템플릿에 적용한다.
            이때, 템플릿에 데이터가 들어갈 자리에는 {{ }} 이 안에 변수명을 표시해주게 된다.
             
            아래의 템플릿에서 {{#users}} {{/users}} 부분은 : users 배열과 같은 객체의 길이가 들어와 해당 길이만큼 반복문을 돌게된다.
            예를들어 users={{name:'abc',id:'sooingkr'},{name:'ccc',id:'ddd'}}; 라는 users 배열이 있으면 2번 돌면서 찍게된다.
             
            {{#users}} {{/users}} 내부에 {{name}}, {{id}} 부분에는 users 배열의 각 인덱스가 가리키는 변수명을 기재해주면 된다.
     -->
    <script id="entry-template" type="text/x-handlebars-template">
    <table>
        <thead>
            <th>이름</th>
            <th>아이디</th>
            <th>메일주소</th>
        </thead>
        <tbody>
            {{#users}}
            <tr>
                <td>{{name}}</td>
                <td>{{id}}</td>
             
            {{!-- 사용자 정의 헬퍼인 email에 id를 인자로 넘긴다 --}}
                <td><a href="mailto:{{email id}}">{{email id}}</a></td>
            </tr>
            {{/users}}
        </tbody>
    </table>
    </script>
    <script>
        // [    handlebars 적용하기 ]
     
        //핸들바 템플릿 가져온다.
        var source = $("#entry-template").html();
     
        //핸들바 템플릿 컴파일
        var template = Handlebars.compile(source);
     
        //핸들바 템플릿에 바인딩할 데이터
        var data = {
                users: [
                    { name: "홍길동1", id: "aaa1" },
                    { name: "홍길동2", id: "aaa2" },
                    { name: "홍길동3", id: "aaa3" },
                    { name: "홍길동4", id: "aaa4" },
                    { name: "홍길동5", id: "aaa5" }
                ]
        };
     
        //커스텀 헬퍼 등록 (id를 인자로 받아서 전체 이메일 주소를 반환)
        // 위에서 {{email id}} 에서 email부분에 id를 인자로 넘기게 되는 것!
        // 그럼 id@daum.net을 반환해서 들어가게 됨.
        Handlebars.registerHelper('email', function (id) {
          return id + "@daum.net";
        });
     
        //핸들바 템플릿에 데이터를 바인딩해서 HTML 생성
        var html = template(data);
     
        //생성된 HTML을 DOM에 주입
        $('body').append(html);
    </script>


+ Recent posts