강의 컨설팅 트레이닝 무료진단 무료책자 마케팅편지 마케팅정보공유 다이어리 서비스제휴 고객센터

동적 테이블 생성 DHTML
작성자 : 99 단국강토
등록날짜 : 2009.02.09 10:00
2,986

Soylent Green은 다양한 사람들로 구성되어 있으며, 여러분은 그 사람들과 대화하실 수 있습니다. "

Soylent Green은 웹과 비슷합니다. 차이점이 있다면 Soylent Green은 사람들로 구성되고 웹은 테이블로 구성된다는 것입니다. 맞습니다. 바로 테이블들로 구성되죠. 여러분이 일상적으로 방문하는 사이트를 살펴 보십시오. 소스 코드에서 <TABLE>을 검색하면 적어도 하나 이상의 테이블을 찾아보실 수 있을 것입니다.


--------------------------------------------------------------------------------
Internet Explorer 5의 업데이트된 디스플레이 기능을 사용하면 테이블을 쉽게 조작할 수 있습니다.
--------------------------------------------------------------------------------

Internet Explorer 4.0의 경우, DHTML을 사용하여 테이블을 조작하기란 간단한 작업이 아니었습니다. 제 경우에도, 디스플레이 속성을 조작할 경우 디스플레이가 끝난 후 약간의 테두리 터드(기술적 용어)가 남았었던 기억이 있습니다. 행이나 셀을 추가하거나 삭제할 때는 어땠을까요? 저는 단 두 명의 분석가가 인센스, 챈팅, 프로그 래그를 조합하는 방법을 계산했을 것이라고 생각했지만, 사실 이 작업은 생각보다 어렵고 복잡한 것이었습니다.

너무 어렵고, 복잡하고, 작동도 되지 않았다구요? 이제 잊어버리세요.

Internet Explorer 5에서는 디스플레이 속성이 테이블의 행과 셀에 제대로 적용됩니다. 또한, 테이블 셀과 행을 간단하게 삽입하거나 제거할 수 있고, 테이블 셀과 행 사이를 이동하기도 쉽습니다

이제 예제를 하나 살펴 봅시다.

선택


사용자는 테이블 편집기에서 한 번 클릭하여 하나의 셀을 선택할 수 있습니다. 또는, ALT 키를 누른 상태에서 셀을 클릭하면 전체 행을 선택할 수도 있습니다. 이 작동 방법에 대하여 살펴봅시다.

function select(element) {
  var e, r, c;
  if (element == null) {
    e = window.event.srcElement;
  } else {
    e = element;
  }
  if ((window.event.altKey) || (e.tagName == "TR")) {
    r = findRow(e);
    if (r != null) {
      if (lastSelection != null) {
        deselectRowOrCell(lastSelection);
      }
      selectRowOrCell(r);
      lastSelection = r;
    }
  } else {
    c = findCell(e);
    if (c != null) {
      if (lastSelection != null) {
        deselectRowOrCell(lastSelection);
      }
      selectRowOrCell(c);
      lastSelection = c;
    }
  }

  window.event.cancelBubble = true;
}

TableContainer.onclick = select;

function cancelSelect() {

  if (window.event.srcElement.tagName != "BODY")
    return;

  if (lastSelection != null) {
    deselectRowOrCell(lastSelection);
    lastSelection = null;
  }
}

document.onclick = cancelSelect;

function findRow(e) {
  if (e.tagName == "TR") {
    return e;
  } else if (e.tagName == "BODY") {
    return null;
  } else {
    return findRow(e.parentElement);
  }
}

function findCell(e) {
  if (e.tagName == "TD") {
    return e;
  } else if (e.tagName == "BODY") {
    return null;
  } else {
    return findCell(e.parentElement);
  }
}

function deselectRowOrCell(r) {
  r.runtimeStyle.backgroundColor = "";
  r.runtimeStyle.color = "";
}

function selectRowOrCell(r) {
  r.runtimeStyle.backgroundColor = "darkblue";
  r.runtimeStyle.color = "white";
}

