Różnica między RegisterStartupScript i RegisterClientScriptBlock?


139

Czy jedyną różnicą między opcjami RegisterStartupScripti the RegisterClientScriptBlockjest to, że RegisterStartupScript umieszcza javascript przed zamykającym </form>tagiem strony, a RegisterClientScriptBlock umieszcza go zaraz po początkowym <form>tagu strony?

Kiedy wybrałbyś jedną z nich? Napisałem krótką przykładową stronę, na której miałem problem i nie jestem pewien dokładnego powodu, dla którego tak się dzieje.

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

Oto kod:

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

Problem polega na tym, że kiedy klikam btnPostBackprzycisk, robi to postback i zmienia etykietę na czerwoną, ale kiedy klikam btnPostBack2, robi postback, ale kolor etykiety nie zmienia się na czerwony. Dlaczego to? Czy to dlatego, że etykieta nie została zainicjowana?

Przeczytałem również, że jeśli używasz UpdatePanel, musisz użyć ScriptManager.RegisterStartupScript, ale jeśli mam MasterPage, czy użyłbym ScriptManagerProxy?

Odpowiedzi:


162

Oto stary wątek do dyskusji, w którym wymieniłem główne różnice i warunki, w których należy stosować każdą z tych metod. Myślę, że może ci się przydać przeprowadzenie dyskusji.

Aby wyjaśnić różnice istotne dla opublikowanego przykładu:

za. Kiedy użyjesz RegisterStartupScript, wyrenderuje twój skrypt po wszystkich elementach na stronie (tuż przed końcowym znacznikiem formularza). Umożliwia to skryptowi wywoływanie lub odwoływanie się do elementów strony bez możliwości ich nie znalezienia w DOM strony.

Oto wyrenderowane źródło strony po wywołaniu RegisterStartupScriptmetody:

<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. Kiedy używasz RegisterClientScriptBlock, skrypt jest renderowany zaraz po tagu Viewstate, ale przed jakimkolwiek elementem strony. Ponieważ jest to bezpośredni skrypt (nie jest funkcją, która może być nazywany , to natychmiast zostanie wykonany przez przeglądarkę. Ale przeglądarka nie znaleźć etykietę na stronie za DOM na tym etapie, a więc powinno się pojawić „Nie znaleziono obiektu” błąd.

Oto wyrenderowane źródło strony po wywołaniu RegisterClientScriptBlockmetody:

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

Dlatego, podsumowując, powinieneś wywołać tę drugą metodę, jeśli zamierzasz renderować definicję funkcji. Następnie możesz wyrenderować wywołanie tej funkcji przy użyciu poprzedniej metody (lub dodać atrybut po stronie klienta).

Edytuj po komentarzach:


Na przykład działałaby następująca funkcja:

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
Czy możesz wyjaśnić trochę więcej na temat funkcji wbudowanych.
Xaisoft

2
Edytujesz mój post, aby lepiej zilustrować go na twoim przykładzie.
Cerebrus

1
Właściwie nie wyskakuje mi błąd, czas się aktualizuje, ale kolor się nie zmienia. A co z częścią mojego pytania, w której pytam, czy muszę używać ScriptManagerProxy, jeśli mam ScriptManager już zdefiniowany na stronie wzorcowej?
Xaisoft

1
Zakończono edycję. Nie jestem pewien co do błędu związanego z ScriptManagerProxy. Myślę, że powinieneś ocenić, czy to naprawdę nie jest oddzielne pytanie. ;-)
Cerebrus

1
Wspaniały! Dzięki. Nie pojawia się błąd dotyczący ScriptManagerProxy. Wiem tylko, że możesz zadeklarować tylko jedno wystąpienie ScriptManager, więc jeśli mam już zdefiniowany ScriptManager na przykład na stronie wzorcowej, założyłbym, że zamiast tego użyłbym ScriptManagerProxy.
Xaisoft,

6

Oto najprostszy przykład ze społeczności ASP.NET, który dał mi jasne zrozumienie koncepcji ...

jaka to różnica?

Na przykład, oto sposób na umieszczenie fokusu na polu tekstowym na stronie, gdy strona jest ładowana do przeglądarki - w języku Visual Basic przy użyciu RegisterStartupScriptmetody:

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

Działa to dobrze, ponieważ pole tekstowe na stronie jest generowane i umieszczane na stronie, zanim przeglądarka przejdzie do dołu strony i dotrze do tego małego fragmentu JavaScript.

Ale jeśli zamiast tego zostało napisane w ten sposób (przy użyciu RegisterClientScriptBlockmetody):

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

Fokus nie przejdzie do kontrolki pola tekstowego i na stronie zostanie wygenerowany błąd JavaScript

Powodem tego jest to, że przeglądarka napotka JavaScript, zanim pole tekstowe znajdzie się na stronie. Dlatego JavaScript nie będzie w stanie znaleźć TextBox1.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.