Extjs를 설치했다면 이제 sample등을 잘 활용하여 사용하기만 하면 된다.
ExtJs를 사용하기 위해서는 ExtJs의 기본 구조를 잘 이해해야 한다.
ExtJs는 Client Side Script인 javascript로 이루어진 Web 개발 library이다. 이 library가 공통으로 화면에 로딩되고 그 상태에서 사용자가 작성한 화면 script가 실행되는 형식이다. Sencha에서 제안하는 또 다른 방법은 extjs를 활용하여 화면 구성에 필요한 새로운 library를 생성하여 이를 배포하는 방식이다. script프로그램의 특성상 화면의 로딩 속도가 빨라야 하고 화면에 표시되는 부분(View)와 데이터를 처리하는 부분(Model)을 분리하여 코드의 재가용성도 높일수 있는 방법이다(MVC Model).
그러나 소규모의 개발에서는 오히려 사용이 어렵고 코드의 재가용성에 대한 요구가 높지 않은 경우 불필요한 작업까지 포함될 수 있고, 소스가 짧은 경우 로딩속도가(script언어의 특성상 개발시 포함된 space와 tab 문자들이 모두 소스에 포함되어 있어 파일 크기가 커진다) 크게 차이나지 않기 때문에 간단히 script-engine + script 방식으로 구성해도 충분한 것 같다.
사실 대부분의 web browser는 javascript(또는 vbscript)를 분석(compile)하고 실행하기 위한 엔진(gecko와 같은 레이아웃 엔진내에)을 탑재하고 있다. 여기에 낮은 레벨의 javascript와 style-sheet를 결합하여 매크로처럼 화면 구성용 함수들을 만들어 놓은 library가 ExtJs이므로 이를 그냥 가져다가 쉽게 사용하기만 하면 되니, 복잡하게 새로운 개발이나 대단위 프로젝트는 생각하지 않기로 했다.
대신 화면 개발시 유사한 화면에 반복적으로 포함되는 코딩을 조금 더 쉽게 처리하기 위한 방법을 고민하다 보니 오히려 Server side의 library가 더 적합하다는 생각을 하게 되었다.
우선 무작정 하드코딩으로 ExtJs를 이용한 page를 개발하기 위해서는 extjs library를 서버에 설치하고 이를 각 page가 로딩될 때 같이 로딩될 수 있도록 한다.
<meta http-equiv="X-UA-Compatible" content="IE=7"> <title>F-square</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="expires" content="0" /> <meta http-equiv="Cache-control" content="no-cache" /> <meta http-equiv="Cache-control" content="max-age=0" /> <meta http-equiv="pragma" content="no-cache" /> <!-- 적용된 테마 외에 추가적인 style정의를 모아 놓은 sheet --> <link rel="stylesheet" type="text/css" href="./design/css/menu_blue.css" media="screen" /> <!-- extjs 핵심 library --> <script type="text/javascript" src="./js/include-ext.js"></script> <script type="text/javascript" src="./js/options-toolbar.js"></script> <script type="text/javascript" src="./js/lib.js"></script>
디렉토리 구조는 각자가 설치하기 나름이므로 설치된 경로를 그대로 써 주면되겠다.
먼저 첫번째에 meta로 잔뜩 나오는 부분은 주로 web browser의 cache를 지워주기 위한 부분이다. 각 페이지 내용을 web browser가 cache(PC상에 임시저장)하고 있으면 개발 작업시 변경부분이 적용되지 않아 혼란을 줄 수 있다. 따라서 가급적 cache는 지워버리도록 하는 것이 좋다. 반대의 경우 static한 내용을 반복적으로 보여줘야 할 때는 cache되어 있는 것이 속도 면에서는 훨씬 유리하다.
이제 본격적으로 코딩을 시작해 보자.
ExtJs설치시 포함되어 있는 예제 파일을 하나씩 소스에 추가해서 실행시켜 보면서 그 구조를 파악하면 훨씬 쉽게 이해할 수 있다.
여기서는 FeedViewer Demo와 Tree, Tab을 이용하여 화면을 구성하고 내부 화면은 iframe으로 간단히 정보조회 화면을 구성하도록 하였다.
편집기는 Text Editor와 vi를 혼용하였고, 테스트는 Web brower로 직접 화면을 보면서 수정을 하였다(Subscription가입을 하지 않아 UI-Designer를 구하지는 못했다).
<script type="text/javascript"> Ext.onReady(function() { Ext.QuickTips.init(); var viewport = Ext.create('Ext.Viewport', { id: 'border-example', layout: 'border', items: [ // create instance immediately Ext.create('Ext.Component', { region: 'north', // 화면의 북쪽(윗쪽)에 위치 height: 58, // give north and south regions a height autoEl: { tag: 'div' } }), { // lazily created panel (xtype:'panel' is default) region: 'south', // 화면의 남쪽(아랫쪽)에 위치하는 panel contentEl: 'south', // div id='south'라고 하는 content를 overriding함 split: true, // 크기조정이 가능한 split height: 70, minSize: 100, maxSize: 200, collapsible: true, collapsed: true, title: 'Ticker', margins: '0 0 0 0' }, { region: 'west', // 화면의 서쪽(왼쪽)에 위치 stateId: 'navigation-panel', id: 'west-panel', // see Ext.getCmp() below title: 'Menu', split: true, // 크기조정이 가능한 split width: 200, minWidth: 175, maxWidth: 400, collapsible: true, // 닫힘 기능이 가능 animCollapse: true, // 닫힐때 애니메이션 적용 margins: '0 0 0 5', layout: 'accordion', // accordion layout으로 탭들이 존재 items: [{ // accordion layout으로 존재하는 탭의 아이템들 title: '즐겨찾기', xtype: 'treepanel', // tree panel object 생성 id: 'favorit', iconCls: 'nav', // style로 정의된 'nav' icon margins: '2 2 0 2', autoScroll: true, rootVisible: false, root: { text: "Root Node", // tree의 node의 정의 children:[ {text:'메뉴1', id: 'PMS_0001', leaf:true}, // 각각의 메뉴 {text:'메뉴100', id: 'PMS_0100', leaf:true} ] }, listeners: { itemclick : function(s,d){ // tree menu를 click 했을때의 action if ( d.data.leaf ) { var scr_id = "S" + d.data.id; var scr_title = d.data.text; var scr_filename = "PMS/SG" + d.data.id.trim() + "_SUB.php?theme=neptune"; // PMS디렉토리 내에있는 php파일명 생성 var tab = Ext.getCmp( scr_id ); var mainPanel = Ext.getCmp('MainPanel'); if ( tab != null ) { mainPanel.setActiveTab(tab); // 만약 이미 화면이 열려있으면 해당 화면을 activate시킴 } else { var tab = new Ext.Panel({ // 새로운 창에 화면을 open id: scr_id, title: scr_title, closable:true, autoScroll: false, border:false, layout:'fit', frame: false, html: '<iframe src="' + scr_filename + '" frameborder="no" allowtransparency="y" vspace="0" hspace="0" width="100%" height="100%"></iframe>' // iframe으로 tab 내에서 화면을 open함 }); mainPanel.add(tab); mainPanel.setActiveTab(tab); // tab을 add하고 activate함 } } // if ( d.data.leaf ) 의 끝 } // itemclick : function(s,d)의 끝 } // listener의 끝 }, { title: '자금관리', xtype: 'treepanel', id: 'Fund-manager', iconCls: 'info', margins: '2 2 0 2', autoScroll: true, rootVisible: false, root: { text: "Root Node", children:[ { text: '<b>메뉴1</b>', id: 'PMS_0001', leaf:true}, { text: '<b>메뉴2</b>', id: 'PMS_0002', leaf:true}, { text: '<b>메뉴100</b>', id: 'PMS_0100', leaf:true}, { text: '<b>메뉴200</b>', id: 'PMS_0200', leaf:true} ] }, listeners: { itemclick : function(s,d){ if ( d.data.leaf ) { var scr_id = "S" + d.data.id; var scr_title = d.data.text; var scr_filename = "PMS/SG" + d.data.id.trim() + "_SUB.php?theme=neptune"; var tab = Ext.getCmp( scr_id ); var mainPanel = Ext.getCmp('MainPanel'); if ( tab != null ) { mainPanel.setActiveTab(tab); } else { var tab = new Ext.Panel({ id: scr_id, title: scr_title, closable:true, autoScroll: false, border:false, layout:'fit', frame: false, html: '<iframe src="' + scr_filename + '" frameborder="no" allowtransparency="y" vspace="0" hspace="0" width="100%" height="100%"></iframe>' }); mainPanel.add(tab); mainPanel.setActiveTab(tab); } } // if ( d.data.leaf ) 의 끝 } // itemclick : function(s,d)의 끝 } // listener의 끝 }, { title: '환경설정', xtype: 'treepanel', id: 'tree-config', iconCls: 'settings', margins: '2 2 0 2', autoScroll: true, rootVisible: false, root: { text: "Root Node", children:[ {text:'즐겨찾기 설정', id: 'CFG_1000', leaf:true}, {text:'화면 설정', id: 'CFG_2000', leaf:true} ] }, listeners: { itemclick : function(s,d){ if ( d.data.leaf ) { var scr_id = "S" + d.data.id; var scr_title = d.data.text; var scr_filename = "CFG/S" + d.data.id.trim() + ".php?theme=neptune"; var tab = Ext.getCmp( scr_id ); var mainPanel = Ext.getCmp('MainPanel'); if ( tab != null ) { mainPanel.setActiveTab(tab); } else { var tab = new Ext.Panel({ id: scr_id, title: scr_title, closable:true, autoScroll: false, border:false, layout:'fit', frame: false, html: '<iframe src="' + scr_filename + '" frameborder="no" allowtransparency="y" vspace="0" hspace="0" width="100%" height="100%"></iframe>' }); mainPanel.add(tab); mainPanel.setActiveTab(tab); } } } } } ] }, Ext.create('Ext.tab.Panel', { // 화면의 가운데 tab panel생성 (mainpanel이라고 명명) region: 'center', // a center region is ALWAYS required for border layout deferredRender: false, bodyStyle: 'background-size:contain; background-image:url(http://www.nyewall.com/images/2013/07/background-flowers-sky-wallpaper-blue-nice-wallpapers.jpg);', id: 'MainPanel', activeTab: 0 // first tab initially active })] }); // get a reference to the HTML element with id "hideit" and add a click listener to it Ext.get("hide-it").on('click', function(){ var w = Ext.getCmp('west-panel'); w.collapsed ? w.expand() : w.collapse(); }); }); </script> <body bgcolor="#F0F0FF" /* onload=reqeustFullScreen();*/> <table width=100% border=0 cellpadding=0 cellspacing=0 > <tr><td align=left width=145 class="logo">AMS</td><td align=left class="logo"></td></tr> <tr><td align=left width=145 class="logo_under"> Management System</td><td class="logo_under">- AMS Consulting</td></tr> </table> <!-- use class="x-hide-display" to prevent a brief flicker of the content --> <div id="west" class="x-hide-display"> <p>west panel</p> </div> <div id="center2" class="x-hide-display"> <a id="hide-it" href="#"> </div> <div id="center1" class="x-hide-display"> </div> </div> <div id="south" class="x-hide-display"> <p>정상상태</p> </div> <br/>
이제 해당 library와 style sheet가 적절한 경로에 설치만 되어 있다면 첫번째 메인 화면이 정상적으로 뜰 것이다.
이제 메인화면을 생성했고 앞으로 해야할 파일은 각 메뉴를 클릭했을 때 iframe상에 뜰 각각의 화면 파일을 생성하는 일만 남았다.
그런데 메인화면을 자세히 보면 반복적인 부분들이 보일것이다. 즉, tree menu가 즐겨찾기, 화면메뉴, 환경설정 등과 같이 동일한 형태의 자료구조로 반복되는 것을 볼 수 있는데 이러한 부분을 모두 Hard coding으로 fix하지 말고 서버측에서 동적으로 DB를 조회하여 생성하면 반복작업이 훨씬 줄어들 것이다.
index.php <header> ... <script type="text/javascript"> ... <? include 'lib/db.php'; // db 조회시작 .... // 조회 결과를 출력 ... while ( $rs = mssql.next() ) { if ($row_cnt > 0 ) echo ",\n"; echo "{ text : '" . $rs.getString(1) . "', id : " . $rs.getString(2) . ", leaf : " . $rs.getString(5) . "}"; $row_cnt ++; } ?> } ]