Unterschied zwischen RegisterStartupScript und RegisterClientScriptBlock?

139

Ist der einzige Unterschied zwischen dem RegisterStartupScriptund dem, RegisterClientScriptBlockdass RegisterStartupScript das Javascript vor das schließende </form>Tag der Seite und RegisterClientScriptBlock direkt nach dem Start- <form>Tag der Seite setzt?

Und wann würden Sie einen über den anderen wählen? Ich habe eine kurze Beispielseite geschrieben, auf der ich ein Problem hatte, und ich bin mir nicht sicher, warum es genau passiert.

Hier ist das Aspx-Markup:

<html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Label ID="lblDisplayDate" runat="server"
                           Text="Label" /><br />
                <asp:Button ID="btnPostback" runat="server" 
                            Text="Register Startup Script"
                            onclick="btnPostback_Click" /><br />
                <asp:Button ID="btnPostBack2" runat="server" 
                            Text="Register"
                            onclick="btnPostBack2_Click" />
            </div>
        </form>
    </body>
</html>

Hier ist der Code dahinter:

protected void Page_Load(object sender, EventArgs e)
{
    lblDisplayDate.Text = DateTime.Now.ToString("T");
}

protected void btnPostback_Click(object sender, EventArgs e)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append(@"<script language='javascript'>");
    sb.Append(@"var lbl = document.getElementById('lblDisplayDate');");
    sb.Append(@"lbl.style.color='red';");
    sb.Append(@"</script>");

    if(!ClientScript.IsStartupScriptRegistered("JSScript"))
    {
        ClientScript.RegisterStartupScript(this.GetType(),"JSScript",
        sb.ToString());
    }
}

protected void btnPostBack2_Click(object sender, EventArgs e)
{
    System.Text.StringBuilder sb = new System.Text.StringBuilder();
    sb.Append(@"<script language='javascript'>");
    sb.Append(@"var lbl = document.getElementById('lblDisplayDate');");
    sb.Append(@"lbl.style.color='red';");
    sb.Append(@"</script>");

    if (!ClientScript.IsClientScriptBlockRegistered("JSScriptBlock"))
    {
        ClientScript.RegisterClientScriptBlock(this.GetType(), "JSScriptBlock",  
        sb.ToString());
    } 
 }

Das Problem ist, wenn ich auf die btnPostBackSchaltfläche klicke, ein Postback erstellt und das Etikett in Rot geändert wird. Wenn ich jedoch auf das btnPostBack2klicke, wird ein Postback ausgeführt, aber die Etikettenfarbe ändert sich nicht in Rot. Warum ist das? Liegt es daran, dass das Label nicht initialisiert ist?

Ich habe auch gelesen, dass Sie, wenn Sie eine verwenden UpdatePanel, diese verwenden müssen ScriptManager.RegisterStartupScript, aber wenn ich eine habe MasterPage, würde ich sie verwenden ScriptManagerProxy?

Xaisoft
quelle

Antworten:

162

Hier ist ein alter Diskussionsthread, in dem ich die Hauptunterschiede und die Bedingungen aufgelistet habe, unter denen Sie jede dieser Methoden anwenden sollten. Ich denke, Sie finden es vielleicht nützlich, die Diskussion durchzugehen.

So erklären Sie die Unterschiede als relevant für Ihr veröffentlichtes Beispiel:

ein. Wenn Sie verwenden RegisterStartupScript, wird Ihr Skript nach allen Elementen auf der Seite gerendert (direkt vor dem End-Tag des Formulars). Auf diese Weise kann das Skript Seitenelemente aufrufen oder referenzieren, ohne dass diese möglicherweise nicht im DOM der Seite gefunden werden.

Hier ist die gerenderte Quelle der Seite, wenn Sie die RegisterStartupScriptMethode aufrufen :

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title></title></head>
<body>
    <form name="form1" method="post" action="StartupScript.aspx" id="form1">
        <div>
            <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="someViewstategibberish" />
        </div>
        <div> <span id="lblDisplayDate">Label</span>
            <br />
            <input type="submit" name="btnPostback" value="Register Startup Script" id="btnPostback" />
            <br />
            <input type="submit" name="btnPostBack2" value="Register" id="btnPostBack2" />
        </div>
        <div>
            <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="someViewstategibberish" />
        </div>
        <!-- Note this part -->
        <script language='javascript'>
            var lbl = document.getElementById('lblDisplayDate');
            lbl.style.color = 'red';
        </script>
    </form>
    <!-- Note this part -->
</body>
</html>