필자는 테이블에 대한 모든 클릭 이벤트를 캡쳐하기 위해, TableContainer.onclick 이벤트를 select() 메서드에 연결했습니다. 그러나 실제로는 코드 안의 다른 위치에서 select() 메서드를 사용하려 합니다. 예를 들어, 새로운 행이 만들어졌을 때 이 행을 삽입한 후 선택하려면 select() 메서드는 지정된 요소를 선택할 수 있도록 추가의 매개 변수를 가져야 합니다.

select()메서드의 다른 코드는 대부분 선택/선택 취소 로직이기 때문에, 한번에 단 하나의 행이나 셀만 시각적으로 강조됩니다.

클릭 처리기의 srcElement는 실제 테이블 셀 (<TD>)이 아닐 수도 있다는 점에 유념하십시오. 사용자가 셀 안의 텍스트를 클릭하면, srcElement는 <TD>가 됩니다. 그러나, <TD><B>Some Bold</B> Text</TD>와 같이 더 복잡한 HTML 구조인 경우에는, "Some Bold"를 클릭하면 "Text"와는 다른 srcElement가 반환됩니다. 그래서 발생하는 각 클릭에 대한 <TR>이나 <TD>를 찾기 위해서는 parentElement 체인을 반복 검색해주는 findCell/findRow 메서드를 사용합니다.

또한 Internet Explorer 5의 경우, 선택 프로세스에는 몇 가지 새로운 기능이 사용됩니다. CSS(cascading style sheet) 색과 배경 색 속성을 설정하면, 셀이나 행이 "selected"되었을 때 각 요소가 시각적으로 강조됩니다. 그러나, element.style.color를 설정하면, 선택 프로세스는 사용자가 설정한 CSS 속성(Set Row/Cell Style 함수를 통해 설정됨)은 무시됩니다. 따라서, 사용자가 셀이나 행에 대한 CSS 속성을 설정할 수 있게 하고, 프로그램에 의한 색상 조작을 배제하려면 런타임 스타일(RuntimeStyle)이라는 개체를 사용해야 합니다.


런타임 스타일 개체(element.runtimeStyle)를 통해 스타일을 설정하면 다른 CSS 속성 값 설정은 무시됩니다. 런타임 스타일 개체는 독립적으로 유지되기 때문에 변경값이 다른 CSS 설정과 충돌하지 않습니다. 한 예로 다음 코드를 살펴 봅시다.

element.style.color = "blue"; // 요소는 이제 청색이 됩니다.

element.runtimeStyle.color = "red"; // 요소는 이제 빨간색이 됩니다.

element.runtimeStyle.color = ""; // 요소가 다시 청색이 됩니다.

런타임 스타일을 어떻게 바꾸어도 요소에 대한 다른 CSS 설정은 무시됩니다. 그러나, 런타임 스타일 개체를 제거하면, 원래의 CSS 값이 다시 적용됩니다.


셀 추가하기

Internet Explorer 5를 사용하면 HTML이나 XML 요소를 보다 쉽게 추가할 수 있습니다. Internet Explorer 4.0에서는, 요소를 추가할 때 다음과 같이 해당 요소의 HTML 구현을 페이지에 삽입해야 했습니다.

document.body.insertAdjacentHTML("AfterBegin",
                                 "<img src='ie.gif'>");

그러나, 이러한 방식으로는 생성이 불가능한 요소도 있습니다. 또한, 이 방법에서는 테이블 요소와 프레임 셋, 도큐먼트 헤드에 있는 요소 등을 쉽게 조작할 수도 없습니다.


Internet Explorer 5에서는 이러한 요소를 더 쉽고 간단하게 만들 수 있습니다. 즉, 여러분은 HTML 구문은 잘 몰라도 새로운 요소를 도큐먼트에 추가할 수는 있습니다.

