Differenza tra RegisterStartupScript e RegisterClientScriptBlock?


139

L'unica differenza tra il RegisterStartupScripte il RegisterClientScriptBlockè che RegisterStartupScript inserisce il javascript prima del </form>tag di chiusura della pagina e RegisterClientScriptBlock lo inserisce subito dopo il <form>tag iniziale della pagina?

Inoltre, quando sceglieresti l'uno rispetto all'altro? Ho scritto una rapida pagina di esempio in cui ho riscontrato un problema e non sono sicuro del motivo esatto per cui sta accadendo.

Ecco il markup aspx:

<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>

Ecco il codice dietro:

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());
    } 
 }

Il problema è quando faccio clic sul btnPostBackpulsante, fa un postback e cambia l'etichetta in rosso, ma quando faccio clic su btnPostBack2, fa un postback, ma il colore dell'etichetta non cambia in rosso. Perchè è questo? È perché l'etichetta non è inizializzata?

Ho anche letto che se si utilizza un UpdatePanel, è necessario utilizzare ScriptManager.RegisterStartupScript, ma se ho un MasterPage, dovrei usare ScriptManagerProxy?

Risposte:


162

Ecco un vecchio thread di discussione in cui ho elencato le principali differenze e le condizioni in cui è necessario utilizzare ciascuno di questi metodi. Penso che potresti trovare utile passare attraverso la discussione.

Per spiegare le differenze rilevanti per il tuo esempio pubblicato:

un. Quando lo usi RegisterStartupScript, eseguirà il rendering dello script dopo tutti gli elementi della pagina (subito prima del tag di fine del modulo). Ciò consente allo script di chiamare o fare riferimento a elementi della pagina senza la possibilità che non li trovi nel DOM della pagina.

Ecco la fonte renderizzata della pagina quando invochi il RegisterStartupScriptmetodo:

<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. Quando si utilizza RegisterClientScriptBlock, lo script viene visualizzato subito dopo il tag Viewstate, ma prima di uno qualsiasi degli elementi della pagina. Poiché si tratta di uno script diretto (non una funzione che può essere chiamata , verrà immediatamente eseguito dal browser. Ma il browser non trova l'etichetta nel DOM della Pagina in questa fase e quindi dovresti ricevere un "Oggetto non trovato" errore.

Ecco la fonte renderizzata della pagina quando invochi il RegisterClientScriptBlockmetodo:

<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';

Pertanto, per riassumere, è necessario chiamare quest'ultimo metodo se si intende eseguire il rendering di una definizione di funzione. È quindi possibile eseguire il rendering della chiamata a quella funzione utilizzando il metodo precedente (o aggiungere un attributo lato client).

Modifica dopo i commenti:


Ad esempio, la seguente funzione funzionerebbe:

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); 
  } 
} 

1
Puoi spiegarci un po 'di più sulle funzioni in linea.
Xaisoft,

2
Modifica il mio post per illustrarlo meglio con il tuo esempio.
Cerebrus,

1
In realtà non ricevo un errore, il tempo si aggiorna, ma il colore non cambia. Che dire della parte della mia domanda in cui chiedo se devo usare ScriptManagerProxy se ho già uno ScriptManager definito in una pagina master?
Xaisoft,

1
Fine modifica. Non sono sicuro dell'errore con ScriptManagerProxy. Penso che dovresti valutare se questa non è davvero una domanda separata. ;-)
Cerebrus,

1
Grande! Grazie finora. Non ricevo un errore con ScriptManagerProxy. So solo che puoi dichiarare solo un'istanza di ScriptManager, quindi se per esempio ho già uno ScriptManager definito in una pagina master, suppongo che utilizzerei invece ScriptManagerProxy.
Xaisoft,

6

Ecco un esempio più semplice della comunità ASP.NET, questo mi ha dato una chiara comprensione del concetto ...

che differenza fa?

Per un esempio di questo, ecco un modo per mettere a fuoco una casella di testo su una pagina quando la pagina viene caricata nel browser, con Visual Basic che utilizza il RegisterStartupScriptmetodo:

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

Funziona bene perché la casella di testo sulla pagina viene generata e posizionata sulla pagina quando il browser scende in fondo alla pagina e arriva a questo piccolo bit di JavaScript.

Ma, se invece è stato scritto in questo modo (usando il RegisterClientScriptBlockmetodo):

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

Lo stato attivo non arriverà al controllo della casella di testo e sulla pagina verrà generato un errore JavaScript

La ragione di ciò è che il browser incontrerà JavaScript prima che la casella di testo sia nella pagina. Pertanto, JavaScript non sarà in grado di trovare un TextBox1.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.