MVC 3:如何在通过 ajax 加载时呈现没有布局页面的视图?

Posted

技术标签:

【中文标题】MVC 3:如何在通过 ajax 加载时呈现没有布局页面的视图?【英文标题】:MVC 3: How to render a view without its layout page when loaded via ajax? 【发布时间】:2011-07-16 03:49:31 【问题描述】:

我正在学习Progressive Enhancement,并且我对 AJAXifying 视图有疑问。在我的 MVC 3 项目中,我有一个布局页面、一个 viewstart 页面和两个普通视图。

viewstart 页面位于 Views 文件夹的根目录中,因此适用于所有视图。它指定所有视图都应将_Layout.cshtml 用于其布局页面。布局页面包含两个导航链接,每个视图一个。链接使用@Html.ActionLink() 将自身呈现到页面。

现在我已经添加了 jQuery,想劫持这些链接并使用 Ajax 在页面上动态加载它们的内容。

<script type="text/javascript">
    $(function () 
        $('#theLink').click(function () 
            $.ajax(
                url: $(this).attr('href'),
                type: "GET",
                success: function (response) 
                    $('#mainContent').html(response);
                
            );
            return false;
        );
    );
</script>

我可以想到两种方法来做到这一点,但我不是特别喜欢任何一种:

1) 我可以获取整个 View 的内容并将它们放在局部视图中,然后让主视图在呈现时调用局部视图。这样,在控制器中使用Request.IsAjaxRequest(),我可以根据请求是否为Ajax 请求返回View() 或返回PartialView()。我无法将常规视图返回给 Ajax 请求,因为那样它将使用布局页面,并且我会得到第二个注入的布局页面副本。但是,我不喜欢这样,因为它迫使我为标准 GET 请求创建空视图,其中只包含 @Html.RenderPartial();

    public ActionResult Index()
    
        if (Request.IsAjaxRequest())
            return PartialView("partialView");
        else
            return View();
    

然后在 Index.cshtml 中这样做:

@Html.RenderPartial("partialView");

2) 当请求不是 Ajax 时,我可以从 _viewstart 中删除布局指定并手动指定它:

    public ActionResult Index()
    
        if (Request.IsAjaxRequest())
            return View(); // Return view with no master.
        else
            return View("Index", "_Layout"); // Return view with master.
    

有人有更好的建议吗?有没有办法在没有布局页面的情况下返回视图?如果它是一个 ajax 请求,明确地说“不包括你的布局”会比明确地包含布局要容易得多,如果它不是一个 ajax。

【问题讨论】:

【参考方案1】:

~/Views/ViewStart.cshtml:

@
    Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";

在控制器中:

public ActionResult Index()

    return View();

【讨论】:

这个可以在viewstart中指定吗? @Matt Greer,你说它讨厌,我称之为 DRY,无论如何都是主观的东西 :-) 我不得不承认,一开始我并不喜欢它,但它节省的代码量似乎远远超过了它的缺点。这是一个简单的布尔值,如果并且并没有真正强加 IMO。我喜欢它而不是每次都将我的动作方法切成两半。另外,它会阻止我做你所说的 Matt,并且可能会在 action 方法中走下两条巨大的逻辑路径。我要么编写动作以在两种情况下工作相同,要么编写一个新动作。 您不能在基本控制器中执行此操作,在 ViewData 中设置一个属性并使用它吗?那么该行将是Layout = ViewBag.LayoutFile 我想我可以,但为什么要为一小行创建一个 baseController?【参考方案2】:

只需将以下代码放在页面顶部

@
    Layout = "";

【讨论】:

这不起作用,因为我希望能够根据是否通过 AJAX 请求来打开或关闭布局。这仅允许您关闭布局,而不是切换它。 为什么会有投票??请解释一下,所以我也会投票赞成。 @UsmanY。你不需要投票。但是我愿意。我的争论转到 google.com.pk/#q=mvc3%20view%20without%20layout 。这是该查询的完美答案。 本主题是关于在两种不同场景下切换布局。这个答案只是将布局设置为空,无论场景是什么。 老兄,这行得通,真的很好。我使用的场景:未经授权的用户尝试登录,不希望错误页面向未经授权的用户显示链接等等!当然,它也适用于其他一切!【参考方案3】:

我更喜欢并使用您的 #1 选项。我不喜欢#2,因为对我来说View() 意味着您要返回整个页面。一旦视图引擎完成它,它应该是一个完全充实且有效的 HTML 页面。 PartialView() 被创建用于返回任意 HTML 块。

我认为拥有一个仅称为局部视图的视图没什么大不了的。它仍然是 DRY,并允许您在两个场景中使用部分的逻辑。

许多人不喜欢使用Request.IsAjaxRequest() 分割他们的操作调用路径,我可以理解这一点。但是 IMO,如果您所做的只是决定是调用 View() 还是 PartialView(),那么分支没什么大不了的,并且易于维护(和测试)。如果您发现自己使用IsAjaxRequest() 来确定您的大部分操作如何进行,那么制作一个单独的 AJAX 操作可能会更好。

【讨论】:

【参考方案4】:

您只需要创建两个布局:

    一个空的布局

    主布局

然后在_viewStart文件中编写如下代码:

@
   if (Request.IsAjaxRequest())
   
      Layout = "~/Areas/Dashboard/Views/Shared/_emptyLayout.cshtml";
   
   else
   
      Layout = "~/Areas/Dashboard/Views/Shared/_Layout.cshtml";
   
 

当然,也许这不是最好的解决方案

【讨论】:

【参考方案5】:

您不必为此创建一个空视图。

在控制器中:

if (Request.IsAjaxRequest())
  return PartialView();
else
  return View();

返回 PartialViewResult 将在呈现响应时覆盖布局定义。

【讨论】:

【参考方案6】:

在 ASP.NET 5 中不再有可用的 Request 变量。您现在可以使用 Context.Request 访问它

也没有 IsAjaxRequest() 方法了,你必须自己写,例如在 Extensions\HttpRequestExtensions.cs 中

using System;
using Microsoft.AspNetCore.Http;

namespace Microsoft.AspNetCore.Mvc

    public static class HttpRequestExtensions
    
        public static bool IsAjaxRequest(this HttpRequest request)
        
            if (request == null)
            
                throw new ArgumentNullException(nameof(request));
            

            return (request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        
    

我现在搜索了一段时间,希望对其他人也有帮助;)

资源:https://github.com/aspnet/AspNetCore/issues/2729

【讨论】:

【参考方案7】:

对于 Ruby on Rails 应用程序,我可以通过指定来阻止加载布局 render layout: false 在我想用 ajax html 响应的控制器操作中。

【讨论】:

标签:c# asp.net,不是 ruby​​

以上是关于MVC 3:如何在通过 ajax 加载时呈现没有布局页面的视图?的主要内容,如果未能解决你的问题,请参考以下文章

通过jQuery设置全局Ajax加载时呈现Loading

如何在 Spring MVC 中使用 AJAX 渲染视图

MVC 5:通过 Ajax 加载内容区域并修改浏览器 url

使用 ajax 加载模板时未呈现脚本

使用 ajax 渲染局部视图

带有部分 ajax 加载视图的 NodeJS MVC 框架