Sys.Application.add_load()、$(document).ready()和pageLoad()之间的区别

33

我有一个页面,其中包含一些需要在页面加载时运行的JavaScript代码。这些代码需要使用$find()方法定位到服务端控件的客户端组件。

当我直接将代码嵌入到页面中时,它会在页面读取时执行,但由于它所依赖的所有内容都还未初始化,因此失败了。

如果我把我的代码放在pageLoad()函数中,它就可以正常运行,因为asp.net会自动为任何名为pageLoad()的函数连接一个onload处理程序。问题是我真的不喜欢pageLoad()的解决方案,主要是因为它只是单个全局名称。如果我使用pageLoad()提交了一些代码,我知道其他程序员会复制该方法并在不合适的地方使用它,最终我们将得到一个包含两个或多个不同pageLoad()函数的页面,并且结果将是一堆神秘的错误,需要花费很长时间才能追踪到。

因此,我将我的代码放在传递给jquery的$(document).ready()的匿名函数中。但这样会失败,因为它在ServerControl的客户端组件存在之前运行。

然后,我将我的代码放在通过Sys.Application.add_load()传递的匿名函数中,但这也会失败,因为Sys未定义。

最后,我决定将我的代码放在Sys.Application.add_load()中,然后将其放在由$(document).ready()调用的函数中。这样做可以正常工作,但是它和pageLoad()一样让我感到非常困扰。

<script type="text/javascript">
    $(document).ready(function(){
        Sys.Application.add_load(function(){
            var component = $find(<clientid>);
            if (component) { <do something> }
        });
    });
</script>

一定有更好的方法来处理这个问题。

有什么想法吗?

4个回答

21
如果您可以控制代码后端,您可以通过以下方式注册JavaScript以在启动时运行:
this.Page.ClientScript.RegisterStartupScript(
    this.GetType(), 
    "StartupScript", 
    "Sys.Application.add_load(function() { functioncall(); });", 
    true);
只要你的组件已通过 Sys.Application.add_init() 加载,那么就可以了…

5
我想为那些试图构建外部库并尽可能遵循非侵入式JavaScript思想的人提供一种选择,与.NET紧密相关。pageLoad是一种非常好的方法,可以自动连接AJAX事件,这些事件应在每次页面加载时触发(无论该加载来自后退按钮导航到此页面,向前按钮导航到页面,AJAX回调,标准页面加载等)。由于您不必担心ScriptManager是否存在于DOM中,并且它的命名方式大多数情况下是有意义的(对于非.NET编码人员而言,pageLoad与body.onload略有混淆,但对于.NET人员而言,pageLoad在每次页面加载后都会触发,包括回调之后,因为其行为与服务器端Page_Load相同)。话虽如此,您的担忧是正确的 - 您不希望在给定页面上有两个pageLoad实例,因为它会破坏它。以下是一种纯JavaScript解决方案,对于所有开发人员都是安全的,允许使用pageLoad,不必担心DOM的存在,确保没有代码冲突,并为我们工作得非常出色。
在您的主javascript库中定义pageLoad和一个辅助函数:
if (!pageLoad) { var pageLoad = function (sender, args) {}; };
if (!mylibrarynamespace) {var mylibrarynamespace = {};};
if (!mylibrarynamespace.registerStartupScript) mylibrarynamespace.registerStartupScript = function (fn) {
    /* create local pointer for added function */
    var f = fn;

    /* create pointer to existing pageLoad function */
    var pLoad = pageLoad;

    /* add new function pointer to pageLoad by creating new anonymous function (search Google for "javascript enclosures" for why pl and f will persist with this newly defined anonymous function) */
    pageLoad = function (sender, args) {
    pLoad(sender,args);
    f(sender, args);
    }
}

接下来,要在你的客户端代码中使用它,只需按照以下步骤操作:

mylibrarynamespace.registerStartupScript(
    function (sender, args){ 
        /* do my AJAX always enabled startup code logic here*/
    }
);

为了使功能更易修改,我建议传入的匿名函数调用页面或控件子集中您的库的函数,这样您只需要更改库中特定部分的页面加载方式(在文件中或在运行时动态更改函数声明)即可。

在JavaScript中,编写前几行代码时,这样写更符合惯用语法:var pageload = pageload || function(sender, args) {}; - Goyuix

3
我相信如果您添加(或移动)ScriptManager控件到脚本块之上,您就不需要将其包含在jQuery的$(document).ready()函数中。通过这样做,显然ScriptManager将作为可用的:

将大部分JavaScript注入到页面中ScriptManager控件所处的确切位置。[http://encosia.com/2007/08/16/updated-your-webconfig-but-sys-is-still-undefined/]

然而,这种解决方案可能仍然会让您感到困扰,因为对于任何不知情的开发人员来说,ScriptManager实际提供了什么并不明显。
另一种方法是在ScriptManager内添加脚本引用(请参见上面链接文章中讨论的“更好的方法”),但我也不太喜欢整个ScriptManager方法。

0

尝试使用ScriptManager注册客户端脚本块,但为每个附加函数调用提供唯一的标题,特别是如果它具有唯一的参数值。如果您使用相同的函数但具有不同的参数值,则应该这样做。如果页面加载不是回发,即仅在页面刷新或页面加载后调用一次,则应仅使用add_load技术。

请尝试使用以下方法: ScriptManager.RegisterClientScriptBlock(this, GetType(), "unique title", "alert('quick test');", true);


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