ความแตกต่างระหว่าง RegisterStartupScript และ RegisterClientScriptBlock


140

ความแตกต่างเพียงอย่างเดียวระหว่างRegisterStartupScriptและRegisterClientScriptBlockคือ RegisterStartupScript วางจาวาสคริปต์ไว้ก่อน</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มันจะโพสต์แบ็ค แต่สีของป้ายกำกับไม่เปลี่ยนเป็นสีแดง ทำไมถึงเป็นแบบนี้? เป็นเพราะฉลากไม่ได้เริ่มต้น?

ฉันยังอ่านว่าถ้าคุณใช้ an UpdatePanelคุณต้องใช้ScriptManager.RegisterStartupScriptแต่ถ้าฉันมีMasterPageฉันจะใช้ScriptManagerProxyหรือไม่?

คำตอบ:


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 ของเพจในขั้นตอนนี้ดังนั้นคุณควรได้รับ "Object not found" ข้อผิดพลาด

นี่คือแหล่งที่มาของหน้าเมื่อคุณเรียกใช้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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.