這是一篇關於easyui配合ajax使用的文章,順帶介紹angularjs的使用以及讓你感受到angularjs的威力。網路上對於ajax 的文字也是多如牛毛 。我就不會直接從那種原生的httpxmlrequest 物件的js 寫起了哈。看那種東西也存粹是了解 高層的東西是怎麼來的 原理是啥真正做的時候寫那種東西 不是扯淡麼 你叼你技術牛逼整站的代碼你全用那種寫。 html js 這種東西一開始設計出來就沒考慮周全就是坨屎。還好現在有各種框架 可以幫助我們更容易的把這坨屎做的更美味。也還好由於網路事業如日中天 的推動 讓瀏覽器端的這堆東西正在往統一規範的方向發展。
我們來建立一個webform頁面 HelloAjaxNet.aspx。先說下ajax 這裡我使用網路上流傳甚廣的那個AjaxPro.2.dll 他的網站是 http://www.ajaxpro.info/ 這是一個個人作品 ,很好用。
原本新的asp.net 裡自帶了服務端方法用webmethod 屬性宣告 用戶端pagemethods存取的方式 ,各種物件也可以json資料化 ,功能跟上面一樣的。微軟自備的是aspx的codebehind 程式碼方法一定要加static ,至於webconfig 在新版的vs2013開發環境下無須配置如果是老的則新建ajax網站專案則webconfig自動弄好了然後服務端頁面載入事件中ScriptManager .GetCurrent(Page).EnablePageMethods = true; 用戶端必須有runat=server 的form 和
我始終還是認為上面那個比較好用 。關於他的原理我就不多說了 ,透過頁面載入時註冊服務端物件 ,然後產生的html頁面上就多了這麼幾句
<script type="text/javascript" src="/ajaxpro/prototype.ashx"></script> <script type="text/javascript" src="/ajaxpro/core.ashx"></script> <script type="text/javascript" src="/ajaxpro/converter.ashx"></script> <script type="text/javascript" src="/ajaxpro/WebApplication.StudentsInfo,WebApplication.ashx"></script> <script type="text/javascript" src="/ajaxpro/WebApplication.Grad,WebApplication.ashx"></script> <script type="text/javascript" src="/ajaxpro/WebApplication.NewFolder.HelloAjaxNet,WebApplication.ashx"></script> <script type="text/javascript" src="/ajaxpro/WebApplication.DataEntity,WebApplication.ashx"></script>
為是什麼呢 為的是引用一段js檔 ajaxpro/WebApplication1.NewFolder2.HelloAjaxNet,WebApplication1.ashx
然後你就明白了噻這段客供你進行客戶端js調用的腳本是服務端自動生成的跟你服務端的名字一模一樣然後你就可以貌似像在客戶端回調服務端方法樣的沒什麼神奇的,我們主要就是想利用他的這個特性和json化資料的方便之處來實現客戶端服務端資料的無縫傳遞。
關於json資料的序列化 要是以前就只有利用外部json函式庫 或微軟自帶的來進行手動解析:
服務端:
public string ServerProcerMethod(string stu) { //System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); //StuInfo s= jsSerializer.Deserialize<StuInfo>(stu); System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); List<StuInfo> s = jsSerializer.Deserialize<List<StuInfo>>(stu); if (s != null && s.Count > ) { StuInfo stu= s[]; StringBuilder sb = new StringBuilder(); jsSerializer.Serialize(stu, sb); return sb.ToString(); } else return null; }
客戶端:
//javascript 字符串转json对象: var obj = JSON.parse(str); //javascript json 对象转字符串: JSON.stringify(obj);
關於AjaxPro.2.dll 和ajax.dll的關係 ,網上說他們不一樣 其實壓根就是一個人搞的吧 我擦 。請上網站下載ajaxpro 這個才是完善的版本
引用dll檔案後需要設定webconfig httphandler 作用就是讓 上面的ashx請求轉到我們的 ajaxpro程式碼 ,進而讓我們的客戶端js直接呼叫服務端方法呼叫成功。
<system.webServer> <directoryBrowse enabled="true"/> <handlers> <add verb="*" path="*.ashx" name="myhandler" type="AjaxPro.AjaxHandlerFactory,AjaxPro."/> <!--<add verb="POST,GET" path="ajax/*.ashx" name="myhandler" type="Ajax.PageHandlerFactory, Ajax" />--> </handlers> </system.webServer>
然後其他的我就不多說了哈待會直接看服務端程式碼。
easyui 你就可以理解為一堆擴充了的控制。就像jquery一樣 你把js物件 原生的html控制用他的東西一包 然後就可以點得出他一些為你寫好的方法 幫助你方便的處理資料。而且還有預設的還可以的控制外觀,這點對於做企業管理類軟體來說 還是真心不錯的,做其他的就只能呵呵了。下載easyui的檔案 放到專案中 並引入easyui 相關js和樣式檔案 還有jquery:
<script type="text/javascript" src="../jquery-easyui-../jquery.min.js"> </script> <link rel="stylesheet" type="text/css" href="../jquery-easyui-../themes/default/easyui.css" /> <link rel="stylesheet" type="text/css" href="../jquery-easyui-../themes/icon.css" /> <script type="text/javascript" src="../jquery-easyui-../jquery.easyui.min.js"></script>
然後,然後你就可以使用easyui了就像easyui 首頁http://jeasyui.com/ 上介紹的那樣透過css樣式或js程式碼把原生html控制渲染成easyuiui
<div class="easyui-dialog" style="width:px;height:px" data-options=" title:'My Dialog', iconCls:'icon-ok', onOpen:function(){}"> dialog content. </div> <input id="cc" style="width:px" /> $('#cc').combobox({ url: ..., required: true, valueField: 'id', textField: 'text' });
是的 非常方便。其實國內還有好些js寫的比較牛的 弄了一些這樣ui 那樣ui 選來選去還是用這個吧。用的最多的需求就是ajax服務端分頁 ,我們來弄個吧。
我們先說下這個easyui的datagrid 打他狗日的,客戶端html放個table標籤:
function bindDataToTb() { var keywordStr = $('#keyword').val(); $('#studb').datagrid( { queryParams: { keyword: keywordStr }, //url:"WebForm.aspx/BindData", toolbar: '#searchBar', pagination: true, pageNumber: , singleSelect: true, pageSize: , pageList: [, , ], loader: function (param, success, error) { var da = WebApplication.NewFolder.HelloAjaxNet.BindData(param.keyword, param.page, param.rows) if (da.value.rows == null) { success(); } else success(da.value); }, pagePosition: 'bottom', columns: [[ { field: 'stuNo', title: 'Id', width: }, { field: 'name', title: '名字', width: }, { field: 'age', title: '年龄', width: }, { field: 'loginName', title: '登录名', width: }, { field: 'loginPwd', title: '密码', width: }, { field: 'GradId', title: '班级Id', width: }, { field: 'gradName', title: '班级', width: }, { field: 'none', title: '操作', width: , formatter: function (value, row, index) { var btn = '<a class="editcls" href="#" onclick="delstuClick(' + row.stuNo + ')">删除</a>'; return btn; } } ]] }); }
具体看loader 和columns ,loader用于定义你以什么形式载入数据 定义了loader上面的url就没有必要了。
我这里的WebApplication1.NewFolder2.HelloAjaxNet.BindData(param.keyword, param.page, param.rows) 自然也是服务端的方法 用于检索数据的 。
关于这三个param.keyword, param.page, param.rows 是我们用于实现loader时 easyui那种设计方式故意暴露给我们的参数 方便我们使用。
param.keyword 是我们上面定义的 我们点搜索的时候需要往服务端传一个查询关键词 queryParams: { keyword: keywordStr }
param.page 是easyui自己的参数表示当前第几页 param.rows表示每页行数,每当你 点表格的 上一页 下一页 的时候 就会自动往loader 发翻页的参数 这个是自动的。
然后就从服务端获取数据填充表格 ,就是这么一个工作过程。 还有colums 我就不说了就是定义显示哪些列 和自定义列 那个很容易看懂。
easyui控件有属性 方法,调用方法 的形式总算像这样 :$('#studb').datagrid('reload') 这就相当于调用了#studb这个表格控件的reload方法了 然后数据就会自动刷新,每个控件的具体见文档。
服务端数据处理我们还是用entityframework 我一般都用codefirst的方式 这东西跟他自己的mssql数据库 结合的很好 用起很方便。
服务端代码:
//查询(带分页 [AjaxPro.AjaxMethod] public static WebApplication.DataEntity BindData(string keyword, int page, int rows) { //, ref int pageIndex, out int totalPage if (keyword == null) keyword = ""; int pageIndex = ; int pageSize = ; int totalPage; if (page != ) pageIndex = page; if (rows != ) pageSize = rows; MyDb db = new MyDb(); var data = from studentInfo in db.Students where studentInfo.name.Contains(keyword) select new { stuNo = studentInfo.stuNo, name = studentInfo.name, age = studentInfo.age, gradName = studentInfo.grad.gradName }; //var data = from studentInfo in db.Students where studentInfo.name.Contains(keyword) select studentInfo; totalPage = data.Count() % pageSize == ? data.Count() / pageSize : data.Count() / pageSize + ; if (pageIndex > totalPage) pageIndex = totalPage; else if (pageIndex < ) pageIndex = ; //var dt = DataList<object>.Create(data.OrderBy(r => r.stuNo), new StudentsInfo(), pageIndex, pageSize).Value; object dt=null ; if(data.Count()>) dt= DataList<object>.Create(data.OrderBy(r => r.stuNo), new { stuNo = , name = "", age = , gradName = "" }, pageIndex, pageSize).Value; WebApplication.DataEntity result = new WebApplication.DataEntity(); result.total = data.Count(); result.rows = dt; return result; }
关于数据部分 和EF linq 分页那些我就不贴出来了 完整示例下载里面有。走走看吧 试试看吧 完全无刷新 服务端分页,感觉棒棒哒
搜索那个我也不想说了哈 就是重新载入下数据而已,删除是通过自定义 列的方式 传id到js函数 然后调用服务端删除。然后要说下 录入功能 以及easyui自带 的表单验证也是相当方便的。
新建一个div 作为弹出层 里面有一个录入信息的表格 各种html控件 只要写上easyui对应的样式 就自动渲染了 看弹出层的 class="easyui-dialog" data-options="closed:true,title:'新学生注册',modal:true"
其实很简单噻看字面意思就明白了 这些参数 都在easyui的文档里有。验证 也是在html元素上写data-options 就可以了, :
<div id="addBox" class="easyui-dialog" data-options="closed:true,title:'新学生注册',modal:true" style="width: px; height: px"> <table class="auto-style"> <tr> <td>学生姓名:</td> <td> <input id="stuname" class=" easyui-textbox" data-options="required:true,missingMessage:'必填项!',validType:'email',invalidMessage:'email格式不正确!'" type="text" /></td> </tr> <tr> <td>班级: </td> <td> <input class="easyui-combobox" id="grad" name="grad" data-options="valueField:'id',textField:'gradName',required:true,missingMessage:'必填项!'" /></td> </tr> <tr> <td> <input id="saveBtn" onclick="saveClick()" type="button" value="保存" /></td> <td> <input id="Button" type="button" onclick="$('#addBox').dialog('close');" value="关闭" /></td> </tr> </table> </div>
新建按钮:
注意千万别用button 元素 就是这种 这是个坑 ,折腾了好久。
保存按钮调用 的js函数:
//保存信息 function saveClick() { var isvaliok = $("#addBox").form('validate');//包起来的需要提交信息的那个div框的id if (isvaliok == false) { $.messager.show({ title: '提示', msg: '请完善不正确的项后再提交', showType: 'show' }); return; } var stu = {}; stu.name = $("#stuname").val(); stu.age = ; stu.GradId = $("#grad").combobox('getValue'); stu.gradName = $("#grad").combobox('getValue'); if (isNaN(stu.GradId)) stu.GradId = null; var rst = WebApplication.NewFolder.HelloAjaxNet.addStu(stu); if (rst.value == "ok") { $('#addBox').dialog('close'); $('#studb').datagrid('reload'); var gradData = WebApplication.NewFolder.HelloAjaxNet.getGrad().value; $('#grad').combobox({ data: gradData }).combobox('reload'); } else { $.messager.show({ title: '提示', msg: rst.error.Message + rst.value, showType: 'show' }); } }
注意到了噻:
var isvaliok = $("#addBox").form('validate');//包起来的需要提交信息的那个div框的id if (isvaliok == false) { $.messager.show({ title: '提示', msg: '请完善不正确的项后再提交', showType: 'show' }); return; }
在easyui里进行验证很简单噻 只要在html代码里把验证格式定义好了 ,只需要传入一个最外面容器控件的id $("#addBox").form('validate') 就自动帮我们验证了。并且界面上还有提示 焦点自动放到第一个验证不通过的控件上去了 完全不需要我们动手。
当然我们在客户端 document.ready()的时候 必须要绑定表格和下拉框的数据:
$(function () { //页面初始化 //载入表格数据 bindDataToTb(); //载入班级下拉框 var gradData = WebApplication.NewFolder.HelloAjaxNet.getGrad().value; $('#grad').combobox({ data: gradData }).combobox('reload'); var fd = new FormData(); });
服务端保存的代码:
//添加 [AjaxPro.AjaxMethod] public string addStu(StudentsInfo stu) { MyDb db = new MyDb(); if(stu.GradId==null) { if (string.IsNullOrEmpty(stu.gradName) == false) { Grad grd = new Grad(); grd.gradName = stu.gradName; Grad grdOld = db.grads.FirstOrDefault(r => r.gradName == stu.gradName); if(grdOld!=null) { return "类别已存在"; } else { db.grads.Add(grd); stu.grad = grd; } } } db.Students.Add(stu); db.SaveChanges(); return "ok"; }
服务端代码 如果我们没有这个id的类别我们就认为这个类别是新的 ,新加一个类别 然后立即绑定 perfect 完美 ,棒棒哒
看上去是不是有模有样。做管理类软件还行。
这样ui 那样ui当你需要自定义样式的时候发现什么ui都是浮云,例如我说的国内的写js比较牛的 就已经造出来很多ui了 ,表格是很漂亮 很强大。 其实很多功能你还是用不到 你想改还很困难 当然我的js也是很菜的。 当你用到另一套ui 的时候又要熟悉它那一套 。我只想用个简简单单的自定义分页表格而已 或者像asp.net里的服务器控件repeat 流式布局 四个数据一行那种 你怎么做。 还是自己动手吧。php里面有前端模板。
我这里只是简单从实际需求了解下angular的威力 php里面模板什么的都是浮云 新建一个webform HelloAjaxNetAngular.aspx
注意这个例子 服务端代码我一律用上面的丝毫都不会变 只是前端变了,angularjs 的主打思想是mvvm 模式 就是wpf里面那种依赖属性 动态绑定 ,不知道你们用过没 反正我用过 感觉就一个字 爽 ,做这种数据库平台程序 mfc winform 都是渣。
angularjs 的基础我就不介绍了 哈 直接从需求入手 做一个分页表格 加 信息更新 功能
angularjs的网站是 http://www.angularjs.org/ 这个网址在国内也是访问不了的。一些相关的其他人的学习笔记有 http://www.angularjs.cn/ http://www.zouyesheng.com/angular.html
反正这两个教程看了下对我没 对我没起到啥作用 感觉跟嚼木渣样的 ,angularjs的理念虽然是mvvm 但是angularjs本身还是感觉晦涩难懂。
我就在这样一个半懂不懂的状态下写了这个例子 ,所有的操作 几乎都完全不需要向jquery那样动dom 。真心感觉到了他的强大。前端就一个controller函数 管整个页面,怎么一个一个的分 我也不明白 只知道controller 跟html限定一样的树状结构。没在范围的html元素不能访问其controller里的 变量。
我们来看这个controller 函数 ,我写的时候也没什么感觉 。就是感觉很存粹 就只感觉到两个东西存在 。业务逻辑在操作数据。 就像在写c#数据操作代码样:
function myCtr($scope) { var mod = [{ name: 'xiang', age: }, { name: 'xiang', age: }, { name: 'xiang', age: }]; $scope.data = mod; $scope.curobj = {}; $scope.pageEntity = { total: , rows: , page: , pgmsg: '' } //初始化默认第一页 $scope.initPage = function () { var firstPage = WebApplication.NewFolder.HelloAjaxNetAngular.BindData($("#txtkeyword").val(), $scope.pageEntity.page, $scope.pageEntity.rows); $scope.data = firstPage.value.rows; var pageEntityMod = {}; pageEntityMod.total = firstPage.value.total; pageEntityMod.rows = $scope.pageEntity.rows; pageEntityMod.page = $scope.pageEntity.page; var totalpage = pageEntityMod.total % pageEntityMod.rows == ? parseInt(pageEntityMod.total / pageEntityMod.rows) : parseInt(pageEntityMod.total / pageEntityMod.rows) + ; pageEntityMod.pgmsg = "共 " + pageEntityMod.total + "条记录 每页 " + pageEntityMod.rows + "条,共 " + totalpage + "页 ,当前第 " + pageEntityMod.page + "页"; $scope.pageEntity = pageEntityMod; $scope.curobj = {}; } //更新当前 选定的 $scope.modifyCur = function () { var rst = WebApplication.NewFolder.HelloAjaxNetAngular.updateStu($scope.curobj) //刷新表格 当前选中信息 复原 $scope.initPage(); alert(rst.value); } //下翻页 $scope.nextPage = function () { var totalpage = $scope.pageEntity.total % $scope.pageEntity.rows == ? parseInt($scope.pageEntity.total / $scope.pageEntity.rows) : parseInt($scope.pageEntity.total / $scope.pageEntity.rows) + ; var pagenewnum = $scope.pageEntity.page + ; if (pagenewnum <= totalpage) $scope.pageEntity.page += ; $scope.initPage(); } //上翻页 $scope.previousPage = function () { var pagenewnum = $scope.pageEntity.page - ; if (pagenewnum >= ) $scope.pageEntity.page -= ; $scope.initPage(); } //搜索 $scope.search = function () { } //选中一行 $scope.del = function (sender, curobj) { //所有行的颜色还原//设置选中那一行的颜色 var rows = $(sender.target).parent().parent().parent().find("tbody").find("tr"); for (var i = ; i < rows.length; i++) { $(rows[i]).css("background", "white"); } $(sender.target).parent().css("background", "#ffed"); $scope.curobj = curobj; } //首次先调用下 以获取第一页 $scope.initPage(); }
界面部分:
<div ng-controller="myCtr" id="mygrid"> <input id="txtkeyword" type="text" /><input ng-click="initPage()" type="button" value="搜索" /> <br /> <br /> <div style="height: px"> <table cellspacing="" border="" class="gridtable"> <thead> <th width="px">name</th> <th width="px">age</th> </thead> <tbody ng-repeat="stu in data"> <tr ng-click='del($event,stu)' style="background-color: white"> <td>{{stu.name}}</td> <td>{{stu.age}}</td> </tr> </tbody> </table> </div> <div id="pager"> <a href="#" ng-click="previousPage()">上一页</a> <a href="#" ng-click="nextPage()">下一页</a> <span>{{pageEntity.pgmsg}}</span> </div> <div> 姓名:<input type="text" value="{{curobj.name}}" ng-model="curobj.name" /><br /> 年龄:<input type="text" value="{{curobj.age}}" ng-model="curobj.age" /> <input id="Button" type="button" ng-click="modifyCur()" value="更改" /> </div> </div>
看到我自己搞了一個資料綁定函數 參考easyui裡datagrid的loader。 第一次要求得到分頁資訊後 我立即把資料綁定到表格 你可以看到完全就像做模板樣的,然後初始化自己的分頁控制項。 在ng-click 的時候像原來一樣觸發客戶端單擊 然後調用controller裡的方法去更新數據 ,注意僅僅是根據業務邏輯去更新數據 其他的不需要做。關於上面兩段程式碼不懂的自行去看angularjs 入門和資料綁定 用不了10分鐘,
由於有wpf那種雙向綁定機制,資料模型 資料更新了 頁面內容自動跟著變。甚至你可以看到我編輯下面文字框裡的數據的時候 都還沒提交 上面表格的數據就跟著變 因為他們的數據是從同一個地方來的,看著恍惚都感覺是ajax哈。
上面所有範例的專案原始碼下載 可直接運行,由於引了些外部函式庫進來十兆差點放不下
說點後話
其實照網路這樣推動發展下去的話 前端會統一 前端才是王道 到時候一個網頁 就是一個系統 一個客戶端。 後端只負責資料和安全。 現在的什麼html5不是幾乎都成為工業標準了麼 有些嵌入式設備都支援
暫時像博客園裡我看到的有幾個講的前後端天人合一的那種mvc模式前端後端操作同一個model 前端更新屬性了有一種機制自動就更新到後端持久化到資料庫去了 或後端更新model的某個屬性前端html頁面的值自動就變了。 不是說做不到 畢竟牛人這麼多 ,我覺得至少還不穩定吧。
各種ui有easyui ligerui fineui miniui Devexpress 還有很多js框架 seajs requirejs JavaScriptMVC backbone avalonjs knockout angular jquery jqueryui js真是屎一樣的東西啊各種框架學都學不完
尤其是軟體產業日新月異基於框架和平台的技術太多了不精通某樣技術沒關係能使用就行,但是作為一個技術人員你至少得精通一樣或者一門技術要不然就是個搬磚的很遺憾我基本上還在搬磚的路上。寫業務代碼就是用一年的經驗混十年,寫業務代碼是他的工作工作之餘還得有點精神追究研究下事情的本質,只要是還不錯的程式設計師做這種資料庫系統久了都會自己搞點能快速開發的所謂的小框架累積一些自己的工具庫和經驗。
在工作上不要有什麼偏見 只要他每天把業務代碼寫的出來 軟體開發也只是一門職業 你不是英雄 ,目的是解決問題 不是轉牛角尖。
我自己對js是不怎麼感冒的 js也很爛,當初設計這個東西的時候就不完善給我們使用它造成了各種阻礙 ,但是你做web開發又不得不用它。這裡也並不是對做前端的有什麼偏見 感謝那些前端吃的很透的人 像司徒正美那些高手 製造了這些工具讓我們更容易的去完成這些網站程序。