在asp.net mvc中, razor引擎的作用是渲染出静态页面。(我这里指的静态页面,是指对浏览器而言,第一次从服务器下载以后页面。)
而ajax的作用是浏览器端的页面通过js向服务端再次发出请求从而从服务端获取数据展示在页面。
我们一般的编程模式是ajax只输出json风格的数据,再由客户端通过某种方式动态展示到页面上,比如通过jquery的模板插件,或第三方的控件。
这种方式无疑是高效的。对服务器压力也较小。
但是它的缺点就是我们无法利用现有的强大的razor引擎,用它丰富的Html帮助类,精确地控制数据展示的方式,维护各种链接。因为它是工作在服务器端的,在初始页面第一次从服务器端下载完以后,它的使命就完成了。
那么有没有办法让ajax和razor这两种截然不同的技术有机地结合在一起呢?
最近本人在做一个项目时发现,只需要简单的写一个jquery的扩展,就可以实现上述目的。
先看下效果:
1. 当我们在vs2013下,新建一个asp.net mvc应用程序, 会出现一个初始站点,我们就在这个初始站点上做文章,
2. 把其中的“关于”和“联系方式”两个页面,不导航到新页面,直接在主页原有的大屏幕介绍底下(如图所示局部加载区)打开:
为实现这个效果,原有的服务器端的Controller中的逻辑不需要做任何的改变。也不需要对视图做任何的改变。
改变的只是一个模板页_Layout.cshtml。
原有的_Layout.cshtml的源代码变成这样:
@ViewBag.Title - 我的 ASP.NET 应用程序 @Styles.Render("~/Content/css") @Scripts.Render("~/bundles/modernizr")@Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") }@RenderBody() @RenderSection("innerScripts", required: false)
其中红色加粗是加的代码。 注意到有一个loadpartial.js文件。这就是对jquery作的一个小扩展。
调用方法是: $.loadPartial({ link: '.nav a', container: '#partial' });
link代表一批链接的选择器,container代表页面加载到的容器。
注意: 所有加载的页面到容器内时,不会加载和主页重复的内容,如导航,版权声明(如果那样就太失败了).只会加载自己的#partial中的内容。
如果加载的页面在加载时有js要执行,可以写在innerScripts这个区域中。
另外,如果加载进的页面本身也有超链接,它依然会限制在这个框框内,more, 如果页面有表单,表单的提交也会限制在这个框框内;
更有,如果你的后台程序出了BUG,比如404或500错误,它也会忠实地把错误信息像普通页面一样显示在框框中。
看起来的感觉就像是一个内框架,但并不会破坏原有页面的dom结构。
是不是很神奇?
而这个神奇只是jquery的功劳,我只是对它写了几十行的小扩展:
好了,上核心loadpartial.js文件的代码:
/* Parital Load(C) Copy right bwangel 2014*/jQuery.extend({ /* 局部加载页 options{ link : 超链接的选择器 container: 要将页面加载到的容的选择器 updateNow: 是否立即将容器中的现有链接进行处理 } */ loadPartial: function (options) { var defaults = { link: '.nav a', container: '#razorContainer', updateNow: true }; defaults = $.extend(defaults, options); razorContainer = $(defaults.container); $(defaults.link).each(alink); if (defaults.updateNow) alinkInContainer(); //var razorUrl = ""; function alink(idx, link) { if ($(link).attr("onclick")) return; if (link.href.indexOf('###') >= 0) return; var addr1 = link.href.split('#'); var addr2 = location.href.split('#'); if (addr1[0] == addr2[0]) return; //说明是锚点跳转 $(link).click(function (e) { e.preventDefault(); if ($(link).attr("action")) { ConfirmDelete(link); } else { getRazor(link.href, null, 'get'); } }); } function alinkInContainer() { razorContainer.find('a').each(alink); razorContainer.find('form').submit(function (e) { e.preventDefault(); getRazor(this.action, $(this).serialize(), "post"); }); } function getRazor(url, d, m) { $.ajax({ url: url, data: d, cache: false, type: m, success: function (data) { var r = $("").append($.parseHTML(data, true)).find('#partial'); razorContainer.html(r); alinkInContainer(); }, error: function (response, status, xhr) { razorContainer.html(response.responseText); } }); } }});
关于此文的完整代码,请在下载