i = document.createElement("IMG");
i.src = "ie.gif";
document.body.insertBefore(i, null);
다음은 새로운 셀을 테이블 행에 추가할 때 사용하는 코드입니다.
function addCell() {
  var r, p, c, nc, text;
  if (lastSelection == null)
    return false;

  r = lastSelection;

  if (r.tagName == "TD") {
    r = r.parentElement;
    c = lastSelection;
  } else {
    c = null;
  }

  nc = document.createElement("TD");
  text = document.createTextNode("New Cell");

  nc.insertBefore(text, null);
  r.insertBefore(nc, c);

  select(nc);

  return nc;
}

이 메서드의 첫 번째 부분은 단순히 현재 선택된 요소를 찾는 역할을 수행합니다. 그러나, 마지막 다섯 줄은 약간 특별한 경우인데 즉, createElement() 메서드에 의해 새로운 <TD>가 생성됩니다. 이러한 방식으로 생성된 요소는 활성 문서에 포함될 때까지 문서에 나타나지 않습니다. 외부적으로 요소 트리를 그 해당 문서에 결합시킬 수도 있습니다(메인 트리에 속하지 않는 요소에 대해 insertBefore()를 호출하면 됨). 이런 식으로 문서 전체 섹션을 동시에 추가하거나 삭제할 수 있습니다.

이 때, 필자는 새로운 셀 안에 텍스트를 넣었습니다. 요소가 메인 문서 트리 밖에 있을 때 텍스트를 만들거나 조작하려면, Text Nodes를 사용해야 합니다. Text Nodes에는 텍스트 이외의 다른 HTML 요소가 들어갈 수 없으며, 필자가 <TD>에 텍스트가 포함된 볼드체 태그를 넣고자 했다면, <B>요소를 만들고 <B>를 <TD>안에 삽입한 다음, 텍스트를 <B>안에 삽입했을 것입니다. 텍스트 노드 개체에 관한 자세한 내용은 Web Workshop의 DHTML Objects area  부분을 참고하십시오.

단, 저는 앞 절에서 설명한 select() 메서드를 사용하여 새로 생성된 테이블 셀을 선택하고 있습니다.


행 제거하기

세상사가 그렇듯이 창조보다는 파괴가 더 쉬운 법입니다. 다음은 테이블 행을 삭제하는데 사용되는 코드입니다.

function removeRow() {
  var r, p, nr;
  if (lastSelection == null)
    return false;

  r = lastSelection;

  if (r.tagName == "TD") {
    r = r.parentElement;
  }

  p = r.parentElement;

  p.removeChild(r);

  lastSelection = null;
 
  return r;
}

이 코드에서 유일한 메소드인 removeChild()는 도큐먼트에서 임의의 요소를 제거하거나 요소의 서브 트리를 제거할 때 사용할 수 있습니다. 이 방법을 사용하여 트리에서 요소를 제거할 수는 없습니다. 제거된 요소는 새로 생성된 요소와 동일한 상태로 존재하며, 언제든지 다른 장소의 문서에 재 삽입할 수 있습니다. 스크립트 관점에서 보면 요소에 대한 참조가 더 이상 없을 경우 그 요소는 실제로 삭제된 것입니다.


한 단계 수준을 높여볼까요?

지금까지는 insertElement() 메서드를 사용하여 새로운 요소를 기존의 문서에 추가하는 방법에 관하여 알아 보았습니다. insertElement()는 요소를 재배치할 때 사용할 수도 있습니다. 이미 트리에 있는 요소에 대해서는 insertBefore()가 호출되며, 이 경우 해당 요소가 현재의 위치에서 제거되어 새로 지정된 장소로 자동적으로 이동합니다. 이것은 removeChild()를 호출한 다음 insertBefore()를 호출하는 것과 똑같은 결과입니다.

다음은 테이블 셀을 왼쪽으로 한 칸 이동시킬 때 사용하는 코드입니다.

function moveLeft() {
  var c, p, ls;
  if (lastSelection == null)
    return false;

  c = lastSelection;

  if (c.tagName != "TD") {
    return null;
  }

  ls = c.previousSibling;

  if (ls == null)
    return null;

  p = ls.parentElement;

  p.insertBefore(c, ls);

  return c;
}

