核心提示:Intraweb一直是Delphi快速開發(fā)web應(yīng)用的首選工具,但自帶的控件較少,樣式比較難看,TMS與IW倒是可用,可是要收費,對于我們這些習(xí)慣用免費的用戶來說,想找個破解也比較費勁。EasyUI是基于JQuery開發(fā)的框架,內(nèi)置的控件完全可以滿足我們開發(fā)一般web程序的需求,而且是免費的,用起來...
Intraweb一直是Delphi快速開發(fā)web應(yīng)用的首選工具,但自帶的控件較少,樣式比較難看,TMS與IW倒是可用,可是要收費,對于我們這些習(xí)慣用免費的用戶來說,想找個破解也比較費勁。EasyUI是基于JQuery開發(fā)的框架,內(nèi)置的控件完全可以滿足我們開發(fā)一般web程序的需求,而且是免費的,用起來也心安理得。下面我就IW如何結(jié)合EasyUI開發(fā)程序談?wù)勛约旱囊恍┬牡?,與大家交流一下。主要有以下幾種方法:
一、使用模板
在IWForm內(nèi)使用模板引入做好的html文件,結(jié)合IW自身的控件進行操控。這種方法雖說比較方便,但模板也有自身的缺點,內(nèi)部不支持中文引用是一大Bug,目前IW都沒有要解決的跡像。如果一定要用模板,也有方法規(guī)避,即漢字全部用網(wǎng)頁轉(zhuǎn)義“&#”加漢字的十進制編碼。模板的使用有很多文章可供參考,也不是本章的重點,不做具體講解。
二、MVC設(shè)計模式
IW使用MVC方式結(jié)合EasyUI設(shè)計程序,是本文的重點。我們知道IW與HTML靜態(tài)頁面的交互,可以通過javascript接口來實現(xiàn),可以使用AddToInitProc('alert("歡迎")')這樣的語句,也可以在控件的JavascriptEvent屬性內(nèi)添加js語句。本文介紹的方法完全將界面與數(shù)據(jù)處理分開,一律使用EasyUI來實現(xiàn)界面(完全不用IW的可視控件,數(shù)據(jù)庫控件還是需要的),數(shù)據(jù)處理交給IW后臺做。我們以開發(fā)一個簡單的應(yīng)用程序來一步步實現(xiàn)這些功能,同時會使用一定篇幅介紹EasyUI部分控件的使用(本文必須要有一定的javascript基礎(chǔ))。
第一步:實現(xiàn)登陸界面。
首先引入以下文件,后面其它頁面也一樣這樣引用,直接貼代碼:
- <span style="white-space:pre"> </span><link rel="stylesheet" type="text/css" href="easyui/themes/default/easyui.css">
- <link rel="stylesheet" type="text/css" href="easyui/themes/icon.css">
- <script type="text/javascript" src="easyui/jquery.min.js"></script>
- <script type="text/javascript" src="easyui/jquery.easyui.min.js"></script>
- <script type="text/javascript" src="easyui/locale/easyui-lang-zh_CN.js"></script>
這些文件是必須引用的,easyui.css是自帶的樣式,icon.css是使用中的各種圖標(biāo),easyui-lang-zh_CN.js是漢化文件(EasyUI對中文支持還是很不錯的,如果覺得漢化得不夠好,可以打開這個文件自行修改)。界面部分:
- <form id="ff" class="easyui-form" method="post" data-options="novalidate:true">
- <!--form提供了各種方法來操作執(zhí)行表單字段,比如:ajax提交, load, clear等等。當(dāng)提交表單的時候可以調(diào)用validate方法檢查表單是否有效。
- “data-options”控件的各種屬性,form有以下屬性:
- 屬性名 類型 描述 默認(rèn)值
- novalidate boolean 定義是否驗證表單的字段,true:驗證,false:不驗證。 false
- ajax boolean 定義是否使用ajax提交表單,true:使用,false:不使用。 true
- queryParams object 當(dāng)表單被提交到服務(wù)器的時候增加的額外參數(shù)列表。 {}
- url string 提交表單動作的URL地址 null
- -->
- <table cellpadding="5">
- <tr>
- <td>用戶名:</td>
- <td><input class="easyui-textbox" type="text" name="username" data-options="required:true" style="width:150px"/></td>
- <!--
- TextBox(文本框)是一個增強的輸入字段組件, 它允許用戶非常簡單的創(chuàng)建一組表單。它是一個用于構(gòu)建其他組合控件的基礎(chǔ)組件,如:combo,databox、spinner等
- required:true表示文本框不能為空,下同。
- -->
- </tr>
- <tr>
- <td>密 碼:</td>
- <td><input class="easyui-textbox" type="password" name="passw" data-options="required:true" style="width:150px"/></td>
- </tr>
- </table>
- </form>
- <div style="width:216px;padding:5px 0px;height:30px">
- <a href="javascript:void(0)" class="easyui-linkbutton" onclick="submitForm()" style="width:80px;float:left">登陸</a>
- <!--easyui-linkbutton按鈕組件,使用超鏈接按鈕創(chuàng)建,提示:不要將它改為button類別,IE9以下瀏覽器會不正常,submitForm()提交數(shù)據(jù),clearForm()清空數(shù)據(jù)-->
- <a href="javascript:void(0)" class="easyui-linkbutton" onclick="clearForm()" style="width:80px;float:right">取消</a>
- </div>
- </div>
- </div>
登陸界面基本完成,有些簡陋,當(dāng)然可以自行修改。下面實現(xiàn)提交數(shù)據(jù)和清空數(shù)據(jù),用Javascript:
- function submitForm(){
- $('#ff').form('submit',{//這是EasyUI的Form自帶功能,就是提交數(shù)據(jù)
- url:'Login.php', //需要把數(shù)據(jù)提交到的頁面
- onSubmit:function(){//驗證數(shù)據(jù)是否為空,如果為空就返回。
- return $(this).form('enableValidation').form('validate');
- },
- success: function(data){
- //提交成功后的回調(diào)函數(shù),data就是返回的數(shù)據(jù)
- if(parseInt(data)==1)
- //我們在這里返回1和0,1表示成功登陸,在后臺實現(xiàn)
- {
- window.location='main.html';
- //登陸成功后,跳轉(zhuǎn)到主程序
- }
- else
- {
- $.messager.alert('錯誤','用戶名或密碼錯誤!','error');
- /*EasyUI消息提示框,就是alert的改進用法,顯示警告窗口。
- 參數(shù)(依次調(diào)用):
- title:在頭部面板顯示的標(biāo)題文本。
- msg:顯示的消息文本。
- icon:顯示的圖標(biāo)圖像??捎弥涤校篹rror,question,info,warning。
- fn: 在窗口關(guān)閉的時候觸發(fā)該回調(diào)函數(shù)。 */
- $('#ff').form('clear');//清空數(shù)據(jù),下同。
- }
- }
-
-
- });
- }
- function clearForm(){
- $('#ff').form('clear');
- }
文件另存為“index.html”,即首頁,放在wwwroot下(注意easyui的相關(guān)文件也要放在這個目錄下),啟動程序后,就是直接訪問這個頁面了,沒有“$”這個標(biāo)志。
登陸界面基本完成,數(shù)據(jù)需要提交到“Login.php”這個頁面,按一般的做的法,新建一個IWForm,使用模板加載文件,本文用另一種思路,也是本文的關(guān)鍵:
用delphi新建一個Unit,命名Login單元,加入IW工程。
直接貼出代碼(參考萬一博客):
- {新建Login 單元, 從 TContentBase 繼承實現(xiàn)一個 TLogin 類}
- unit Login;
-
- interface
- uses Classes, IW.Content.Base, System.SysUtils,HTTPApp, IWApplication, IW.HTTP.Request, IW.HTTP.Reply, IWMimeTypes;
-
-
- type
- TLogin = class(TContentBase)
- protected
- function Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean; override;
- public
- constructor Create; override;
- end;
-
- implementation
- uses ServerController,UserSessionUnit;
- { TLogin }
-
- constructor TLogin.Create;
- begin
- inherited;
- mFileMustExist := False;
- end;
-
- function TLogin.Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean;
- begin
- aReply.ContentType := MIME_HTML;
- aReply.WriteString('這里就是返回到客戶端的數(shù)據(jù)');
- Result := True;
- end;
-
- end.
-
- {在 IWServerControllerBase.OnConfig 映射login.php}
- uses
- IWInit, IWGlobal, IW.Content.Handlers, Login;
-
- procedure TIWServerController.IWServerControllerBaseConfig(Sender: TObject);
- begin
- THandlers.Add('', 'login.php', TLogin.Create);
- //添加虛擬文件名,映射到服務(wù)器
- end;
直接列出代碼大家可以不太清楚怎么回事,這里說明一下流程:
客戶端通過Form提交用戶名和密碼到“Login.php”,“Login.php”是通過服務(wù)器添加的一個虛擬文件,映射到從TContentBase繼承實現(xiàn)的TLogin類,用THttpRequest接收提交的數(shù)據(jù),并進行處理,用THttpReply.writestring寫入返回客戶端數(shù)據(jù)。這樣登陸過程前臺與后臺代碼均完成。
第二步:實現(xiàn)主界面
我們開發(fā)的是一個商品信息管理程序,主界面用EasyUI的Layout實現(xiàn)自適應(yīng)瀏覽器(記得引入相關(guān)js和css):
- <div data-options="region:'north',border:false" style="height:60px;background:#B3DFDA;padding:0px 10px;text-align:center">
- <h3>商品信息管理系統(tǒng)</h3>
- </div>
- <div data-options="region:'west',split:true,title:'商品分類'" style="width:200px;padding:10px;">
-
- </div>
- <!--<div data-options="region:'east',split:true,collapsed:true,title:'East'" style="width:100px;padding:10px;">east region</div>-->
- <div data-options="region:'south',border:false" style="height:50px;background:#A9FACD;padding:10px;">
- 京ICP證000000號
- </div>
- <div data-options="region:'center',title:'商品簡要信息'">
-
- </div>
很好理解,即左西右東,上北下南加上中央的布局,右邊不需要,我把它注釋掉。
頁面設(shè)計思路是這樣的,左邊放一個Tree,用來顯示商品分類,中央放GridData,用來顯示商品信息列表,通過兩個控件實現(xiàn)刪除、添加、修改功能。
west這個DIV內(nèi)加入Tree:
- <ul id="easyui_tt" class="easyui-tree"
- data-options="
- animate:true,//動畫
- lines:true,//顯示樹線
- url:'Treedata.php',//上面有解釋,需要提交的頁面
- method:'post',//提交方式Post,再強調(diào)一下必須用Post
- onClick: function(node){//鼠標(biāo)單擊事件
- QueryByID(node.id);//通過node.id來查詢數(shù)據(jù),講DataGrid時再說
- },
- onContextMenu: function(e, node){//右鍵菜單
- e.preventDefault();//必須用的
- $(this).tree('select', node.target);//選擇的Node
- $('#mm').menu('show', {//EasyUI的菜單,非常簡單
- left: e.pageX,//彈出菜單的位置
- top: e.pageY
- });
- }">
- </ul>
Tree的屬性很多,其中一個比較重要的是node,即Tree的節(jié)點每個節(jié)點都具備以下屬性:
id:節(jié)點ID,對加載遠(yuǎn)程數(shù)據(jù)很重要。
text:顯示節(jié)點文本。
state:節(jié)點狀態(tài),'open' 或 'closed',默認(rèn):'open'。
如果為'closed'的時候,將不自動展開該節(jié)點。
checked:表示該節(jié)點是否被選中。
attributes: 被添加到節(jié)點的自定義屬性。
children: 一個節(jié)點數(shù)組聲明了若干節(jié)點
Tree的節(jié)點是通過url提交請求到服務(wù)器接收返回數(shù)據(jù)加載的,形成
樹的數(shù)據(jù)是JSon格式,我們可以分析一下:
- [{
- "id": 1,//對應(yīng)node的ID,其他也是一一對應(yīng)的
- "text": "Node 1",
- "state": "closed",
- "children": [{ //子node
- "id": 11,
- "text": "Node 11"
- },{
- "id": 12,
- "text": "Node 12"
- }]
- },{
- "id": 2,
- "text": "Node 2",
- "state": "closed" //不展開節(jié)點
- }]}
同上面的“登陸”,我們從TContentBase繼承實現(xiàn)一個 TTreeData 類直接復(fù)制模板,修改一個即可,注意加入IW工程,并在ServerController內(nèi)映射“TreeData.php”。我們現(xiàn)在需要通過delphi來實現(xiàn)樹,Tree的層越多就越復(fù)雜,我發(fā)現(xiàn)
不管通過什么語言動態(tài)實現(xiàn)Tree,都是非常麻煩的一件事,EasyUI的例子只能實現(xiàn)兩層樹。從數(shù)據(jù)庫讀取Tree數(shù)據(jù),在數(shù)據(jù)庫設(shè)計的時候有一個技巧,不知道大家是怎樣處理的,我這里說一個我的方法:樹的上下級之間用代碼表示,2位數(shù)字代表根,4位數(shù)字代表下一級,依此類推,代碼不能用純數(shù)字,這樣不好排序,我在數(shù)字前加個字母,這樣通過“select*from Tree order by id”就可以把上下級排列在一起,而不是按代碼大小排序。數(shù)據(jù)庫就不多講了,不在本文的范圍,大家看一下我的源碼里的數(shù)據(jù)庫就知道了。建樹代碼如下(本想用JSon,無奈學(xué)不到家,只能用字符串拼接):
- function BuildTree:string;
- var
- i,j,old_ln,new_ln:Integer;
- id,s,title,ft:string;
- begin
- ft:='{"id":"%s","text":"%s"},';//Json格式
- with UserSession.FDQuery1 do
- begin
- Open('select*from Tree order by id'); //按id排序可以將父子節(jié)點正好羅列在一起
- s:='[';
- old_ln:=0;//初始化開始節(jié)點ID的長度
- for i := 0 to RecordCount-1 do
- begin
- id:=Fields.Fields[0].AsString;
- title:=Fields.Fields[1].AsString;
- new_ln:=id.Length-3;//新節(jié)點ID的長度,減去3除去了根節(jié)點的長度,方便計算
- //通過比較與上一節(jié)點ID的長度來判斷節(jié)點的上下級關(guān)系
- if (new_ln=old_ln) then//與上一節(jié)點同等級
- s:=s+Format(ft,[id,title]);
- if new_ln>old_ln then //上一節(jié)點為父節(jié)點
- begin
- s:=s.Substring(0,s.Length-2);
- s:=s+Format(',"state":"closed","children":['+ft,[id,title]);
- end;
- if (new_ln<old_ln) then //上一節(jié)點為子節(jié)點
- begin
- s:=s.Substring(0,s.Length-1);
- for j :=1 to (old_ln-new_ln) div 2 do
- s:=s+']}';
- s:=s+Format(','+ft,[id,title]);
- end;
- Next;
- old_ln:=new_ln;//將當(dāng)前節(jié)點ID長度賦予舊節(jié)點
- end;
- end;
- s:=s.Substring(0,s.Length-1);
- for i := 1 to new_ln div 2 do //結(jié)束時需要判斷是否為子節(jié)點,有幾層
- s:=s+']}';
- result:=s+']';
- end;
以上代碼已經(jīng)注釋,有什么不明白的地方我們再交流,可以實現(xiàn)N多級樹,只要客戶端支持,有的控件是不支持多級樹的。Tree實現(xiàn)了,我們再實現(xiàn)右鍵菜單,onContextMenu:
- onContextMenu: function(e, node){
- e.preventDefault();
- $(this).tree('select', node.target);
- $('#mm').menu('show', {
- left: e.pageX,
- top: e.pageY
- });
注意$('#mm')這個就是右鍵菜單的JQuery標(biāo)識,我們做一個刪除、添加功能,代碼如下:
- <div id="mm" class="easyui-menu" style="width:120px;">
- <div onclick="addnode()" data-options="iconCls:'icon-add'">添加</div>
- <div onclick="removeit()" data-options="iconCls:'icon-remove'">刪除</div>
- </div>
提示:EasyUI很多情況下只需要引用$('')類似的標(biāo)識就可以將其他控件加進去。實現(xiàn)addnode()、removeit()以及其他功能:
- <span style="white-space:pre"> </span>function appendn(r){//添加節(jié)點
- var t = $('#easyui_tt');
- var node =t.tree('getSelected');
- var pii=node.id;
- $.ajax({
- type : "post",
- url : "Treedata.php",
- data : {Action:'Add',ID:pii,Title:r},
- async : false,//這里必須用同步
- success : function(data){
- pii=data;
- }
- });
- t.tree('append', {
- parent: (node?node.target:null),
- data: [{id:pii,text:r}]
- });
- }
- function removeit(){//刪除節(jié)點
- var node = $('#easyui_tt').tree('getSelected');
- var pii=node.id;
- $.post('Treedata.php',{Action:'Del',ID:pii});
- $('#easyui_tt').tree('remove', node.target);
- }
- function collapse(){//樹折疊
- var node = $('#easyui_tt').tree('getSelected');
- $('#easyui_tt').tree('collapse',node.target);
- }
- function expand(){//樹展開
- var node = $('#easyui_tt').tree('getSelected');
- $('#easyui_tt').tree('expand',node.target);
- }
- function addnode(){//彈出添加節(jié)點對話框,用消息框
- $.messager.prompt('添加', '請輸入需要添加的名稱:', function(r){
- if (r){
- appendn(r);
- }
- });
- }
這段代碼是用JQuery實現(xiàn)向IW提交數(shù)據(jù),即把data以JSon格式提交到服務(wù)器$.post('Treedata.php',{Action:'Del',ID:pii});提交刪除功能,是$.ajax的簡單實現(xiàn),順便說一下,萬一的博客提到
- function TestPost(){
- var mydata="TestMYPost測試一下";
- executeAjaxEvent("&data="+mydata, null, "DoCallBack1", false, null, false);
- //中文在IE下亂碼
- }
這樣提交數(shù)據(jù),用WebApplication.RegisterCallBack('IWCallBack1', DoCallBack1) 注冊回調(diào)接收數(shù)據(jù),我覺得用JQuery的post實現(xiàn)更簡單,IWForm內(nèi)用$.post需要這樣:
- $.post(GURLBase+"callback?",
- {callback:"DoCallBack1",data:"測試一下可以嗎-----?"},
- function(data){processAjaxResponse(data);},"xml");//必須是xml格式
- }//效果是一樣的,也需要注冊回調(diào)函數(shù)
注:GURLBase等于'/$/'(看著非常不爽的美元符號),修改一下萬一的代碼:
- function TestPost(){
- var mydata=escape("TestMYPost測試一下");
- executeAjaxEvent("&data="+mydata, null, "DoCallBack1", false, null, false);//中文在IE下亂碼,需要escape
- }
這樣也支持中文了。
服務(wù)器如何處理數(shù)據(jù),登陸界面已經(jīng)詳解,基本類似,添加刪除也不再列代碼,大家可以直接看我的源碼,用delphi實現(xiàn)真的很簡易。
Tree講完,我們接著講DataGrid:
center這個DIV內(nèi)加入:
- <table class="easyui-datagrid" style="width:100%;height:400px"
- data-options="singleSelect:true,collapsible:true,fitColumns:true,url:'GridData.php',
- method:'post',pageSize:10,pagination:true,onDblClickRow:onDClickRow"
- <!--
- 相同的屬性不再說明,
- singleSelect選擇單行
- collapsible定義是否顯示可折疊按鈕,EasyUI大部分控件繼承自panel,一般可折疊
- fitColumns列寬自適應(yīng)
- pageSize分頁時每頁顯示的行數(shù)
- pagination是否分布
- -->
- toolbar="#dg_tb"//工具欄,EasyUI可以這種方式嵌入其他控件
- id="easyui_tb">
- <thead><!--頭部-->
- <tr>
- <th data-options="field:'codeID',width:80,halign:'center',editor:'text'">商品編號</th>
- <!--field對應(yīng)數(shù)據(jù)庫字段
- halign標(biāo)題居中
- editor:'text'編輯樣式為文本框
- align:'center'整列居中
- -->
- <th data-options="field:'p_name',width:100,halign:'center',editor:'text'">名稱</th>
- <th data-options="field:'p_type',width:80,halign:'center',align:'center',editor:'text'">型號</th>
- <th data-options="field:'p_tid',width:80,halign:'center',align:'center',editor:'text'">類別</th>
- <th data-options="field:'p_pinpai',halign:'center',width:250,editor:'text'">品牌</th>
- <th data-options="field:'p_price',halign:'center',width:60,align:'center',editor:'text'">價格</th>
- <th data-options="field:'p_discount',halign:'center',width:60,align:'center',editor:'text'">折扣</th>
- </tr>
- </thead>
- </table>
- <div id="dg_tb" style="padding:3px"><!--工具欄-->
- <span>商品編號</span>
- <input id="codeID" class="easyui-numberbox" style="line-height:22px;border:1px solid #ccc">
- <span>商品名稱</span>
- <input id="p_name" class="easyui-textbox" style="line-height:22px;border:1px solid #ccc">
- <a href="#" class="easyui-linkbutton" plain="true" onclick="doSearch()">查詢</a>
- <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="appendr();">添加</a>
- <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="remover()">刪除</a>
- <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-save',plain:true" onclick="acceptr()">修改</a>
- <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-undo',plain:true" onclick="rejectr()">撤消</a>
- </div>
DataGrid功能強大,也很復(fù)雜,本文只講基本應(yīng)用,大家可以看我上傳的EasyUI幫助文件。從服務(wù)器端獲取表格數(shù)據(jù)同上,數(shù)據(jù)也是JSon格式的,建一個MyGridData,上面講Tree時留下一下函數(shù)未講解QueryByID(node.id),JS如下:
- function QueryByID(id){//以節(jié)點ID查詢
- var tb=$('#easyui_tb');
- tb.datagrid({queryParams:{Action:'Q_ID',ID:id}});
- /*queryParams是DataGrid提交數(shù)據(jù)時的參數(shù),
- 也可以直接:tb.datagrid('load',:{Action:'Q_ID',ID:id}});
- 但是在測試中發(fā)現(xiàn),這樣提交后數(shù)據(jù)為空時,表仍然顯示有數(shù)據(jù),
- 也許是Bug,也許是我不會用。load即是post數(shù)據(jù)到服務(wù)器,同時
- 接收返回數(shù)據(jù),GridData全部封閉好了。
- */
- tb.datagrid('load');
- }
以ID查詢數(shù)據(jù)在服務(wù)器端這樣實現(xiàn):
- function QueryData(config:string):string;
- var
- arrjson:JSONArray;
- ajson:JSONObject;
- i,j:integer;
- begin
- arrjson:=JSONArray.Create;
- ajson:=JSONObject.Create;
- with UserSession.FDQuery1 do
- begin
- Open('select*from product where '+config);
- for I :=0 to RecordCount-1 do
- begin
- for j := 0 to Fields.Count-1 do
- ajson.Put(Fields.Fields[j].DisplayName,Fields.Fields[j].AsString);
- //形成'{aaa:"BBB",ccc:"DDDD"}'這樣的字符串,不需要拼接字符串了。
- arrjson.AddJSON(ajson.ToString(4));
- //字面上理解就是JSon數(shù)組,即[{},{}];
- ajson.Clear;
- //清除ajson內(nèi)的數(shù)據(jù),不然ajson會不停put數(shù)據(jù),類似js的push用法
- Next;
- end;
-
-
- end;
- Result:='{"total":'+i.ToString+',"rows":'+arrjson.ToString(4)+'}';
- //ToString(4)表示以4個空格縮進,不這樣使用json數(shù)據(jù)會被轉(zhuǎn)義
- //datagrid數(shù)據(jù)多出的total是分頁時用到的,表示總行數(shù),rows表示當(dāng)前顯示頁面
- //如果不分頁,可以直接: Result:=arrjson.ToString(4)';
- arrjson.Free;
- ajson.Free;
-
- end;
我是直接以查詢條件為參數(shù)的,以便于擴展,這里用到了yxdJson,在我上傳的控件中有,比較好用,其實就是形成'{aaa:"BBB",ccc:"DDDD"}'這樣的語句,特別簡潔,不用拼接字符串(拼接字符串是很痛苦的)。Tree的數(shù)據(jù)我也想用的,但死活不行,只好放棄。GridData是用服務(wù)器實現(xiàn)分頁的,也特簡單,即提交page和rows這個兩個參數(shù)到服務(wù)器,代碼大家自已下載,delphi實現(xiàn)也非常簡單,sql查詢時加入limit (page-1)*rows,rows條件即可。注意字符串與整數(shù)的變換。實現(xiàn)查詢、刪除、添加、修改功能,客戶端js:
- function doSearch(){//查詢功能
- $('#easyui_tb').datagrid('load',{
- Action:'Q_DN',
- id: $('#codeID').val(),
- p_name: $('#p_name').val()
- });}//load參數(shù)即可,上面有講解
- var editIndex = undefined;
- var ExecType='';
- function endEditing(){//結(jié)束編輯
- if (editIndex == undefined){return true}
- if ($('#easyui_tb').datagrid('validateRow', editIndex)){
- var ed = $('#easyui_tb').datagrid('getEditor', {index:editIndex,field:'codeID'});
- $('#easyui_tb').datagrid('endEdit', editIndex);
- editIndex = undefined;
- return true;
- } else {
- return false;
- }
- }
- function onDClickRow(index){//雙擊編輯整行數(shù)據(jù)
- if (editIndex != index){
- if (endEditing()){
- var tt=$('#easyui_tb').datagrid('selectRow', index);
- var EditID=tt.datagrid('getSelected')['codeID'];//選擇行的codeID值
- tt.datagrid('beginEdit', index);
- editIndex = index;
- ExecType='update,'+EditID;//提交到服務(wù)器update
- } else {
- $('#easyui_tb').datagrid('selectRow', editIndex);
- //數(shù)據(jù)庫必須依靠主鍵為標(biāo)志來更新。
- }
- }
- }
- function appendr(){//添加
- if (endEditing()){
- $('#easyui_tb').datagrid('appendRow',{p_discount:'1.0'});
- editIndex = $('#easyui_tb').datagrid('getRows').length-1;
- $('#easyui_tb').datagrid('selectRow', editIndex)
- .datagrid('beginEdit', editIndex);
- //添加一行空行
- ExecType='insert into,';//提交到服務(wù)器insert
- }
- }
- function remover(){//刪除
- var tt=$('#easyui_tb').datagrid('getSelected');//找到選擇行
- if (tt==undefined) return;
- //沒有選擇就退出
- var Delindex=$('#easyui_tb').datagrid('getRowIndex',tt);
- //選擇行的行號
- var DelID=tt['codeID'];//主鍵,用于刪除
- $.messager.confirm('刪除','您確認(rèn)想要刪除記錄嗎?',
- function(r){ if (r){
- $('#easyui_tb').datagrid('deleteRow', Delindex);
- $.post('GridData.php',{Action:'delete',id:DelID});
- //提交delete
- }});
- editIndex = undefined;//這個本程序沒用上,是單擊時用的
- }
- function acceptr(){//修改編輯的數(shù)據(jù),添加或編輯后,需要修改數(shù)據(jù),提交到服務(wù)器
- //不修改只是客戶端更新,服務(wù)器端數(shù)據(jù)庫沒變
- if (endEditing()){
- $('#easyui_tb').datagrid('acceptChanges');
- if (ExecType=='') return;
- var selrow=$('#easyui_tb').datagrid('getSelected');
- var row=new Array();
- if(selrow!=undefined)
- row.push(selrow['codeID'],selrow['p_name'],selrow['p_type'],selrow['p_tid'],
- selrow['p_pinpai'],selrow['p_price'],selrow['p_discount']);
- //push就是將數(shù)據(jù)壓入數(shù)組
- var param=ExecType.split(',');//分割字符串為數(shù)組,delphi的用法類似
- if(param[0]=='update')
- {
- $.post('GridData.php',{Action:param[0],id:param[1],Rowdata:row.toString()},function(data){alert(data)});
- //update時要提交動作、codeID和更新后的數(shù)據(jù),
- //post的參數(shù)function(data){alert(data)就是服務(wù)器返回數(shù)據(jù)。
- }
- if(param[0]=='insert into')
- {
- $.post('GridData.php',{Action:param[0],Rowdata:row.toString()},function(data){alert(data)});
- //insert時要提交動作和插入后的數(shù)據(jù)
- }
- ExecType='';
- }
- }
- function rejectr(){//取消
- $('#easyui_tb').datagrid('rejectChanges');
- ExecType='';
- editIndex = undefined;
- }
- function getChanges(){
- var rows = $('#easyui_tb').datagrid('getChanges');
- return rows;
- }
服務(wù)器實現(xiàn)這些功能用下面這個函數(shù):
function Exec_SQL(act,id,row:string):string;
源碼自己去看,很簡單,就是操作數(shù)據(jù)庫。本文基本完成,最后講一下這種方式未完成的功能:直接使用http://xxx.xxx.xxx/main.html可以不用登陸就能進入主界面,顯然不是我們所期望的,可以在主界面加入驗證登陸的功能,也很簡單,可以在頁面加載之前$.post提交驗證信息到login.php,里面代碼已經(jīng)寫了,只是客戶端沒有添加。還有第三大點。
三、動態(tài)加載
動態(tài)加載簡單說就是,客戶端還是單獨做出來,不用放在wwwroot下面,引用js和css時需要在路徑前面多加一個“/”即可。仍然從TContentBase 繼承實現(xiàn)一個類,在函數(shù)中這樣實現(xiàn) :
- function TMyIndex.Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean;
- var
- ss:Tstrings;
- begin
- aReply.ContentType := MIME_HTML;
- ss:=TstringList.create;
- ss.loadformfile('做好靜態(tài)頁面');
- aReply.WriteString(ss.text);
- ss.free;
- Result := True;
- end;
這樣顯而易見是比較安全的,可以在加載主界面前先驗證有無登陸,還可以在加載頁面中加一些類似模板替換標(biāo)識,動態(tài)加載時,將這些標(biāo)識替換成本頁面需要展示的內(nèi)容,實現(xiàn)header、body、footer共用。
本文所需要工具:delphiXE7+Intraweb 14.0.38