通过jQuery ajax调用响应在DOM上呈现页面内容时,在视图上呈现脚本部分

最后发布: 2018-09-03 09:47:13


问题

脚本捆绑后,我在页面底部的_Layout.cshtml上使用@RenderSection("scripts", required: false) 使用此布局的My View定义了脚本部分( @section scripts{ //script block} )。 当我通过整页调用从控制器操作呈现视图时,一切正常。

但是,当我使用$ .ajax调用完成的处理程序(例如( $('#container').html(result) )渲染容器内相同视图的内容时,则不会加载并执行_Layout.cshtml页面上定义的脚本部分在DOM上。 请注意,在这种情况下,由于调用是ajax并且布局页面已经在DOM上,因此未加载_Layout,并且我不想再次加载布局页面以缩短页面加载时间。 我只关心加载子视图的内容。

请在下面找到设置

_Layout.cshtml

 <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    @Styles.Render("~/Content/css")
</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">                

            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Load Full", "LoadPartial", "Home")</li>
                    <li><a href="#" id="lnkMenu" data-url="@Url.Action("LoadPartial","Home")">Load via SPA</a></li>
                </ul>
            </div>
        </div>
    </div>
    <div id="container" class="container body-content">
        @RenderBody()
        <hr />
    </div>    
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    <script src="~/Scripts/Common.js"></script>
    @RenderSection("scripts", required: false)
</body>
</html>

调节器

public ViewResult LoadPartial()
    {       
        return View("_LoadPartial");
    }

_ViewStart.cshtml:

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

局部视图:_LoadPartial.cshtml

     <div class="jumbotron">
        <h2>Script loading demo</h2>
    </div>
    <p id="partial-id">Partial view content</p>
    @section scripts
        {
        <script>
                $(function () {
                    console.log("full");
                    $('#partial-id').css('color', 'blue');
                });
            </script>
        }

Java脚本代码使用Ajax调用加载视图

    $(function () {
    $('#lnkMenu').click(function () {
        var url = $(this).data("url");
        $.ajax({
            url: url,
            type: 'GET',
            cache: false
        }).done(function (result) {
            $('#container').html(result);
        });
    });
  });

现在,当我在第一种情况下使用Layout加载页面时,效果很好。 但是,如果我尝试使用jquery ajax加载页面,那么脚本部分将无法正常工作。

=========================我尝试过的解决方案======================= =========

为了解决这个问题,我尝试了以下解决方案,即在我看来,我基于以下条件加载脚本部分:如果请求是Ajax,则正常运行脚本;如果它是带有Layout的全页请求,则运行脚本部分。 使用此解决方案,我的_LoadPartial.cshtml视图如下所示

    <div class="jumbotron">
    <h2>Script loading demo</h2>
</div>
<p id="partial-id">Partial view content</p>
@{
    if (Request.IsAjaxRequest())
    {
        <script>
            $(function () {
                console.log("partial");     
                $('#partial-id').css('color', 'blue');
            });
        </script>
    }
    else
    {
        @section scripts
        {
        <script>
                $(function () {
                    console.log("full");
                    $('#partial-id').css('color', 'blue');
                });
            </script>
        }
    }
}

这个解决方案在两种情况下都可以正常工作,但是这里解决方案的问题是它违反了DRY原理,因为我必须在if和else block编写相同的脚本block

是否有人知道处理这种情况的最佳方法是什么?

javascript jquery html ajax asp.net-mvc
回答

$(function(){}); 只是$(document).ready({})的简写;

$(document).ready仅在初始文档加载完成后才触发一次。 如果我对您的理解正确,您的流程如下:

  1. 载入页面
  2. 单击链接以加载部分视图
  3. Ajax调用从服务器获取部分视图标记,并将其插入DOM
  4. 您期望$(function(){}); 在这一点上运行

$(document).ready将在第1步和第2步之间被调用。到您在局部视图中加载时,它已经被调用,而不会仅仅因为您正在加载其他标记而被再次调用。

我建议将$(function())代码更改为实际函数,并在ajax的成功部分中调用它。

局部视图:_LoadPartial.cshtml

@section scripts
    {
    <script>
            function changeTextColour() {
                console.log("full");
                $('#partial-id').css('color', 'blue');
            };
        </script>
    }

JavaScript的

$(function () {
$('#lnkMenu').click(function () {
    var url = $(this).data("url");
    $.ajax({
        url: url,
        type: 'GET',
        cache: false
    }).done(function (result) {
        $('#container').html(result);
        changeTextColour();
    });
});
});

================================================== =======

如果需要更通用的解决方案,则可以将部分视图标记作为字符串返回作为JSON对象的一部分,以便返回多个值。 您将需要以下方法:

public static string RenderPartialToString(Controller controller, string partialViewName, object model, ViewDataDictionary viewData, TempDataDictionary tempData)
    {
        ViewEngineResult result = ViewEngines.Engines.FindPartialView(controller.ControllerContext, partialViewName);

        if (result.View != null)
        {
            controller.ViewData.Model = model;
            StringBuilder sb = new StringBuilder();
            using (StringWriter sw = new StringWriter(sb))
            {
                using (HtmlTextWriter output = new HtmlTextWriter(sw))
                {
                    ViewContext viewContext = new ViewContext(controller.ControllerContext, result.View, viewData, tempData, output);
                    result.View.Render(viewContext, output);
                }
            }

            return sb.ToString();
        }

        return String.Empty;
    }

用法:

行动:

public ActionResult Action() 
{
     var viewModel = new WhateverTypeYourViewModelIs();
     string partialHtml = RenderPartialToString(this, "PartialViewLocation.cshtml", viewModel, ViewData, TempData);
     return Json(new { Html = partialHtml, Color = "Blue" });
}

使用Javascript:

$(function () {
$('#lnkMenu').click(function () {
    var url = $(this).data("url");
    $.ajax({
        url: url,
        type: 'GET',
        cache: false
    }).done(function (result) {
        $('#container').html(result.Html);
        changeTextColour(result.Color);
    });
});
});

然后,您可以根据要调用的操作来更改操作中的颜色。 然后,您只需在页面加载时而不是在局部视图中注册功能changeTextColor()。

希望其中的一些帮助。