b. Bei Verwendung RegisterClientScriptBlockwird das Skript direkt nach dem Viewstate-Tag, jedoch vor einem der Seitenelemente gerendert. Da es sich um ein direktes Skript handelt (keine Funktion, die aufgerufen werden kann , wird es sofort vom Browser ausgeführt. Der Browser findet die Bezeichnung jedoch zu diesem Zeitpunkt nicht im DOM der Seite und daher sollten Sie ein "Objekt nicht gefunden" erhalten. Error.

Hier ist die gerenderte Quelle der Seite, wenn Sie die RegisterClientScriptBlockMethode aufrufen :

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1"><title></title></head>
<body>
    <form name="form1" method="post" action="StartupScript.aspx" id="form1">
        <div>
            <input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="someViewstategibberish" />
        </div>
        <script language='javascript'>
            var lbl = document.getElementById('lblDisplayDate');
            // Error is thrown in the next line because lbl is null.
            lbl.style.color = 'green';

Zusammenfassend sollten Sie daher die letztere Methode aufrufen, wenn Sie eine Funktionsdefinition rendern möchten. Sie können den Aufruf dieser Funktion dann mit der vorherigen Methode rendern (oder ein clientseitiges Attribut hinzufügen).

Nach Kommentaren bearbeiten:


Zum Beispiel würde die folgende Funktion funktionieren:

protected void btnPostBack2_Click(object sender, EventArgs e) 
{ 
  System.Text.StringBuilder sb = new System.Text.StringBuilder(); 
  sb.Append("<script language='javascript'>function ChangeColor() {"); 
  sb.Append("var lbl = document.getElementById('lblDisplayDate');"); 
  sb.Append("lbl.style.color='green';"); 
  sb.Append("}</script>"); 

  //Render the function definition. 
  if (!ClientScript.IsClientScriptBlockRegistered("JSScriptBlock")) 
  {
    ClientScript.RegisterClientScriptBlock(this.GetType(), "JSScriptBlock", sb.ToString()); 
  }

  //Render the function invocation. 
  string funcCall = "<script language='javascript'>ChangeColor();</script>"; 

  if (!ClientScript.IsStartupScriptRegistered("JSScript"))
  { 
    ClientScript.RegisterStartupScript(this.GetType(), "JSScript", funcCall); 
  } 
} 
Cerebrus
quelle
1
Können Sie etwas mehr über die Inline-Funktionen erklären?
Xaisoft
2
Bearbeiten Sie meinen Beitrag, um ihn anhand Ihres Beispiels besser zu veranschaulichen.
Cerebrus
1
Ich bekomme eigentlich keinen Fehler, die Zeit wird aktualisiert, aber die Farbe ändert sich nicht. Was ist mit dem Teil meiner Frage, in dem ich frage, ob ich ScriptManagerProxy verwenden muss, wenn auf einer Masterseite bereits ein ScriptManager definiert ist?
Xaisoft
1
Bearbeitung abgeschlossen. Ich bin mir über den Fehler mit ScriptManagerProxy nicht sicher. Ich denke, Sie sollten bewerten, ob dies nicht wirklich eine separate Frage ist. ;-)
Cerebrus
1
Toll! Vielen Dank bisher. Ich erhalte keine Fehlermeldung mit ScriptManagerProxy. Ich weiß nur, dass Sie nur eine Instanz von ScriptManager deklarieren können. Wenn ich also bereits einen ScriptManager auf einer Masterseite definiert habe, würde ich davon ausgehen, dass ich stattdessen ScriptManagerProxy verwenden würde.
Xaisoft
6

Hier ist ein einfachstes Beispiel aus der ASP.NET-Community. Dies gab mir ein klares Verständnis für das Konzept.

Welchen Unterschied macht das?

Ein Beispiel hierfür ist eine Möglichkeit, den Fokus auf ein Textfeld auf einer Seite zu legen, wenn die Seite in den Browser geladen wird - mit Visual Basic mithilfe der folgenden RegisterStartupScriptMethode:

Page.ClientScript.RegisterStartupScript(Me.GetType(), "Testing", _ 
"document.forms[0]['TextBox1'].focus();", True)

Dies funktioniert gut, da das Textfeld auf der Seite generiert und auf der Seite platziert wird, wenn der Browser den unteren Rand der Seite erreicht und dieses kleine Stück JavaScript erreicht.

Aber wenn es stattdessen so geschrieben wurde (mit der RegisterClientScriptBlockMethode):

Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "Testing", _
"document.forms[0]['TextBox1'].focus();", True)

Der Fokus wird nicht auf das Textfeldsteuerelement gelegt und ein JavaScript-Fehler wird auf der Seite generiert

Der Grund dafür ist, dass der Browser auf das JavaScript stößt, bevor sich das Textfeld auf der Seite befindet. Daher kann das JavaScript keine TextBox1 finden.

cis-Benutzer
quelle