22

当前,当对 MVC 操作进行 Ajax 调用时,我的 javascript 在视图中,而不是在它自己的 JS 文件中。

然后很容易做到这一点:

var xhr = $.ajax({
     url: '<%= Url.Action("DisplayItem","Home") %>/' + el1.siblings("input:hidden").val(),
     data: { ajax: "Y" },
     cache: false,
     success: function(response) { displayMore(response, el1, xhr) }
});

...然后在 JS 中使用的 ajax 调用中包含 URLUrl.Action()非常容易。如果没有对 URL 进行硬编码,我怎么能移动它自己的 JS 文件?

4

5 回答 5

38

我这样做的方式是生成 URL 服务器端并使用HTML5 数据属性存储在生成的 HTML 中,例如:(Razor 语法)

<li class='customClass' data-url='@Url.Action("DisplayItems", "Home", new { id = Model.Id })'>...</li>

然后你可以使用 jQuery attr() 函数来获取 url,例如:

$(".customClass").click(function () {
    $.ajax({
        url: $(this).attr("data-url"),
        success: function (data) {
            // do stuff
        }
    });
});

如果您生成 HTML 客户端以响应 AJAX 调用,则可以在 JSON 有效负载中包含相关 URL,并以相同方式填充data-属性。

于 2011-04-18T07:22:58.960 回答
19

这种方式充分利用了 MVC 路由,因此您可以充分利用 MVC 框架。受到 stusmith 回答的启发。

在这里,我ApplicationController对此 URL 有一个动态 javascript 操作:

 /application/js

我在这里包含静态文件是因为我只想要一个主 javascript 文件来下载。如果需要,您可以选择只返回动态内容:

     /// <summary>
    /// Renders out javascript
    /// </summary>
    /// <returns></returns>
    [OutputCache(CacheProfile = "Script")]
    [ActionName("js")]
    public ContentResult RenderJavascript()
    {
        StringBuilder js = new StringBuilder();

        // load all my static javascript files                    
        js.AppendLine(IO.File.ReadAllText(Request.MapPath("~/Scripts/rr/cart.js")));
        js.AppendLine(";");

        // dynamic javascript for lookup tables
        js.AppendLine(GetLookupTables());
        js.AppendLine(";");

        return new ContentResult()
        {
            Content = js.ToString(),
            ContentType = "application/x-javascript"
        };
    }

这是创建我们的查找表的辅助函数。只需为您要使用的每个 RouteUrl 添加一行。

    [NonAction]
    private string GetLookupTables() 
    {
        StringBuilder js = new StringBuilder();

        // list of keys that correspond to route URLS
        var urls = new[] {
            new { key = "updateCart", url = Url.RouteUrl("cart-route", new { action = "updatecart" }) },
            new { key = "removeItem", url = Url.RouteUrl("cart-route", new { action = "removeitem" }) }
        };

        // lookup table function
        js.AppendLine("// URL Lookuptable");
        js.AppendLine("$.url=function(url) {");
        js.AppendLine("var lookupTable = " + new JavaScriptSerializer().Serialize(urls.ToDictionary(x=>x.key, x=>x.url)) + ";");
        js.AppendLine("return lookupTable[url];");
        js.AppendLine("}");

        return js.ToString();
    }

这会生成以下动态 javascript,它基本上只是从任意键到我的操作方法所需的 URL 的查找表:

// URL Lookuptable
$.url=function(url) {
var lookupTable = {"updateCart":"/rrmvc/store/cart/updatecart","removeItem":"/rrmvc/store/cart/removeitem"};
return lookupTable[url];
}

在 cart.js 我可以有这样的功能。请注意,url 参数取自查找表:

 var RRStore = {};
 RRStore.updateCart = function(sku, qty) {

    $.ajax({

        type: "POST",
        url: $.url("updateCart"),
        data: "sku=" + sku + "&qty=" + qty,
        dataType: "json"

        // beforeSend: function (){},
        // success: function (){},
        // error: function (){},
        // complete: function (){},
    });

    return false;

};

我可以从任何地方调用它:

 RRStore.updateCart(1001, 5);

这似乎是我能想到的唯一方法,它可以让我以干净的方式使用路由。在 javascript 中动态创建 URL 很麻烦,而且很难测试。测试类型可以在这里的某个地方添加一个层,以方便测试。

于 2009-07-16T07:14:48.273 回答
6

将 AJAX 调用包装在一个函数中,该函数将 URL(和任何其他数据)作为参数并返回响应。然后在您看来,调用函数而不是直接调用 AJAX 调用。

function doAjax( url, data, elem, callback )
{
    return $.ajax({
        url: url,
        data: { ajax: data },
        cache: false,
        success: function(response) { callback(response, elem, xhr); }
    });
}

...

<input type='button' value='Go get it' onclick='doAjax( <%= Url.Action ...

我不确定这是否比在页面上而不是在 JS 文件中调用 Ajax 更好,除非您经常使用完全相同的模式。

于 2008-12-18T01:53:18.973 回答
3

使用模块模式。


// separate js file
var PAGE_MODULE = (function () {
  var url = {},
      init = function(url) { ... },
      load = function() {
      $.ajax({
           url: url,
           ...
           });
      }

      return { init: init };
})();


// calling init goes on the page itself
PAGE_MODULE.init(" %: Url.Action(...) %>");

一般来说,内联 onclick 处理程序不是好的 javascript,因为您使用的是全局函数。

onclick='doAjax(

我建议阅读http://jqfundamentals.com/book/index.html#N20D82以更好地处理模块模式。

于 2011-03-15T04:49:46.363 回答
-1

这是另一种方式:

在您的母版页中,包括一个用于内联脚本的区域:

<head>
  ...
  <asp:ContentPlaceHolder runat="server" ID="_inlineScripts" />
  ...
</head>

然后在 Page_Load 中,创建一个实用函数:

protected void Page_Load( object sender, EventArgs e )
{
  AddInlineScript( string.Format( "$.url=function(url){{return '{0}'+url;}}", GetBaseUri() ) );
  ...
}

private Uri GetBaseUri()
{
  var requestUrl = Request.Url.AbsoluteUri;
  var i = requestUrl.IndexOf( request.Path );

  return new Uri( requestUrl.Substring( 0, i ) );
}

private void AddInlineScript( string content )
{
  var script = new HtmlGenericControl( "script" );

  script.Attributes.Add( "type", "text/javascript" );
  script.InnerHtml = content;

  _inlineScripts.Controls.Add( script );
}

现在你可以在你的 ajax 中使用这个函数:

$.ajax({
  url: $.url('path/to/my-handler'),
  ...
});
于 2008-12-31T12:44:33.000 回答