Разница между RegisterStartupScript и RegisterClientScriptBlock?

140

Единственная разница между RegisterStartupScriptи RegisterClientScriptBlockзаключается в том, что RegisterStartupScript помещает javascript перед закрывающим </form>тегом страницы, а RegisterClientScriptBlock помещает его сразу после начального <form>тега страницы?

Кроме того, когда бы вы предпочли одно другому? Я написал краткий образец страницы, где у меня возникла проблема, и я не уверен, в какой именно причине это происходит.

Вот разметка 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>

Вот скрытый код:

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

Проблема в том, что когда я нажимаю btnPostBackкнопку, выполняется обратная передача и изменение метки на красный, но когда я нажимаю кнопку btnPostBack2, выполняется обратная передача, но цвет метки не меняется на красный. Почему это? Это потому, что метка не инициализирована?

Я также читал, что если вы используете UpdatePanel, вам нужно использовать ScriptManager.RegisterStartupScript, но если у меня есть MasterPage, я бы использовал ScriptManagerProxy?

Xaisoft
источник

Ответы:

163

Вот старая ветка обсуждения, в которой я перечислил основные отличия и условия, в которых вы должны использовать каждый из этих методов. Думаю, вам будет полезно пройти обсуждение.

Чтобы объяснить различия, относящиеся к вашему опубликованному примеру:

а. Когда вы используете RegisterStartupScript, он будет отображать ваш скрипт после всех элементов на странице (прямо перед закрывающим тегом формы). Это позволяет сценарию вызывать элементы страницы или ссылаться на них без возможности их обнаружения в DOM страницы.

Вот визуализированный источник страницы при вызове RegisterStartupScriptметода:

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

б. При использовании RegisterClientScriptBlockсценарий отображается сразу после тега Viewstate, но перед любым из элементов страницы. Поскольку это прямой сценарий (не вызываемая функция , он будет немедленно выполнен браузером. Но браузер не находит метку в DOM страницы на этом этапе, и, следовательно, вы должны получить сообщение «Объект не найден») ошибка.

Вот визуализированный источник страницы при вызове RegisterClientScriptBlockметода:

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

Поэтому, чтобы подвести итог, вы должны вызвать последний метод, если вы собираетесь визуализировать определение функции. Затем вы можете выполнить вызов этой функции с помощью прежнего метода (или добавить атрибут на стороне клиента).

Редактировать после комментариев:


Например, будет работать следующая функция:

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
Не могли бы вы подробнее рассказать о встроенных функциях.
Xaisoft,
2
Редактирую свой пост, чтобы лучше проиллюстрировать его на вашем примере.
Cerebrus
1
На самом деле у меня ошибки нет, время обновляется, но цвет не меняется. Как насчет части моего вопроса, где я спрашиваю, нужно ли мне использовать ScriptManagerProxy, если у меня уже есть ScriptManager, определенный на главной странице?
Xaisoft
1
Закончив редактирование. Я не уверен в ошибке ScriptManagerProxy. Я думаю, вам стоит оценить, действительно ли это отдельный вопрос. ;-)
Cerebrus
1
Большой! Пока спасибо. Я не получаю сообщения об ошибке ScriptManagerProxy. Я просто знаю, что вы можете объявить только один экземпляр ScriptManager, поэтому, если у меня уже есть ScriptManager, например, определенный на главной странице, я бы предположил, что вместо этого я бы использовал ScriptManagerProxy.
Xaisoft,
6

Вот простейший пример из сообщества ASP.NET, он дал мне четкое представление о концепции ...

какая разница?

В качестве примера приведем способ навести фокус на текстовое поле на странице, когда страница загружается в браузер - с помощью Visual Basic, используя RegisterStartupScriptметод:

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

Это хорошо работает, потому что текстовое поле на странице создается и размещается на странице к тому моменту, когда браузер переходит к нижней части страницы и переходит к этому небольшому фрагменту JavaScript.

Но, если бы вместо этого было написано так (с помощью RegisterClientScriptBlockметода):

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

Фокус не попадет в элемент управления текстовым полем, и на странице будет сгенерирована ошибка JavaScript.

Причина этого в том, что браузер обнаружит код JavaScript до того, как текстовое поле появится на странице. Следовательно, JavaScript не сможет найти TextBox1.

пользователь c-sharp
источник