Ajax在MVC中的应用——实现良好的用户体验
最近在项目中尝试了一下使用结合Ajax和SQL存储过程实现分页,体验了一把无刷新的感觉,真好!
通过搜集资料和利周末时间,总算弄出来了,辛苦啊!很高兴和大家分享!
这里是在MVC框架下实现的,由于时间关系,这里Linq和ADO就混搭使用了(还是那句话,自己ADO比较熟悉一点)。代码方面也写的不是很好,有空的时候,在慢慢重构吧!
这里有两个目标,一个是实现无刷新高效的分页,一个是给用户良好的体验,比如在增删改时的体验。
为了模拟真实场景,我事先插入了一万条数据,速度很快,效果不错。
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Data.SqlClient; namespace InsSql { class Program { public static string connstr = @"Data Source=20110814-1820\SQLEXPRESS;Initial Catalog=blog;Integrated Security=True"; static SqlConnection conn = null; static SqlCommand cmd = null; static void Main(string[] args) { Excute(); } public static void Excute() { conn = new SqlConnection(connstr); if(conn.State == ConnectionState.Closed) { conn.Open(); } try { string sql = ""; for (int i = 0; i < 10000; i++) { int cid = 100 + i; string name = "H" + i; string demo = name + i; sql = "insert into cls values('"+cid+"','" + name + "','" + demo + "')"; cmd = new SqlCommand(sql, conn); cmd.ExecuteNonQuery(); } } catch(SqlException ex) { Console.Write(ex.ToString()); } finally { conn.Close(); } } } }
先看效果:
样式可能有点难看,回头找做美工的同事修改一下。当然,由于时间仓促,这里可能还存在不通用问题,有时间我会继续修改以使其能够比较通用。
View(cls/Index):
View Code
<h2>栏目管理</h2> <fieldset> <legend>栏目管理</legend> <p><a href="#" onclick="add(0)">添加一级栏目</a> </p> <table style="width: 95%" id="content"> </table> <div id="pager" class="yahoo2"> </div> <div id="add" style="display: none"> 栏目名称: <input type="text" id="adStr" name="adStr" style="width: 100px;" /> <input type="button" onclick="add_sub()" value="添加" /> </div> <div id="edit" style="display: none"> 栏目名称: <input type="text" name="itStr" id="itStr" style="width: 100px;" /> <input type="button" onclick="edit_sub()" value="修改" /> </div> </fieldset>
JS:
View Code
$(document).ready(function () { $("#n1").addClass("on"); //alert(1); list(); }); function list() { $.post("/Cls/list", null, function (data) { var total = data;//后台返回的数据 //alert(total); PageClick(1, total, 3); }); PageClick = function (pageIndex, total, spanInterval) { //alert(pageIndex); //alert(12); $.ajax({ url: "/Cls/list", data: { "PageIndex": pageIndex }, type: "post", dataType: "Json", success: function (data) { //索引从1开始 //将当前页索引转为int类型 var intPageIndex = parseInt(pageIndex); //获取显示数据的表格 //var table = $("#content"); //var table1 = "<thead><tr><th style=\"width:50px\">编号</th><th>栏目名称</th><th style=\"width:100px\">操作</th></tr></thead><tbody></tbody>"; var table = "<tr><th style=\"width:50px\">编号</th><th>栏目名称</th><th style=\"width:100px\">操作</th></tr>"; //清楚表格中内容 $("#content tr").remove(); //向表格中添加内容 //alert(data); //alert(table); var jsonData = eval(data); //很重要的 $.each(jsonData, function (i, d) { table += "<tr><td>" + d.cid + "</td><td>" + d.name + "</td><td><a href=# onclick=\"add(" + d.cid + ")\">添加</a> <a href=# onclick=\"edit(" + d.cid + ")\">修改</a> <a href=# onclick=\"dele(" + d.cid + ")\">删除</a> </td></tr>"; }); //alert(table); $("#content").append(table); //alert(n); //alert(total); //total = n; //alert(table); //创建分页 //将总记录数结果 得到 总页码数 假分页 var pageS = total; if (pageS % 10 == 0) pageS = pageS / 10; else pageS = parseInt(total / 10) + 1; var $pager = $("#pager"); //清楚分页div中的内容 $("#pager span").remove(); $("#pager a").remove(); //添加第一页 if (intPageIndex == 1) $pager.append("<span class='disabled'>第一页</span>"); else { var first = $("<a href='javascript:void(0)' first='" + 1 + "'>第一页</a>").click(function () { PageClick($(this).attr('first'), total, spanInterval); return false; }); $pager.append(first); } //添加上一页 if (intPageIndex == 1) $pager.append("<span class='disabled'>上一页</span>"); else { var pre = $("<a href='javascript:void(0)' pre='" + (intPageIndex - 1) + "'>上一页</a>").click(function () { PageClick($(this).attr('pre'), total, spanInterval); return false; }); $pager.append(pre); } //设置分页的格式 这里可以根据需求完成自己想要的结果 var interval = parseInt(spanInterval); //设置间隔 var start = Math.max(1, intPageIndex - interval); //设置起始页 var end = Math.min(intPageIndex + interval, pageS)//设置末页 if (intPageIndex < interval + 1) { end = (2 * interval + 1) > pageS ? pageS : (2 * interval + 1); } if ((intPageIndex + interval) > pageS) { start = (pageS - 2 * interval) < 1 ? 1 : (pageS - 2 * interval); } //生成页码 for (var j = start; j < end + 1; j++) { if (j == intPageIndex) { var spanSelectd = $("<span class='current'>" + j + "</span>"); $pager.append(spanSelectd); } //if else { var a = $("<a href='javascript:void(0)'>" + j + "</a>").click(function () { PageClick($(this).text(), total, spanInterval); return false; }); $pager.append(a); } //else } //for //上一页 if (intPageIndex == total) { $pager.append("<span class='disabled'>下一页</span>"); } else { var next = $("<a href='javascript:void(0)' next='" + (intPageIndex + 1) + "'>下一页</a>").click(function () { PageClick($(this).attr("next"), total, spanInterval); return false; }); $pager.append(next); } //最后一页 if (intPageIndex == pageS) { $pager.append("<span class='disabled'>最后一页</span>"); } else { var last = $("<a href='javascript:void(0)' last='" + pageS + "'>最后一页</a>").click(function () { PageClick($(this).attr("last"), total, spanInterval); return false; }); $pager.append(last); } } //sucess }); //ajax };//function }
Controllers(ClsController.cs)
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcOneByOne.Models; using System.Data; using System.Data.SqlClient; using System.Data.Linq; using System.Data.Linq.Mapping; using MvcOneByOne.Helpers; namespace MvcOneByOne.Controllers { public class ClsController : Controller { DataClasses1DataContext db = new DataClasses1DataContext(); string connstr = @"Data Source=20110814-1820\SQLEXPRESS;Initial Catalog=blog;Integrated Security=True"; // // GET: /Cls/ [Authorize] public ActionResult Index() { return View(); } [Authorize] public JsonResult list() { JsonResult js = null; var context = new DataContext(connstr); var pageIndex = Request["PageIndex"]; //判断当前索引存不存在,如果不存在则获取记录的总数。 if (string.IsNullOrEmpty(pageIndex)) { //获取查询记录总数的sql语句 string sql = "select count(-1) from cls"; int count = 0; count = int.Parse(ExecuteScalar(connstr,sql).ToString()); Response.Write(count); Response.End(); } //当根据索引获取数据 else { int currentPageIndex = 1; int.TryParse(pageIndex, out currentPageIndex); SqlParameter[] parms = new SqlParameter[] { new SqlParameter("@FEILDS",SqlDbType.NVarChar,1000), new SqlParameter("@PAGE_INDEX",SqlDbType.Int,10), new SqlParameter("@PAGE_SIZE",SqlDbType.Int,10), new SqlParameter("@ORDERTYPE",SqlDbType.Int,2), new SqlParameter("@ANDWHERE",SqlDbType.VarChar,1000), new SqlParameter("@ORDERFEILD",SqlDbType.VarChar,100) }; parms[0].Value = "*";//获取所有的字段 parms[1].Value = pageIndex;//当前页面索引 parms[2].Value = 10;//页面大小 parms[3].Value = 1;//升序排列 parms[4].Value = "";//条件语句 parms[5].Value = "cid";//排序字段 List<cls> list = new List<cls>(); using (SqlDataReader sdr = ExecuteReader(connstr, CommandType.StoredProcedure, "PAGINATION", parms)) { while (sdr.Read()) { list.Add(new cls { cid = int.Parse(sdr[0].ToString()), name = sdr[1].ToString(), demo = sdr[2].ToString() }); } } js = Json(list, JsonRequestBehavior.AllowGet); } return js; } public SqlDataReader ExecuteReader(string connstr, CommandType CommandType, string cmdText, SqlParameter[] parms) { SqlConnection conn = new SqlConnection(connstr); if (conn.State == ConnectionState.Closed) { conn.Open(); } string cmdT = cmdText; DataSet ds = new DataSet(); //创建参数列表,并为参数赋值 SqlParameter[] paras = parms; SqlCommand cmd = new SqlCommand(cmdText, conn); cmd = new SqlCommand(cmdText, conn); cmd.Parameters.AddRange(paras); cmd.CommandType = CommandType;//表明Command对象类型为存储过程 SqlDataReader sdr = cmd.ExecuteReader(); return sdr; } public object ExecuteScalar(string connstr,string sql) { object o = null; SqlConnection conn = new SqlConnection(connstr); if (conn.State == ConnectionState.Closed) { conn.Open(); } try { SqlCommand cmd = new SqlCommand(sql, conn); o = cmd.ExecuteScalar(); } catch( SqlException ex) { Console.Write(ex.ToString()); } finally { conn.Close(); } return o; } // // GET: /Cls/Create [Authorize] public ContentResult Create(int cid, string name) { cls c1 = new cls(); c1.cid = SqlHelper.get_ID("cls", "cid"); c1.name = Server.UrlDecode(name); var f = from d in db.cls where d.cid == cid select d; if (f.Count() > 0) { cls f1 = f.First(); c1.demo = f1.demo + c1.cid + "|"; } else { try { var f2 = (from d in db.cls where d.demo.Length == 2 orderby d.demo descending select d).First(); c1.demo = (Convert.ToInt32(f2.demo.Substring(0, 1)) + 1).ToString() + "|"; } catch { c1.demo = "1|"; } } db.cls.InsertOnSubmit(c1); db.SubmitChanges(); return Content(name); } } }
存储过程(仅供参考):
View Code
View Code USE [blog] GO /****** Object: StoredProcedure [dbo].[PAGINATION] Script Date: 05/06/2012 22:41:01 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: <Lucky Hu> -- Create date: <2012-05-06> -- Description: <分页存储过程> -- ============================================= CREATE PROCEDURE [dbo].[PAGINATION] @FEILDS VARCHAR(1000),--要显示的字段 @PAGE_INDEX INT,--当前页码 @PAGE_SIZE INT,--页面大小 @ORDERTYPE BIT,--当为0时 则为 desc 当为1 时 asc @ANDWHERE VARCHAR(1000)='',--where语句 不用加where @ORDERFEILD VARCHAR(100) --排序的字段 as DECLARE @EXECSQL VARCHAR(2000) DECLARE @ORDERSTR VARCHAR(100) DECLARE @ORDERBY VARCHAR(100) BEGIN set NOCOUNT on IF @ORDERTYPE = 1 BEGIN SET @ORDERSTR = ' > ( SELECT MAX(['+@ORDERFEILD+'])' SET @ORDERBY = 'ORDER BY '+@ORDERFEILD+' ASC' END ELSE BEGIN SET @ORDERSTR = ' < ( SELECT MIN(['+@ORDERFEILD+'])' SET @ORDERBY = 'ORDER BY '+@ORDERFEILD+' DESC' END IF @PAGE_INDEX = 1 --当页码是第一页时直接运行,提高速度 BEGIN IF @ANDWHERE='' SET @EXECSQL = 'SELECT TOP '+STR(@PAGE_SIZE)+' '+@FEILDS+' FROM [cls] '+@ORDERBY ELSE SET @EXECSQL = 'SELECT TOP '+STR(@PAGE_SIZE)+' '+@FEILDS+' FROM [cls] WHERE '+@ANDWHERE+' '+ @ORDERBY END ELSE BEGIN IF @ANDWHERE='' BEGIN --以子查询结果当做新表时 要给表名别名才能用 SET @EXECSQL = 'SELECT TOP'+STR(@PAGE_SIZE)+' '+@FEILDS+' FROM [cls] WHERE '+@ORDERFEILD+ @ORDERSTR+' FROM (SELECT TOP '+STR(@PAGE_SIZE*(@PAGE_INDEX-1))+' '+@ORDERFEILD+ ' FROM [cls] '+@ORDERBY+') AS TEMP) '+ @ORDERBY END ELSE BEGIN SET @EXECSQL = 'SELECT TOP'+STR(@PAGE_SIZE)+' '+@FEILDS+' FROM [cls] WHERE '+@ORDERFEILD+ @ORDERSTR+' FROM (SELECT TOP '+ STR(@PAGE_SIZE*(@PAGE_INDEX-1))+' '+@ORDERFEILD+ ' FROM [cls] WHERE '+@ANDWHERE+' '+@ORDERBY+') AS TEMP) AND '+@ANDWHERE+' '+ @ORDERBY END END EXEC (@EXECSQL)--这里要加括号 END GO