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

问题描述 投票:0回答:1

我在脚本捆绑后在页面底部的_Layout.cshtml上使用@RenderSection("scripts", required: false)。使用此布局的My View定义了脚本部分(@section scripts{ //script block})。当我通过整页调用从控制器动作渲染视图时,每件事都可以正常工作。

但是当我使用$ .ajax调用完成处理程序($('#container').html(result))在容器内呈现相同视图的内容时,_Layout.cshtml页面上定义的脚本部分不会在DOM上加载和执行。注意在这种情况下_Layout没有加载,因为调用是ajax并且布局页面已经在DOM上了,我不想再次加载布局页面来改善页面加载时间。我只关心加载子视图的内容。

请在下面找到设置

_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>
        }

使用ajax调用加载视图的Javascript代码

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

现在,当我在第一种情况下使用布局加载页面时,它工作正常。但是,如果我尝试使用jquery ajax加载页面,则脚本部分不起作用。

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

为了解决这个问题,我尝试了以下解决方案,即在我的视图中,我根据条件加载脚本部分,如果请求是Ajax,则正常运行脚本,如果是带有布局的完整页面请求,则运行脚本部分。使用此解决方案,我的_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原则,因为我必须在ifblock中编写相同的脚本块。

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

javascript jquery html ajax asp.net-mvc
1个回答
0
投票

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

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

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

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

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

部分视图:_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(),而不是在局部视图中。

希望其中一些有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.