ASP.NET UserControl在UpdatePanel中不触发JavaScript

8
我看到了类似的问题和答案,但没有一个能解决这个问题。
我在 update panel 中有一个用户控件,在我的用户控件中输出 JavaScript。
当触发时,JavaScript 不会被触发。如果我将 JavaScript 移动到父页面之外的 usercontrol/updatepanel 中,它就会被触发。这样做没有意义,因为我不能在另一个页面上使用此用户控件而不重复代码...要么复制整个 JavaScript(不同的站点),要么在每个使用它的页面中添加对 .js 文件的引用(同一站点)。这样做较不具有可移植性。
我只想在控件内部(update panel 内)输出 JavaScript。
提到 updatepanel 是为了准确地说明我正在做什么。即使我将用户控件放在 updatepanels 之外,它也无法工作。
简单来说(这对我不起作用):
用户控件:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="_location.ascx.cs" Inherits="_location" %>
<script type="text/javascript">
    function test() {
        alert('Hello World!');
    }
</script>

<a href="javascript:void(0);" onclick="javascript:test();">
    Find For Me
</a>

父级元素:

<uc1:_location runat="server" ID="_location"  />

在Chrome的调试中告诉我:“未捕获的引用错误:test未定义”
如果我直接将JavaScript添加到以下onclick中,它就可以工作:
onclick="alert('Hello World!');"

正如上面所述,将函数移动到父页面也可以起作用。

就好像浏览器忽略了用户控件的脚本输出一样。

有什么想法吗?


你的代码对我来说运行良好。 - chamara
@chamara 如果您从内部的UpdatePanel中调用并更新此代码,则无法正常工作。 - Aristos
5个回答

6
当您使用 UpdatePanel 更新其内容时,它会将其内容视为简单的文本/HTML(而不是代码),因此它没有任何解析器可用于运行脚本并使其对页面可用。
因此,此内容:
<script type="text/javascript">
    function test() { alert('Hello World!'); }
</script>

<a href="javascript:void(0);" onclick="javascript:test();">
    Find For Me
</a>

在客户端更新面板的代码运行并更新页面内容后,脚本部分不会被解析 - 它只是页面的简单文本/HTML。

然而,这部分则可以正常运行。

<a href="javascript:void(0);" onclick="alert('Hello World!');">Find For Me</a>

由于 onclick 属性的解析是在单击它时进行的。
以下有一些可用的解决方法:
  1. 将你的 JavaScript 移入外部文件。
  2. 将你的脚本移动到 UpdatePanel 之外。
  3. 使用 RegisterClientScriptBlock 或替代函数在代码后台中注册脚本。

这与我在问题中所述的工作方式并没有太大区别。如果我必须将脚本放在updatepanel之外,那么我就不得不将其包含在父页面上...我的用户控件位于父页面上的updatepanel中...是的,在不使用registerclientscriptblock的情况下,将脚本放在该updatepanel之外也可以正常工作...虽然这样可以工作,但并不理想。当然,微软肯定提供了一种方法来在用户控件内包含javascript,以便实现可移植性。 - Adam Wood
1
@AdamWood 你可以在代码后端注册脚本。我的回答与你的问题不同之处在于,你没有意识到更新不是解析和无法解析脚本 - 这是关键点。 - Aristos
1
谢谢。它解释了为什么 UpdatePanel 中的 UserControl 上的内联代码根本无法调用。它只是文本。搜索了几个小时... - Fried

2
除了Adam Wood发布的解决方案之外,我应该说在使用更新面板时必须使用ScriptManager来注册脚本,至少在.net 4.0中,否则它将无法正常工作。
因此,您可以将以下内容放置在用户控件的PageLoad事件中:
string script = @" alert('this is a test');
alert('it worked')";
ScriptManager.RegisterStartupScript(Page,Page.GetType(),"scriptMelhoria",script,true);

我原以为这是解决我另一个问题的方法。我正在尝试将jquery事件绑定到控件上。但是,由于某种原因,我收到了0x800a139e-JavaScript运行时错误:语法错误,无法识别表达式:#<%=pnDetails.ClientID%>,我无法在脚本中访问我的用户控件。(我尝试这样做是因为如果我将脚本放在我的用户控件上,它位于Update Panel内,我的脚本根本不会触发)。 - SoroTrestal

1
感谢Aristos将我引向正确的方向...尽管他的解决方案有效,但它没有回答从用户控件内部输出javascript的问题,而是建议将其移到外部。正如所述,这不是期望的结果,因为它不便于在控件内部移植。
以下是我实现此目标的解决方案: CS文件:
String script = "<script type=\"text/javascript\">";
script += "function test() {";
    script += "alert('Hello World!');";
script += "</script>";

Page.ClientScript.RegisterClientScriptBlock(Page.GetType(), "locationScript", script);

如果脚本很长,可以使用字符串生成器,但无论哪种方法都可以。

这将使代码完全保留在用户控件内,并且可以从a标签的onclick事件中工作。


0

试试这个:

在更新面板回调后,您可以找到您的脚本元素并对它们进行评估。

为内联脚本标签添加一个特殊属性以选择回调请求后的元素。

<script type="text/javascript" data-tag='myscript'>
    function test() {
        alert('Hello World!');
    }
</script>

并将此脚本添加到您的UpdatePanel容器aspx文件中。

<script>

        if (Sys !== undefined) {
            var prm = Sys.WebForms.PageRequestManager.getInstance();
            prm.add_endRequest(endPostbackRequest);
        }

        function endPostbackRequest(sender, args) {
            $("script[data-tag='myscript']:not([data-run])").each(
                function () {
                    eval.apply(window, [$(this).text()]);
                    $(this).attr('data-run', '1');
                });
        }

</script>

-1

处理绑定在 UpdatePanel 中的 JavaScript 代码的首选方法是订阅 PageRequestManagerendRequest 事件,并在此处执行您的代码。例如,您想在此处设置单击事件处理程序。

// that is standard way for asp.net to execute JS on page load
// pretty much the same as $(function(){ ...}) with jquery
function pageLoad() {
    // find PRM instance and subscribe to endRequest
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(endRequest);
}

function endRequest() {
    // set all handlers to DOM elements that are within UpdatePanel
    $('<%= myButton.ClientID %>').on('click', test)
}

function test(e) {
   alert('Hi')
}

另一种解决方案是使用事件委托,如下所示:
function pageLoad() {

    // delegate click event on .myButton inside .container
    // to the .container DOM element
    $('.container').on('click', '.myButton', test)

}

使用一个名为container的类包围你的更新面板,并用div标签来实现。在这种情况下,你的div.container永远不会从DOM中移除,因此它上面的所有事件处理程序都将在部分回发后保留。

没有使用jQuery的同样代码,仅使用asp.net ajax,将会像这样:

function pageLoad() {
   Sys.UI.DomEvent.addHandler($("myContainer"), "click", delegatedTest);
}

function delegatedTest(e) {
   // since asp.net ajax does not support event delegation
   // you need to check target of the event to be the right button 
   if (e.target.id == "myButton") test(e)
}

function test(e) {
   alert("HI")
}

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