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">
            栏目名称:&nbsp;<input type="text" id="adStr" name="adStr" style="width: 100px;" />&nbsp;
            <input type="button" onclick="add_sub()" value="添加" />
        </div>
        <div id="edit" style="display: none">
            栏目名称:&nbsp;<input type="text" name="itStr" id="itStr" style="width: 100px;" />&nbsp;
            <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>&nbsp;<a href=# onclick=\"edit(" + d.cid + ")\">修改</a>&nbsp;&nbsp;<a href=# onclick=\"dele(" + d.cid + ")\">删除</a>&nbsp;</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

 

 


 

 

 

posted @ 2012-05-06 23:21  楠木大叔  阅读(1640)  评论(3编辑  收藏  举报