前段時間參與一個公司的項目,使用ASP.NET MVC 3.0,其中有多處使用了級聯下拉。
考慮到這種ajax異步調用代碼重復且不方便調試,於是做了一個公用控件,實際是一個.NET MVC的PartialView。
PartialView:

@model Platform.Modules.Base.ViewModels.SelectViewModel <select id="@Model.Id" name="@Model.Name" class="@Model.Class" style="@Model.Style"><option value='@Model.DefaultValue'>@Model.DefaultText</option></select> <script type="text/javascript"> $(function () { var actionUrl = '@Model.ActionUrl'; var unselected = "<option value='@Model.DefaultValue'>@Model.DefaultText</option>"; var tagId,textProperty,valueProperty,parentTagId,paramName,currentSelectedValue,requestMethod; tagId = '@Model.Id'; textProperty='@Model.TextProperty'; valueProperty='@Model.ValueProperty'; parentTagId='@Model.ParentTagId'; paramName='@Model.ParamName'; currentSelectedValue='@Model.SelectedValue'; requestMethod='@Model.RequestMethod.ToString()'; @{if(String.IsNullOrEmpty(Model.ParentTagId)){ <text> $.ajax({ type: requestMethod, url: actionUrl+"?ts="+new Date().getTime(), cache:false, success: function(data){ $("#" + tagId).empty(); $("#" + tagId).append(unselected); $.each(data, function (i, item) { if($(item).attr(valueProperty)==currentSelectedValue){ $("#" + tagId).append($("<option selected='selected' value='" + $(item).attr(valueProperty) + "'>" + $(item).attr(textProperty) + "</option>")); }else{ $("#" + tagId).append($("<option value='" + $(item).attr(valueProperty) + "'>" + $(item).attr(textProperty) + "</option>")); } }); }, complete:function() { if(currentSelectedValue!=null){ if($('#'+tagId).fireEvent) $('#'+tagId).fireEvent("onchange"); else $('#'+tagId).change(); } } }); </text> }else{ <text> $("#" + parentTagId).change(function () { $('#'+tagId).empty(); $('#'+tagId).append(unselected); if($('#'+tagId).fireEvent) $('#'+tagId).fireEvent("onchange"); else $('#'+tagId).change(); var parentValue = $(this).val(); if (!parentValue) { return; } $.ajax({ type: requestMethod, url: actionUrl+"?ts="+new Date().getTime(), data: paramName+"=" + parentValue, cache:false, success: function(data){ $.each(data, function (i, item) { if($(item).attr(valueProperty)==currentSelectedValue){ $("#" + tagId).append($("<option selected='selected' value='" + $(item).attr(valueProperty) + "'>" + $(item).attr(textProperty) + "</option>")); }else{ $("#" + tagId).append($("<option value='" + $(item).attr(valueProperty) + "'>" + $(item).attr(textProperty) + "</option>")); } }); }, complete:function() { if(currentSelectedValue!=null){ if($('#'+tagId).fireEvent) $('#'+tagId).fireEvent("onchange"); else $('#'+tagId).change(); } } }); }); </text> } } }); </script>
該控件使用到的Model類:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web.Mvc; namespace Platform.Modules.Base.ViewModels { public class SelectViewModel { /// <summary> /// select標簽Id /// </summary> public String Id { get; set; } /// <summary> /// select標簽Name /// </summary> public String Name { get; set; } /// <summary> /// json數據源元素中代表select>option>Text的屬性 /// </summary> public String TextProperty { get; set; } /// <summary> /// json數據源元素中代表select>option>value的屬性 /// </summary> public String ValueProperty { get; set; } /// <summary> /// 數據源獲取地址 /// </summary> public String ActionUrl { get; set; } /// <summary> /// select標簽初始項文本,默認為空字符串 /// </summary> public String DefaultText { get; set; } /// <summary> /// select標簽初始項值,默認為空字符串 /// </summary> public String DefaultValue{ get; set; } /// <summary> /// 獲取數據時傳遞的參數名 /// </summary> public String ParamName { get; set; } /// <summary> /// 父級下拉框的標簽id /// 有父級必選 /// </summary> public String ParentTagId { get; set; } /// <summary> /// 樣式表 /// </summary> public String Class { get; set; } /// <summary> /// 樣式 /// </summary> public String Style { get; set; } /// <summary> /// select標簽當前選定項 /// </summary> public String SelectedValue { get; set; } private FormMethod requestMethod = FormMethod.Get; /// <summary> /// 請求方式 /// 默認為GET /// </summary> public FormMethod RequestMethod { get { return requestMethod; } set { requestMethod = value; } } } }
Demo:

public ActionResult GetProvinces() { var entities = locationService.GetProvinceList(); return Json(entities, JsonRequestBehavior.AllowGet); } public ActionResult GetCities(String provinceCode) { var entities = locationService.GetCityList(new CityQuery() { ProvinceCode = provinceCode }); return Json(entities, JsonRequestBehavior.AllowGet); } public ActionResult GetCounties(String cityCode) { var entities = locationService.GetCountyList(new CountyQuery() { CityCode = cityCode }); return Json(entities, JsonRequestBehavior.AllowGet); } /// <summary> /// 測試頁Action /// </summary> /// <returns></returns> public ActionResult SelectControlTest() { return View(); }

@{ ViewBag.Title = "SelectControlTest"; } @using Platform.Modules.Base.ViewModels <h2>SelectControlTest</h2> 省:@{Html.RenderPartial("SelectView", new SelectViewModel() { ActionUrl = Url.Action("GetProvinces", "Location"), DefaultText = "---請選擇---", DefaultValue = "", Id = "aaaaa", Name = "aaaaa", TextProperty = "Name", ValueProperty = "Code", Style = "width:173px", });} 市:@{Html.RenderPartial("SelectView",new SelectViewModel(){ ActionUrl = Url.Action("GetCities", "Location"), DefaultText="---請選擇---", DefaultValue="", Id="bbbbbb", ParentTagId="aaaaa", ParamName = "provinceCode", Name="bbbbbb", TextProperty="Name", ValueProperty = "Code", Style = "width:173px" });} 縣:@{Html.RenderPartial("SelectView",new SelectViewModel(){ ActionUrl = Url.Action("GetCounties", "Location"), DefaultText="---請選擇---", DefaultValue="", Id="cccccc", ParamName = "cityCode", ParentTagId="bbbbbb", Name="cccccc", TextProperty="Name", ValueProperty="Code", Style = "width:173px" });}
理論上支持無限級聯。。
支持Post,Get兩種請求方式。默認使用Get方式。
注意:使用Get方式請求Action,返回JSON的時候一定要加JsonRequestBehavior.AllowGet。