특정 셀을 왼쪽으로 이동시키려면 단순히 셀의 앞에 삽입 기능을 사용하면 됩니다. 여러 셀들 사이를 이동하려면 두 개의 새로운 속성 previousSibling과 nextSibling을 사용합니다. moveRight() 메서드는 moveLeft()와 거의 비슷하지만, previousSibling 대신 nextSibling 속성을 사용합니다.

독자 여러분이 직접 연습해 보시기 바랍니다. MoveLeft()를 어떻게 구현해야만 테이블 행에도 사용이 가능할까요? 또한, 어떤 메서드가 moveLeft()와 moveUp()에 공통적으로 들어갈 수 있을까요?


편집 내용과 스타일 편집하기

필자가 처음 Lotus 1-2-3을 접했을 때, 가장 인상 깊었던 점은 값을 입력할 때마다 셀 안의 값이 즉시 업데이트된다는 것이었습니다. (그때가 1990년이었습니다.) 사실, 이 기능은 아직까지도 구현하기가 매우 어렵다고 말할 수 있습니다.


그러나, Internet Explorer 5의 새로운 기능을 이용하면 이 작업을 간단히 수행할 수 있습니다. 바로 Dynamic Properties의 three-liner가 그것입니다.

function editContents() {
  var c, p, nr;
  if (lastSelection == null)
    return false;

  c = lastSelection;

  if (c.tagName != "TD") {
    return null;
  }

  EditCell.style.display = "";

  EditCell.value = c.innerHTML;

  c.setExpression("innerHTML", "EditCell.value");

  EditCell.focus();

  EditCell.onblur = unhookContentsExpression;
}

function unhookContentsExpression() {
  lastSelection.removeExpression("innerHTML");
  EditCell.value = '';
  EditCell.style.display = "none";
}

Dynamic Properties를 사용하여 셀의 innerHTML 속성을 입력 값으로 정의할 수 있습니다. 입력 값이 변경되면, 셀의 내용도 자동적으로 변경됩니다. onblur 이벤트만 감시하면 되기 때문에 입력 값과 셀 내용 사이의 관계를 분리시킬 수도 있으며, 키 입력은 감시할 필요가 없습니다.


단추 활성화

서로 다른 종류의 요소를 선택할 경우 페이지 상단에 위치한 단추의 활성화/비활성화는 어떻게 이루어질까요? 이러한 유형의 작동은 유휴 루프 프로세스를 통해 이루어지거나, 응용 프로그램에서 상태가 변경된 모든 부분을 추적한 다음 활성화/비활성화 여부를 결정함으로써 이루어집니다. 상당히 복잡하지요. 그러나, Dynamic Properties를 사용하면 이 작업을 쉽게 수행할 수 있습니다.

ButtonAddRow.setExpression("disabled", "nothingSelected(lastSelection)");

ButtonMoveRight.setExpression("disabled",
"! cellSelected(lastSelection)");

ButtonEditContents.setExpression("disabled",
"(! cellSelected(lastSelection)) || (EditCell.style.display == '')");

ButtonEditStyle.setExpression("disabled",
"(EditStyle.style.display == '')");

ButtonEditStyle.setExpression("value",
"'Edit ' + whatIsSelected(lastSelection) + ' Style'");

필자는 nothingSelected(), cellSelected(), 그리고 rowSelected(), 이렇게 세 개의 헬퍼 메소드를 만들었습니다. Dynamic Property로서 단추 각각에 대한 비활성화 속성이 설정되므로, 단추가 비활성화 된 경우에만 식의 결과가 참이 됩니다. 예를 들어, "Move Right"는 셀에 대해서만 작용하기 때문에, 셀이 선택되지 않은 경우에는 단추가 비활성화 되어야 합니다.

