ASP.NET Webforms,用户控件中的JavaScript

6
我们在解决(APS.NET Webforms)中JavaScript的正确实现方面遇到了一些问题。
按照最佳实践,我们希望将所有(或至少尽可能多)的javascript放在页面底部,这样页面可以先加载HTML和CSS,并提供更好的用户体验。
项目中有很多jQuery代码,通常是特定于某些控件的,因此我们不希望它们在每个页面上都加载。
目前,jQuery本身,包括jQuery UI,位于页面顶部,以便我们可以在控件中使用jQuery(来自js文件或内联代码),但是,我们想将所有这些东西移动到页面底部。我们已经在页面底部添加了一个contentplaceholder(“JavascriptFooter”),以便我们可以在页面的页脚放置来自页面的javascript,但是我们卡在了控件上。
有什么最佳实践方法吗?我们应该将所有JS外部化,并在JS中检查是否加载了控件吗?但是那样会一直显示太多的东西。还是有其他方法?

1
为什么不推迟脚本的执行,直到 DOM 准备好呢?例如:($(function(){ ..在准备好时执行的代码放在这里.. }); - ctorx
在头部使用 ($(function(){ console.log("Works?"); })); 会抛出错误 $ is not defined,因为 jQuery 是在底部初始化的。 - Richard
在执行该脚本之前,您需要包含Jquery...您可以轻松地从像Google这样的CDN中获取它。我通常将Jquery放在头部,从CDN中获取所有其他内容并放在底部。 - ctorx
这就是整个主题的重点。如何将控件中的JS放在页脚,而不是将jQuery放在页面顶部。 - Richard
你想如何添加JavaScript?你打算在控件的标记内还是控件代码后面进行添加? - ctorx
基本上它是控件内部的代码,而不是后台代码。但它也可以是对外部文件的引用。理想情况下,我们希望将所有代码外部化(我们有一些内联内容)。 - Richard
3个回答

4

首先,我建议从CDN加载Jquery。以下是谷歌的代码:

<script type="text/javascript">
    document.write(["\<script type='text/javascript' src='", 
    ("https:" == document.location.protocol) ? "https://" : "http://", 
    "ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'>\<\/script>"].join(''));
</script>

那样的话,如果访问者在其他网站上已经看过这个内容,它将被缓存。此外,它将从不同的主机下载并行传输。
我也同意@ctorx的观点 - 你应该使用文档就绪执行。
此外,你可以使用ScriptManager,并在每个控件的代码后端创建所有特定于控件的JS(如果该控件是唯一利用该JS的对象,则可能是一个好主意)- 所有这些代码都会呈现在页面底部。
例如:
Page pg = (Page)System.Web.HttpContext.Current.Handler; // or this.Page in .ascx
ScriptManager.RegisterStartupScript(pg, typeof(Page), "myJS", "[... your code ]", true);

谢谢,我们确实使用CDN来加载jQuery(-UI),但我们仍然希望将它们加载在页面底部。 - Richard
2
协议可以自动解析,只需将脚本URL键入为 "//ajax.googleapis.com/..." - Pavel Hodek

1

我敢打赌,使用Web表单的公司有多少种解决方案就有多少种。话虽如此,您始终可以使用请求上下文来存储必要的脚本,然后在页面呈现之前编写它们。

您还可以尝试使用requireJS。虽然我不是专家,但有很多选项可供选择,它可以处理脚本加载超时、循环依赖、定义多个依赖项等问题。


1
首先,最好的方法是将控件中的JavaScript外部化到一个JS文件中,在您的网站的第一次请求和所有后续请求(即site.js)中加载。然后,该文件将由浏览器缓存,用户不必像在控件中保留JS时那样反复下载JS。
接下来,您需要创建一个机制,仅执行与执行页面或控件相关的脚本部分。
有几种方法可以实现这一点,但如果我处于您的情况,我会这样做。
识别包装大多数内容的页面级元素...通常人们称之为“wrapper”。动态向包装器添加自定义属性,称为“data-js”。从页面或用户/自定义控件(在服务器端)动态设置“data-js”的值。允许它具有由管道(|)或其他字符分隔的多个键。
<div class="wrapper" data-js="funtion1|function2">
     <!-- Page content goes here -->
</div>

在DOM准备就绪时利用jQuery查找此属性,并根据data-js属性中的值执行自定义JS函数。该函数仅包含与当前页面或控件相关的代码。

 $(function(){
    var funcKeys = $('.wrapper').attr('data-js');
    if(funcKeys != null)
    {
        var funcs = funcKeys.split('|');
        for(var i=0; i< funcs.length; i++) {
           var funcName = eval(funcs[i]);
           if(typeof funcName == 'function') {
                funcName();
           }
        }
    }    
});

使用这种方法,您只需要jQuery CDN引用、对站点JS文件的引用以及上面的代码片段在您的布局中。
然后,您只需要在您站点特定的JS文件中包含页面/控件特定的函数,就像这样:
function function1() {
    alert("This is function 1");
}

function function2() {
    alert("This is function 2");
}

希望这能帮到您。

顺便提一下,我还为您设置了一个示例链接,让您可以尝试它的工作方式: http://jsfiddle.net/hh84f/1/


谢谢,有趣的解决方案,我会看一下的。或者可以使用相同的技术来加载特定的JS文件,而不是执行函数。 - Richard
确实。我一开始想要在第一次请求时进行一次可缓存的http请求,但是如果网站有很多JS,单独的文件可能会从维护的角度更加清晰。 - ctorx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接