在由ASP.NET所謂前臺調用後臺、後臺調用前臺想到HTTP——理論篇中描述了一下ASP.NET新手的三個問題及相關的HTTP協議內容,在由ASP.NET所謂前臺調用後臺、後臺調用前臺想到HTTP——實踐篇(一)中已經解答了關於服務器怎麼改變頁面元素或「調用」JavaScript的問題,爲了不上篇囉囉嗦嗦一大推,此次直奔主題——ASP.NET前臺如何調用後臺方法javascript
所謂前臺調用後臺這種問題的提出無非是由於不少新手受了ASP.NET服務器端控件的「誤導」,你不是說前臺沒有把JavaScript語句、頁面元素什麼的傳到後臺,因此前臺調用後臺,或者後臺監視頁面變化是扯淡嘛!那ASP.NET中爲何服務器端控件一點擊就能調用後臺制定方法呢?按照你前面的理論即便用了服務器端控件,那麼到了瀏覽器頁面也變成最普通不過的HTML文本了,怎麼還可以調用服務器端方法呢?!css
確實,瀏覽器呈現的是HTML文本,咱們先不用拘泥於ASP.NET怎麼作到的前臺「調用」後臺,咱們能夠本身實現一下,不過在此以前咱們得明白一些過於Post的問題html
咱們在看不少網頁的時候都會看到這樣的內容java
<form id="form1" method="post" action="Default.aspx"> <input type="text" name="wd" /> <input type="submit" name="test" value="test" /> </form>
這段HTML文本同窗們都能看懂,頁面上有一個form,form內有兩個input,點擊submit的時候,頁面form內容會以post方式被提交到Default.aspx這個頁面。程序員
HTTP協議中的Post方法會將所處的form提交到form指定頁面,若是form指定的方法爲post(還多是get等),那麼form內有些數據會一併被提交。瀏覽器
既然不是整個form被提交,那麼哪些數據會被提交呢?服務器
1.input的name和valueide
2.input type=」submit」 只有被點擊的時候纔將其自己name與value提交函數
3.對於多個name相同的input type=」checkbox」,只有選中項的值會被提交(多個value以,鏈接)post
4.對於多個name相同的input type=」radio」,只有選中項的value會被提交(同名的radio只能單選)
5.select的name和被選中的option的vaue(不是option的text)
6.textarea 的name與value
這樣被提交的數據能夠在提交的頁面的後臺中以Request.Form[「name」]的方式查到其值
知道了form和post的最基本知識,咱們就能夠模擬ASP.NET的button調用後臺方法了,首先準備這樣一個頁面
<form id="form1" method="post" action="Default.aspx"> <input type="submit" name="test" value="test"/> </form>
在後臺添加想調用的方法
protected void test_Click(object sender, EventArgs e) { Response.Write("Button Click!"); }
很簡單的內容,後臺方法的兩個參數徹底能夠不用(和事件有關),填上只是爲了增長其逼真性,代碼中有幾個須要注意的地方
1.form的方法須要設爲post,這個很明顯。。。
2.form的action設爲頁面自己,也就是讓頁面提交給本身
3.input要有name
準備工做作好後就能夠模擬JavaScript調用後臺方法了,在頁面的 OnLoad方法中寫入代碼
protected override void OnLoad(EventArgs e) { if (Request.Form["test"]!=null) { test_Click(this, new EventArgs()); } base.OnLoad(e); }
聰明的同窗確定能夠看出端倪了,在點擊test的時候會提交表單,頁面的OnLoad會自動執行,這時候會判斷提交過來的表單中是否包含test(submit被點擊後會被提交,不點擊不提交,因此能夠根據name能夠判斷出哪一個按鈕被按了),就這麼簡單,點擊submit的時候,預約義的方法就被調用了,要是頁面上有不少submit,這時候就須要if-else或者switch或者for這樣的東西來判斷究竟是哪一個submit被點擊了,而後調用對應方法。
對比一下,ASP.NET正好用,首先人家的from是這樣的
<form id="form1" runat="server"> </form>
人家自動就給render成這樣了
咱們也不須要本身在OnLoad中添加if-else,只要在control的屬性中添加OnClick=」XXX」就能夠了,我沒看過.NET源碼,可是我大膽的揣測,雖然不用再OnLoad裏if-else了,但應該也是相似的方式處理。
細心的同窗可能要問了,你這麼作是能夠,可是依賴於表單提交,咱們知道並非全部的頁面元素都會點一下就提交表單,像控件asp: DropDownList的OnSelectIndexChanged事件,人家也會調用回臺方法,那是怎麼作的?
其實很是簡單,對於這種需求,仍然能夠用表單提交的方式處理,不能自動提交表單,那麼咱們能夠用JavaScript幫助其提交,看個select change 「調用」後臺函數的例子,首先像這樣修改頁面,添加一個select
<form id="form1" method="post" action="Default.aspx"> <input type="hidden" id="__param" name="__param" /> <input id="test" name="test" type="submit" value="test" /> <select id="select1" name="select1"> <option value="0">0</option> <option value="1">1</option> <option value="2">2</option> </select> <script type="text/javascript"> document.getElementById('select1').onchange = function () { document.getElementById('__param').value = this.name; document.getElementById('form1').submit(); }; </script> </form>
咱們除了select元素還添加了兩個內容,一個input type=」hidden」的隱藏元素,一段JavaScript腳本,在JavaScript腳本中對select的onchange綁定了一個方法,當select選擇項變化的時候,把其name賦值給隱藏域的value,而後提交表單,因爲隱藏域可定會被提交,這樣咱們能夠一樣在頁面的Onload中判斷誰的onchange觸發了,而後調用預約義方法,後臺代碼是這樣的
protected override void OnLoad(EventArgs e) { string param= Request.Form["__param"]; if (Request.Form["test"]!=null) { test_Click(this, new EventArgs()); } else if (param == "select1") { select_Change(this, new EventArgs()); } base.OnLoad(e); } protected void test_Click(object sender, EventArgs e) { Response.Write("Button Click!"); } protected void select_Change(object sender, EventArgs e) { string newValue = Request.Form["select1"]; Response.Write("Seclect value chaned to " + newValue); }
是否是很簡單呢?先判斷是否是submit,不是的話判斷隱藏域,命中後調用預約義方法。
細心的同窗仍然會發現問題,要是一個元素上同時又兩個事件怎麼辦?好比還想對這個select添加cilck事件怎麼辦,這時候咱們能夠修改隱藏域的值,不只記錄name,還記上事件類型,相似這樣
document.getElementById('select1').onchange = function () { document.getElementById('__param').value = this.name+"$ onchange"; document.getElementById('form1').submit(); }; document.getElementById('select1').onclick = function () { document.getElementById('__param').value = this.name+"$ onclick"; document.getElementById('form1').submit(); };
而後在後臺判斷的時候,咱們能夠先把參數按$分割爲兩個字符串,分別判斷元素與事件類型,固然咱們也能夠再添加一個隱藏域,用來記事件類型,大同小異。
還有同窗回問,若是我在客戶端一樣寫了select的onclick,不就把你的代碼覆蓋了嗎?這樣我就不能post了,對於這個問題咱們大能夠換種方式綁定事件處理程序,用addEventListener(attachEven)的方式,這樣post的代碼和本身寫的客戶端的就能夠同時存在了,這樣
var select = document.getElementById('select1'); select.onclick = function () { // // // }; select.addEventListener('clcik', function () {//瀏覽器兼容性問題要處理,這裏就不演示了 document.getElementById('__param').value = this.name + "$ onclick"; document.getElementById('form1').submit(); }, false);
咱們能夠看看ASP.NET是怎麼處理的,在頁面上寫一個DropDownList,設起AutoPostBack屬性爲true
<form id="form1" runat="server"> <asp:DropDownList ID="ddlTest" runat="server" AutoPostBack="true"> <asp:ListItem>1</asp:ListItem> <asp:ListItem>2</asp:ListItem> <asp:ListItem>3</asp:ListItem> </asp:DropDownList> </form>
生成的頁面源碼是這樣的
<html xmlns="http://www.w3.org/1999/xhtml"><head><title> </title><style type="text/css"></style></head> <body cz-shortcut-listen="true"> <form method="post" action="Default.aspx" id="form1"> <div class="aspNetHidden"> <input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value=""> <input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value=""> </div> <script type="text/javascript"> //<![CDATA[ var theForm = document.forms['form1']; if (!theForm) { theForm = document.form1; } function __doPostBack(eventTarget, eventArgument) { if (!theForm.onsubmit || (theForm.onsubmit() != false)) { theForm.__EVENTTARGET.value = eventTarget; theForm.__EVENTARGUMENT.value = eventArgument; theForm.submit(); } } //]]> </script> <div class="aspNetHidden"> <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEdAAWUpg6MZl3t8/pBYubwqWOJqSwDGOXu15HYfC2efhAyHc1gIfz8erLrnvHjMLCTGHuRsEl8lEzJ1SVLtM7lgCLfggLVPRtDk70yN7TcfPOwwBRLeEs10HSMSLT9zq5aYmmjMFX5QrdQAuJDrw+EXFTJ"> </div> <select name="ddlTest" onchange="javascript:setTimeout('__doPostBack(\'ddlTest\',\'\')', 0)" id="ddlTest"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> </form> </body></html>
主要是這個方法,認真讀讀是否是和咱們剛纔寫的相似呢,人家傳了兩個隱藏域,一個用來是Target,一個用來及參數
onchange="javascript:setTimeout('__doPostBack(\'ddlTest\',\'\')', 0)"
function __doPostBack(eventTarget, eventArgument) { if (!theForm.onsubmit || (theForm.onsubmit() != false)) { theForm.__EVENTTARGET.value = eventTarget; theForm.__EVENTARGUMENT.value = eventArgument; theForm.submit(); } }
經過上面例子分析能夠看得出來,JavaScript根本沒有調用後臺函數,只是提交了含有預設參數的表單,服務器根據參數調用後臺方法,生成特定HTML,所謂前臺調用後臺也就這麼回事兒。
有一個問題值得思考,爲何這種很想固然的作法PHP程序員能夠輕鬆想到,不少.NET初級程序員卻不行,甚至有時候咱們都已經在使用了,好比根據Url的QueryString來調用不一樣方法,或進行不一樣處理,卻沒有進一步想到更經常使用的Button、DropDownList是怎麼作到的?仍是那句話,.NET程序員當自勉,不要被.NET的易用性慣壞,多學習原理知識,不要過度知足於作出來,而要多追求爲何,這樣才能不斷進步。