lastSelection 속성은 이들 메서드 모두에 매개 변수로 전달됩니다. 이 속성은 식 안에서 참조되기 때문에 종속성이 설정됩니다. 즉, 속성이 변경될 때마다, 식이 다시 계산되는 것입니다. lastSelection이 코드 안의 어떤 부분에서 어떻게 변경되든, 모든 단추는 추가 코드나 오버헤드 없이 자동적으로 활성화되거나 비활성화 됩니다.


요약
위의 예제를 참고하면 HTML 테이블과 상호 작용하는 데 많이 도움이 될 것입니다. 의문사항이나 다음 달 칼럼에 대한 제안 사항이 있으시면 msdn@Microsoft.com으로 메일을 보내주십시오. 기꺼이 도와드리겠습니다. 그럼, 다음 달까지 안녕히 계십시오.

[출처] 빛남이

"쇼핑몰·홈페이지·오픈마켓
블로그·페이스북·이메일 등의 각종 마케팅 글쓰기,
각종 광고, 영업, 판매, 제안서, 전단지
반응율 3배×10배 이상 높이는 마법의 8단계 공식"
자세히보기

Comments

번호 제목 글쓴이 날짜 조회
2985 Table 태그 (2) 99 단국강토 02.09 2241
2984 테이블 응용 99 단국강토 02.09 2352
2983 프레임 tag-프레임(1) 99 단국강토 02.09 2150
2982 프레임(2) 99 단국강토 02.09 2147
2981 form tag-form (1) 99 단국강토 02.09 1991
2980 form(2) 99 단국강토 02.09 1802
2979 form-(4) 99 단국강토 02.09 2267
2978 아름다운글 올리는 방법 5 마퀴 태그 99 단국강토 02.09 2301
2977 이미지의 태그 처리 99 단국강토 02.09 2253
2976 글쓰기/FIELDSET source 99 단국강토 02.09 2531
2975 블로그 영상시, 나도 만들어 볼까? 99 단국강토 02.09 2292
열람중 동적 테이블 생성 DHTML 99 단국강토 02.09 2987
2973 table,tr,td 의 innerHTML 속성으로 좀 가꾸놀기 99 단국강토 02.09 3923
2972 CSS를 활용한 INPUT FORM의 커스트마이징 기법 99 단국강토 02.09 2887
2971 테이블 테두리를 가늘게 하는 확실한 팁 99 단국강토 02.09 2271
2970 스타일시트를 적용시키는 3가지 방법 99 단국강토 02.09 2059
2969 cursor:hand 을 cursor:pointer 로 교체요 ^^ 99 단국강토 02.09 2267
2968 ID attribute selector 99 단국강토 02.09 1496
2967 폼테그쓸때 테이블정렬이 잘안될때 쓰이는 css 99 단국강토 02.09 1602
2966 홈페이지 제작시 사용되는 CSS 정리 99 단국강토 02.09 1343
2965 부드럽게 펼쳐지는 콤보박스형 메뉴 99 단국강토 02.09 1674
2964 [CSS]스타일시트로 배경그림 고정시키기 99 단국강토 02.09 1677
2963 아이프레임 일부기능 대체할 수 있는 박스 99 단국강토 02.09 3230
2962 페이지 한개에서 모든것을 해결할 수 있는 탭메뉴 스크립트 99 단국강토 02.09 1407
2961 [CSS]글씨 크기-줄 간격 조절해서 보기 좋은 문서 만들기 99 단국강토 02.09 3309
2960 아이프레임 일부기능 대체할 수 있는 박스 99 단국강토 02.09 1309
2959 백그라운드 반복없이 한번만 넣기 99 단국강토 02.09 1862
2958 JAVASCRIPT + DOM 을 이용한 데이터 검색 99 단국강토 02.09 2785
2957 JAVASCRIPT + DOM 을 이용한 데이터 검색 99 단국강토 02.09 1962
2956 DOM 참조(JavaScript이용) 99 단국강토 02.09 1622
마케팅
특별 마케팅자료
다운로드 마케팅자료
창업,경영
기획,카피,상품전략
동기부여,성취