之前的“省市县镇”四级控件是使用 MagicAjax 开发的。每一级都是到数据库中读取。经过 DBA 分析,
和该控件有关的表查询量很大, SQL 语句解析次数也非常多,虽然是 Oracle 数据库还是要尽量避免的。
为此新的控件将“省市”两级的数据存放在 JS 里,而“县镇”两级从数据库中读取,同时再结合项目需
要的特殊功能。
主要功能:
用户访问网站,首先根据二级域名加载用户所在的地区(如 http://xm.XXXX.com 福建-厦门)。如果没
有二级域名,那么根据 Cookie (如果之前访问过)加载用户所在的地区。如果没有,最后根据 IP 来
加载用户所在的地区。
如果是通过 Cookie 或是 IP 来判断,最后还要进行重定向(就是将 http://www.XXXX.com 转成
http://bj.XXXX.com)。如果是根据 IP 判断的,还要把用户所在的地区存入 Cookie。方便下次使用。
为了能从数据库读取数据,直接加载相应地区,还有能从下拉框中读取用户选择的地区就自定义一些属性。
特殊功能
是否重定向、是否只显示“省市”两级、是否垂直排列下拉框(默认是横向)、是否在在省份下拉框前
显示“省份”,城市下拉框前显示“城市”......、是否禁用控件(有些情况下,你可能要禁止用户选
择,等满足条件后才能选)
其他说明
前台脚本采用 JavaScript 和 DOM 互操作,全部使用 W3C 标准使其在各种浏览器下都正常。操作
<select> 采用更通用的 createElement() 而没有使用 options.add()。
后台采用 ASP.NET 进行少量操作(保存 Cookie||读数据库)
前后台采用 AjaxPro 使 JavaScript 和 C# 交互(传递枚举||调用方法||传递结果集)这部分应该是
重点....脚本和高级语言的交互是很让人向往的...暂时只会第三方 Ajax
最后采用一些看似多余的调用,实际上是为了防止 AjaxPro 生成的代码泄露了程序集和命名空间,老
大要求的...
顺便说下,如果数据库设计合理,前两位省份,中间两位城市,最后两位县/区,那么程序中很多地方
的代码都能省了...可见良好的数据库设计是非常重要的。
项目请一定要采用 AjaxPro 6.10.4.1 版本,其他版本有 BUG ,我也是开发中被搞乱了
下面就是源码了,没什么好说了...注释都很详细了
首先是 AreaInfo.cs 地区信息实体类,方便在其他程序读取用的
... {
/**//// <summary>
/// 地区信息类
/// </summary>
public sealed class AreaInfo
...{
private int _SFID;
private int _CSID;
private int _XianID;
private int _ZhenID;
private string _SF;
private string _CS;
private string _Xian;
private string _Zhen;
private string _Domain;
/**//// <summary>
/// 省份ID
/// </summary>
public int SFID
...{
get ...{ return this._SFID; }
set ...{ this._SFID = value; }
}
/**//// <summary>
/// 城市ID
/// </summary>
public int CSID
...{
get ...{ return this._CSID; }
set ...{ this._CSID = value; }
}
/**//// <summary>
/// 县/区ID
/// </summary>
public int XianID
...{
get ...{ return this._XianID; }
set ...{ this._XianID = value; }
}
/**//// <summary>
/// 镇
/// </summary>
public int ZhenID
...{
get ...{ return this._ZhenID; }
set ...{ this._ZhenID = value; }
}
/**//// <summary>
/// 省份名称
/// </summary>
public string SF
...{
get ...{ return this._SF; }
set ...{ this._SF = value; }
}
/**//// <summary>
/// 城市名称
/// </summary>
public string CS
...{
get ...{ return this._CS; }
set ...{ this._CS = value; }
}
/**//// <summary>
/// 县/区名称
/// </summary>
public string Xian
...{
get ...{ return this._Xian; }
set ...{ this._Xian = value; }
}
/**//// <summary>
/// 镇名称
/// </summary>
public string Zhen
...{
get ...{ return this._Zhen; }
set ...{ this._Zhen = value; }
}
/**//// <summary>
/// 域名
/// </summary>
public string Domain
...{
get ...{ return this._Domain; }
set ...{ this._Domain = value; }
}
}
}
接下来是数据访问层,项目使用的是 Oracle
using System.Data;
using System.Data.OracleClient;
using System.Web;
namespace AreaDropDownList
... {
/**//// <summary>
/// 地区控件数据访问操作层
/// </summary>
public static class AreaDAL
...{
private static readonly string Link = "server=gou200;user=gou;pwd=gou;";
private static readonly string CookieDomain = "xxx.cn"; //Cookie 的域
/**//// <summary>
/// 返回符合 SQL语句 的 DataTable
/// </summary>
/// <param name="sql">SQL 语句</param>
/// <returns></returns>
public static DataTable GetDataTable(string sql)
...{
OracleConnection conn = new OracleConnection(Link);
OracleDataAdapter adapter = new OracleDataAdapter(sql, conn);
DataTable table = new DataTable();
adapter.Fill(table);
return table;
}
/**//// <summary>
/// 将当前所有下拉框的值存入 Cookie
/// </summary>
/// <param name="sfid">省份ID</param>
/// <param name="csid">城市ID</param>
/// <param name="xianid">县/区ID</param>
/// <param name="zhenid">镇ID</param>
/// <param name="sf">省份名</param>
/// <param name="cs">城市名</param>
/// <param name="xian">县/区名</param>
/// <param name="zhen">镇名</param>
/// <param name="domain">地区域名</param>
public static void SaveCookie(int sfid, int csid, int xianid, int zhenid, string sf, string cs, string xian, string zhen, string domain)
...{
HttpCookie cookie = new HttpCookie("Area");
cookie["SFID"] = sfid.ToString();
cookie["CSID"] = csid.ToString();
cookie["XianID"] = xianid.ToString();
cookie["ZhenID"] = zhenid.ToString();
cookie["SF"] = HttpContext.Current.Server.UrlEncode(String.IsNullOrEmpty(sf) ? "" : sf.Replace("—请选择—", ""));
cookie["CS"] = HttpContext.Current.Server.UrlEncode(String.IsNullOrEmpty(cs) ? "" : cs.Replace("—请选择—", ""));
cookie["Xian"] = HttpContext.Current.Server.UrlEncode(String.IsNullOrEmpty(xian) ? "" : xian.Replace("—请选择—", ""));
cookie["Zhen"] = HttpContext.Current.Server.UrlEncode(String.IsNullOrEmpty(zhen) ? "" : zhen.Replace("—请选择—", ""));
cookie["Domain"] = domain;
cookie.Domain = CookieDomain;
cookie.Expires = DateTime.Now.AddDays(CookieDay);
HttpContext.Current.Response.Cookies.Add(cookie);
}
/**//// <summary>
/// 将地区信息存入 Cookie
/// </summary>
/// <param name="ai">地区信息</param>
private static void SaveCookie(AreaInfo ai)
...{
SaveCookie(ai.SFID, ai.CSID, ai.XianID, ai.ZhenID, ai.SF, ai.CS, ai.Xian, ai.Zhen, ai.Domain);
}
/**//*=====================================================================*/
/**//// <summary>
/// 通过 域名 加载相应的地区
/// </summary>
/// <returns></returns>
public static AreaInfo GetAreaInfoByDomain()
...{
string domain = HttpContext.Current.Request.Url.Host.Split('.')[0].ToLower();
if (IsSecondDomain(domain))
return null;
AreaInfo ai;
HttpCookie cookie = HttpContext.Current.Request.Cookies["Area"];
if (cookie != null && cookie["Domain"] == domain)
...{
//Cookie 里的域名和当前的域名相同,说明 Cookie 里有更详细的地区信息(如:从 Cookie 重定向而来)
ai = new AreaInfo();
ai.SFID = Convert.ToInt32(cookie["SFID"]);
ai.CSID = Convert.ToInt32(cookie["CSID"]);
ai.XianID = Convert.ToInt32(cookie["XianID"]);
ai.ZhenID = Convert.ToInt32(cookie["ZhenID"]);
ai.SF = HttpContext.Current.Server.UrlDecode(cookie["SF"]);
ai.CS = HttpContext.Current.Server.UrlDecode(cookie["CS"]);
ai.Xian = HttpContext.Current.Server.UrlDecode(cookie["Xian"]);
ai.Zhen = HttpContext.Current.Server.UrlDecode(cookie["Zhen"]);
ai.Domain = cookie["Domain"];
}
else
...{
ai = GetAreaInfoByDomain(domain);
if (ai == null)
return null;
SaveCookie(ai);
}
return ai;
}
/**//// <summary>
/// 返回域名对应的地区信息
/// </summary>
/// <param name="domain">三级域名</param>
/// <returns></returns>
private static AreaInfo GetAreaInfoByDomain(string domain)
...{
OracleConnection conn = new OracleConnection(Link);
//使用一条SQL 代替 多次SQL查询
string sql = String.Format("SELECT cs.csid,(cs.sfid || sf.sfid) AS sfid,cs.CityName,(cs.sfname || sf.sfname) AS sfname FROM (SELECT c.pkid AS csid,c.OneID AS sfid,c.CityName AS CityName,s.sfname AS sfname FROM (SELECT PKID,OneID,CityName FROM CityInfo WHERE CityDomain='{0}') c RIGHT JOIN(SELECT pkid,CityName AS sfname FROM CityInfo WHERE pkid=(SELECT OneID FROM CityInfo WHERE CityDomain='{0}')) s ON c.oneid=s.pkid) cs FULL OUTER JOIN (SELECT pkid AS sfid,CityName AS sfname FROM cityinfo WHERE citydomain='{0}' AND OneID=0) sf ON cs.sfid=sf.sfid", domain);
OracleCommand cmd = new OracleCommand(sql, conn);
conn.Open();
OracleDataReader dr = cmd.ExecuteReader();
if (dr.Read())
...{
AreaInfo ai = new AreaInfo();
Object[] os = new object[dr.FieldCount];
dr.GetValues(os);
dr.Close();
conn.Close();
ai.CSID = (os[0] is DBNull) ? 0 : Convert.ToInt32(os[0]);
ai.SFID = (os[1] is DBNull) ? 0 : Convert.ToInt32(os[1]);
ai.CS = (os[2] is DBNull) ? String.Empty : os[2].ToString();
ai.SF = (os[3] is DBNull) ? String.Empty : os[3].ToString();
ai.Domain = domain;
return ai;
}
dr.Close();
conn.Close();
return null;
}
/**//// <summary>
/// 是否是二级域名
/// </summary>
/// <param name="domain">可能是二级域名的字符串</param>
/// <returns>是,返回 ture</returns>
private static bool IsSecondDomain(string domain)
...{
foreach (string sd in SecondDomain)
...{
if (domain == sd)
return true;
}
return false;
}
/**//*=====================================================================*/
/**//// <summary>
/// 返回 Cookie 对应的地区信息
/// </summary>
/// <returns></returns>
public static AreaInfo GetAreaInfoByCookie()
...{
AreaInfo ai = new AreaInfo();
HttpCookie cookie = HttpContext.Current.Request.Cookies["Area"];
if (cookie == null)
return null;
ai.SFID = Convert.ToInt32(cookie["SFID"]);
ai.CSID = Convert.ToInt32(cookie["CSID"]);
ai.XianID = Convert.ToInt32(cookie["XianID"]);
ai.ZhenID = Convert.ToInt32(cookie["ZhenID"]);
ai.SF = HttpContext.Current.Server.UrlDecode(cookie["SF"]);
ai.CS = HttpContext.Current.Server.UrlDecode(cookie["CS"]);
ai.Xian = HttpContext.Current.Server.UrlDecode(cookie["Xian"]);
ai.Zhen = HttpContext.Current.Server.UrlDecode(cookie["Zhen"]);
ai.Domain = cookie["Domain"];
if (ai.SFID == 0)
return null;
return ai;
}
/**//*=====================================================================*/
/**//// <summary>
/// 通过 IP 加载相应的地区
/// </summary>
/// <returns></returns>
public static AreaInfo GetAreaInfoByIP()
...{
AreaInfo ai = GetAreaInfoByIP(HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]);
if (ai == null)
return null;
SaveCookie(ai);
return ai;
}
/**//// <summary>
/// 返回 IP 对应的地区信息
/// </summary>
/// <param name="ip">IP字符串</param>
/// <returns></returns>
private static AreaInfo GetAreaInfoByIP(string ip)
...{
AreaInfo ai = new AreaInfo();
uint IpNum;
string[] IPList = ip.Split('.');
IpNum = Convert.ToUInt32(Convert.ToUInt32(IPList[0]) * 255 * 255 * 255 + Convert.ToUInt32(IPList[1]) * 255 * 255 + Convert.ToUInt32(IPList[2]) * 255 + Convert.ToUInt32(IPList[3]));
string sql = String.Format("SELECT i.sfid00,i.CityCode,i.sfname,i.CityName,c.CityDomain FROM (SELECT CityDomain,pkid FROM CityInfo) c RIGHT JOIN (SELECT SFID00,CityCode,SFName,CityName FROM T_BM_Ip WHERE IpOne<={0} AND IpTwo>={0}) i ON c.pkid=i.CityCode", IpNum);
OracleConnection conn = new OracleConnection(Link);
OracleCommand cmd = new OracleCommand(sql, conn);
conn.Open();
OracleDataReader dr = cmd.ExecuteReader();
if (dr.Read())
...{
Object[] os = new object[dr.FieldCount];
dr.GetValues(os);
dr.Close();
conn.Close();
ai.SFID = (os[0] is DBNull) ? 0 : Convert.ToInt32(os[0]);
ai.CSID = (os[1] is DBNull) ? 0 : Convert.ToInt32(os[1]);
ai.SF = (os[2] is DBNull) ? String.Empty : os[2].ToString();
ai.CS = (os[3] is DBNull) ? String.Empty : os[3].ToString();
ai.Domain = (os[4] is DBNull) ? String.Empty : os[4].ToString();
return ai;
}
dr.Close();
conn.Close();
ai.SFID = 11; //设置默认值
ai.SF = "北京";
ai.Domain = "bj";
return ai;
}
}
}
然后就是重点了...用户控件 前台代码,中间有段很长的 省份城市JS 数组,我去掉了,想看可以去另一篇同名 blog 看
< div >
< table id = " AreaTable " runat = " server " >
< tr >
< td >
< select id = " sSF " runat = " server " >
< option selected = " selected " value = " 0 " > —请选择— </ option >
</ select >
</ td >
< td >
< select id = " sCS " runat = " server " >
< option selected = " selected " value = " 0 " > —请选择— </ option >
</ select >
</ td >
< td >
< select id = " sXian " runat = " server " >
< option selected = " selected " value = " 0 " > —请选择— </ option >
</ select >
</ td >
< td >
< select id = " sZhen " runat = " server " >
< option selected = " selected " value = " 0 " > —请选择— </ option >
</ select >
</ td >
</ tr >
</ table >
< input type = " hidden " id = " hSF " runat = " server " />
< input type = " hidden " id = " hCS " runat = " server " />
< input type = " hidden " id = " hXian " runat = " server " />
< input type = " hidden " id = " hZhen " runat = " server " />
< input type = " hidden " id = " hDomain " runat = " server " />
</ div >
< script type = " text/javascript " >
// <%-- ID 城市 上级ID 二级域名--%>
var aDQ = new Array();
// <%-- 省份的上级ID改为 -1 和 "—请选择—" 区分开 --%>
aDQ[ 0 ] = [ " 11 " , " 北京 " , " -1 " , " bj " ];
// 该数组请去另一篇 Blog 看
// <%-- 通过 DOM 创建下拉框 --%>
// <%-- obj:下拉框的 options 数据集 --%>
// <%-- id:下拉框的 id --%>
function CreateDropDownList(obj,id)
... {
var sel=document.getElementById(id);
if(sel==null) //<%-- 可能只显示省市 --%>
return;
sel.options.length=1; //<%-- 保存"—请选择—" --%>
//<%-- 对于省份、城市常用 Array 存储,对于县、镇则从数据库读取 --%>
if(obj==null)
return;
if(obj instanceof Array)
...{
for(var i=0;i<obj.length;i++)
...{
var op=document.createElement("option");
op.setAttribute("value",obj[i][0]); //<%-- 可考虑改成 value="xm,厦门">厦门 --%>
var txt=document.createTextNode(obj[i][1]);
op.appendChild(txt);
sel.appendChild(op);
}
}
else
...{
for(var i=0;i<obj.Rows.length;i++) //<%-- 注意这里是 length 不是 Count --%>
...{
var op=document.createElement("option");
op.setAttribute("value",obj.Rows[i].ID); //<%-- 注意区分大小写 --%>
var txt=document.createTextNode(obj.Rows[i].NAME); //<%-- 根 DataTable 的列名称要一致 --%>
op.appendChild(txt);
sel.appendChild(op);
}
}
//<%-- 绑定下一个下拉框 --%>
switch(id)
...{
//<%-- 选择一次,保存到 Cookie 一次,可以往 onchange 事件里加入 Save(); --%>
case "<%=this.sSF.ClientID%>":sel.onchange=function()...{ClearXianZhen();CreateDropDownList(GetArray(this.value),"<%=this.sCS.ClientID%>");Save();};break;
case "<%=this.sCS.ClientID%>":sel.onchange=function()...{ClearZhen();CreateDropDownList(AreaControl.GetDataTable(this.value,AreaEnum.Xian).value,"<%=this.sXian.ClientID%>");Save();};break; //<%-- JS 向 C# 传递参数,并取得 C# 的返回值 --%>
case "<%=this.sXian.ClientID%>":sel.onchange=function()...{CreateDropDownList(AreaControl.GetDataTable(this.value,AreaEnum.Zhen).value,"<%=this.sZhen.ClientID%>");Save();};break; //<%-- 返回值.value --%>
default:sel.onchange=function()...{Save();};break; //alert(this.value);
}
}
// <%-- 获取要求的数组 --%>
// <%-- val:所属的省份ID --%>
function GetArray(val)
... {
if(val==0) //<%-- 用户选"—请选择—"不查询 --%>
return null;
var temp=new Array();
var j=0;
for(var i=0;i<aDQ.length;i++)
...{
if(val==aDQ[i][2].toString())
...{
temp[j]=aDQ[i];
j++;
}
}
return temp;
}
// <%-- 清空"镇"下拉框 --%>
function ClearZhen()
... {
CreateDropDownList(null,"<%=this.sZhen.ClientID%>");
}
// <%-- 清空"县"和"镇"下拉框 --%>
function ClearXianZhen()
... {
CreateDropDownList(null,"<%=this.sXian.ClientID%>");
CreateDropDownList(null,"<%=this.sZhen.ClientID%>");
}
// <%-- 将当前所有下拉框的值存入 Cookie --%>
function Save()
... {
var sf=Single("<%=this.sSF.ClientID%>","<%=this.hSF.ClientID%>");
var cs=Single("<%=this.sCS.ClientID%>","<%=this.hCS.ClientID%>");
var xian=Single("<%=this.sXian.ClientID%>","<%=this.hXian.ClientID%>");
var zhen=Single("<%=this.sZhen.ClientID%>","<%=this.hZhen.ClientID%>");
var domain=GetDomain((cs.ID==0)?sf.ID:cs.ID);
document.getElementById("<%=this.hDomain.ClientID%>").value=domain;
//<%-- 暂时不存 Cookie ,只存到隐藏控件里 --%>
//<%-- AreaControl.SaveCookie(sf.ID,cs.ID,xian.ID,zhen.ID,sf.Name,cs.Name,xian.Name,zhen.Name,domain); --%>
}
// <%-- 返回单个下拉框的值和文本 --%>
// <%-- sid:下拉框ID --%>
// <%-- hid:隐藏控件ID --%>
function Single(sid,hid)
... {
var sel=document.getElementById(sid);
var a=new Area();
if(sel==null) //<%-- 可能只显示省市 --%>
return a;
a.ID=sel.value; //<%-- 取得下拉框的 value --%>
a.Name=sel.options[sel.selectedIndex].text; //<%-- 取得下拉框的 text --%>
document.getElementById(hid).value=a.Name; //<%-- text 另存到隐藏控件里 --%>
return a;
}
// <%-- 构造函数 --%>
function Area()
... {
this.ID; //<%-- 下拉框的值 --%>
this.Name; //<%-- 下拉框的文本 --%>
}
// <%-- 返回 ID 对应的域名 --%>
// <%-- id:地区ID --%>
function GetDomain(id)
... {
for(var i=0;i<aDQ.length;i++)
...{
if(aDQ[i][0]==id)
return aDQ[i][3];
}
return "";
}
/**/ /*<%------------------------------------------------------------------%>*/
// <%-- 通过 域名 加载相应的地区 --%>
function LoadAreaByDomain()
... {
var ai=AreaControl.GetAreaInfoByDomain().value;
if(ai==null)
return false;
Bind(ai);
return true;
}
// <%-- 根据地区信息绑定相应的下拉框 --%>
// <%-- ai:地区信息类 --%>
function Bind(ai)
... {
bind(ai.SFID,ai.CSID,ai.XianID,ai.ZhenID);
}
// <%-- 根据地区信息绑定相应的下拉框 --%>
// <%-- 因为JS不支持重载写成2个方法 --%>
function bind(sfid,csid,xianid,zhenid)
... {
var index;
if(sfid!=0)
...{
index=Val2Index(sfid,"<%=this.sSF.ClientID%>");
document.getElementById("<%=this.sSF.ClientID%>").selectedIndex=index;
document.getElementById("<%=this.hSF.ClientID%>").value=Index2Text(index,"<%=this.sSF.ClientID%>"); //<%-- text 另存到隐藏控件里 --%>
CreateDropDownList(GetArray(sfid.toString()),"<%=this.sCS.ClientID%>");
}
if(csid!=0)
...{
index=Val2Index(csid,"<%=this.sCS.ClientID%>");
document.getElementById("<%=this.sCS.ClientID%>").selectedIndex=index;
document.getElementById("<%=this.hCS.ClientID%>").value=Index2Text(index,"<%=this.sCS.ClientID%>");
CreateDropDownList(AreaControl.GetDataTable(csid.toString(),AreaEnum.Xian).value,"<%=this.sXian.ClientID%>") //<%-- 要把 int 型的转换成字符串--%>
}
if(xianid!=0 && document.getElementById("<%=this.sXian.ClientID%>")!=null) //<%-- 可能只显示省市 --%>
...{
index=Val2Index(xianid,"<%=this.sXian.ClientID%>");
document.getElementById("<%=this.sXian.ClientID%>").selectedIndex=index;
document.getElementById("<%=this.hXian.ClientID%>").value=Index2Text(index,"<%=this.sXian.ClientID%>");
CreateDropDownList(AreaControl.GetDataTable(xianid.toString(),AreaEnum.Zhen).value,"<%=this.sZhen.ClientID%>");
}
if(zhenid!=0 && document.getElementById("<%=this.sZhen.ClientID%>")!=null)
...{
index=Val2Index(zhenid,"<%=this.sZhen.ClientID%>");
document.getElementById("<%=this.sZhen.ClientID%>").selectedIndex=index;
document.getElementById("<%=this.hZhen.ClientID%>").value=Index2Text(index,"<%=this.sZhen.ClientID%>");
}
document.getElementById("<%=this.hDomain.ClientID%>").value=GetDomain((csid==0)?sfid:csid);
}
// <%-- 将 <select> 的 value 换算成 selectedIndex --%>
// <%-- val:下拉框的值 --%>
// <%-- id:下拉框 ID --%>
function Val2Index(val,id)
... {
var sel=document.getElementById(id);
for(var i=0;i<sel.options.length;i++)
...{
if(val==sel.options[i].value)
return i;
}
return 0;
}
// <%-- 将 <select> 的 value 换算成 text --%>
// <%-- index:下拉框的值 --%>
// <%-- id:下拉框 ID --%>
function Index2Text(index,id)
... {
return document.getElementById(id).options[index].text;
}
/**/ /*<%------------------------------------------------------------------%>*/
// <%-- 通过 cookie 加载相应的地区 --%>
function LoadAreaByCookie()
... {
var ai=AreaControl.GetAreaInfoByCookie().value;
if(ai==null)
return false;
//<%-- 根据地区域名重定向 --%>
if(<%=this.IsRedirect.ToString().ToLower()%> && ai.Domain!=null && ai.Domain!="" && ai.Domain!=window.location.hostname.split(".")[0])
...{
window.location.href=window.location.href.substring(0,7)+ai.Domain+"."+window.location.href.slice(7);
return true; //<%-- 返回真,不执行后面的判断,直接页面重定向 --%>
}
Bind(ai);
return true;
}
/**/ /*<%------------------------------------------------------------------%>*/
// <%-- 通过 IP 加载相应的地区 --%>
function LoadAreaByIP()
... {
var ai=AreaControl.GetAreaInfoByIP().value;
if(ai==null)
return false;
if(<%=this.IsRedirect.ToString().ToLower()%> && ai.Domain!=null && ai.Domain!="" && ai.Domain!=window.location.hostname.split(".")[0])
...{
window.location.href=window.location.href.substring(0,7)+ai.Domain+"."+window.location.href.slice(7);
return true;
}
Bind(ai);
return true;
}
/**/ /*<%------------------------------------------------------------------%>*/
// <%-- 执行入口 --%>
var arr = GetArray( " -1 " );
CreateDropDownList(arr, " <%=this.sSF.ClientID%> " );
// <%-- 是否只显示省份和城市 --%>
if ( <%= this .OnlySFCS.ToString().ToLower() %> ) // <%-- JS 的布尔值是小写 --%>
... {
var table=document.getElementById("<%=this.AreaTable.ClientID%>");
table.rows[0].deleteCell(3); //<%-- 删除后行索引变小,因此要从后面开始删除 --%>
table.rows[0].deleteCell(2);
}
if ( <%= this .SFID %>== 0 ) // <%-- 没赋值才根据 域名->Cookie->IP 绑定下拉框 --%>
(LoadAreaByDomain()) ? "" : ((LoadAreaByCookie()) ? "" : LoadAreaByIP());
else // <%-- 只要省份有值就绑定 --%>
bind( <%= this .SFID %> , <%= this .CSID %> , <%= this .XianID %> , <%= this .ZhenID %> ); // <%-- 赋值绑定 --%>
// <%-- 是否垂直显示 --%>
if ( <%= this .IsVertical.ToString().ToLower() %> )
... {
var h=document.getElementById("<%=this.AreaTable.ClientID%>");
var v=document.createElement("table");
v.setAttribute("id","<%=this.AreaTable.ClientID%>");
InsertRow(h.rows[0].cells.length);
h.parentNode.replaceChild(v,h); //<%-- 注意这里要通过添加 <div> 来解决 ascx 不能操作 aspx 的问题 --%>
}
// <%-- 循环创建(将列变成行) --%>
// <%-- length:循环次数 --%>
function InsertRow(length)
... {
for(var i=0;i<length;i++)
...{
v.insertRow(i);
v.rows[i].insertCell(0);
v.rows[i].cells[0].appendChild(h.rows[0].cells[i].childNodes[0]); //<%-- 将 cell 的的元素剪贴走 --%>
}
}
// <%-- 是否显示在下拉框前显示名称(省份、城市、县、镇) --%>
if ( <%= this .IsDisplayName.ToString().ToLower() %> )
... {
var sel=document.getElementById("<%=this.sSF.ClientID%>");
sel.parentNode.insertBefore(document.createTextNode("省份:"),sel);
sel=document.getElementById("<%=this.sCS.ClientID%>");
sel.parentNode.insertBefore(document.createTextNode("城市:"),sel);
sel=document.getElementById("<%=this.sXian.ClientID%>");
if(sel!=null)
sel.parentNode.insertBefore(document.createTextNode("县区:"),sel);
sel=document.getElementById("<%=this.sZhen.ClientID%>");
if(sel!=null)
sel.parentNode.insertBefore(document.createTextNode("乡镇:"),sel);
}
// <%-- 是否禁用控件 --%>
if ( <%= this .IsDisabled.ToString().ToLower() %> )
... {
var sels=document.getElementById("<%=this.AreaTable.ClientID%>").getElementsByTagName("select");
for(var i=0;i<sels.length;i++)
sels[i].setAttribute("disabled","disabled");
}
</ script >
最后就是用户控件的后台页了.
using System.Data;
using System.Data.OracleClient;
using System.Web.UI.MobileControls;
using AreaDropDownList;
public partial class AreaControl : System.Web.UI.UserControl
... {
属性#region 属性
private int _SFID;
private int _CSID;
private int _XianID;
private int _ZhenID;
private string _SF;
private string _CS;
private string _Xian;
private string _Zhen;
private string _Domain;
private bool _OnlySFCS;
private bool _IsRedirect;
private bool _IsVertical;
private bool _IsDisplayName;
private bool _IsDisabled;
//地区ID
public int SFID
...{
get ...{ return this._SFID; }
set ...{ this._SFID = value; }
}
public int CSID
...{
get ...{ return this._CSID; }
set ...{ this._CSID = value; }
}
public int XianID
...{
get ...{ return this._XianID; }
set ...{ this._XianID = value; }
}
public int ZhenID
...{
get ...{ return this._ZhenID; }
set ...{ this._ZhenID = value; }
}
//地区名
public string SF
...{
get ...{ return this._SF; }
set ...{ this._SF = value; }
}
public string CS
...{
get ...{ return this._CS; }
set ...{ this._CS = value; }
}
public string Xian
...{
get ...{ return this._Xian; }
set ...{ this._Xian = value; }
}
public string Zhen
...{
get ...{ return this._Zhen; }
set ...{ this._Zhen = value; }
}
//地区域名
public string Domain
...{
get ...{ return this._Domain; }
set ...{ this._Domain = value; }
}
/**//************** 特殊属性 ****************/
//是否重定向(通过 Cookie 和 IP 绑定下拉框会重定向)
public bool IsRedirect
...{
get ...{ return this._IsRedirect; }
set ...{ this._IsRedirect = value; }
}
//只显示省份城市
public bool OnlySFCS
...{
get ...{ return this._OnlySFCS; }
set ...{ this._OnlySFCS = value; }
}
//是否垂直显示
public bool IsVertical
...{
get ...{ return this._IsVertical; }
set ...{ this._IsVertical = value; }
}
//是否显示在下拉框前显示名称(省份、城市、县、镇)
public bool IsDisplayName
...{
get ...{ return this._IsDisplayName; }
set ...{ this._IsDisplayName = value; }
}
//是否禁用控件
public bool IsDisabled
...{
get ...{ return this._IsDisabled; }
set ...{ this._IsDisabled = value; }
}
#endregion
//在 aspx 取值用(赋值用 JS)
protected void Page_Init()
...{
//为了在 aspx 页面的 按钮事件里取值
if (this.IsPostBack)
...{
this.SFID = Convert.ToInt32(this.Request.Form[this.sSF.UniqueID]);
this.CSID = Convert.ToInt32(this.Request.Form[this.sCS.UniqueID]);
this.XianID = Convert.ToInt32(this.Request.Form[this.sXian.UniqueID]);
this.ZhenID = Convert.ToInt32(this.Request.Form[this.sZhen.UniqueID]);
this.SF = this.Request.Form[this.hSF.UniqueID].Replace("—请选择—", "");
this.CS = this.Request.Form[this.hCS.UniqueID].Replace("—请选择—", "");
this.Xian = this.Request.Form[this.hXian.UniqueID].Replace("—请选择—", "");
this.Zhen = this.Request.Form[this.hZhen.UniqueID].Replace("—请选择—", "");
this.Domain = this.Request.Form[this.hDomain.UniqueID];
}
}
protected void Page_Load(object sender, EventArgs e)
...{
//将C#的类和枚举分别注册到JS里
AjaxPro.Utility.RegisterTypeForAjax(typeof(AreaControl));
AjaxPro.Utility.RegisterEnumForAjax(typeof(AreaEnum));
}
/**//// <summary>
/// 将当前下拉框对应的地区信息存入 Cookie(供"保存"按钮使用)
/// </summary>
public void SaveCookie()
...{
AreaDAL.SaveCookie(this.SFID, this.CSID, this.XianID, this.ZhenID, this.SF, this.CS, this.Xian, this.Zhen, this.Domain);
}
/**//*====================== 以下是为防止命名空间暴露在 JS 里 ==========================*/
/**//// <summary>
/// 取得下拉框所需数据
/// </summary>
/// <param name="UpID">上一级ID</param>
/// <param name="ae">县/镇</param>
/// <returns>返回 DataTable</returns>
[AjaxPro.AjaxMethod]
public static DataTable GetDataTable(string UpID, AreaEnum ae)
...{
if (UpID == "0" || String.IsNullOrEmpty(UpID)) //用户选"—请选择—"不查询
return null;
//处于安全性考虑采用 列别名
//Oracle 返回的 DataTable 里的列名全是大写,在页面取值时记得大写
string sql;
if (Enum.Equals(ae, AreaEnum.Xian))
sql = "SELECT PKID AS id,CityName AS name,OneID,CityDomain FROM CityInfo WHERE THREEID=0 AND TWOID=" + UpID;
else
sql = "SELECT PKID AS id,CityName AS name,OneID,CityDomain FROM CityInfo WHERE THREEID=" + UpID;
return AreaDAL.GetDataTable(sql);
}
/**//// <summary>
/// 将当前所有下拉框的值存入 Cookie
/// </summary>
/// <param name="sfid">省份ID</param>
/// <param name="csid">城市ID</param>
/// <param name="xianid">县/区ID</param>
/// <param name="zhenid">镇ID</param>
/// <param name="sf">省份名</param>
/// <param name="cs">城市名</param>
/// <param name="xian">县/区名</param>
/// <param name="zhen">镇名</param>
/// <param name="domain">地区域名</param>
[AjaxPro.AjaxMethod]
public static void SaveCookie(int sfid, int csid, int xianid, int zhenid, string sf, string cs, string xian, string zhen, string domain)
...{
AreaDAL.SaveCookie(sfid, csid, xianid, zhenid, sf, cs, xian, zhen, domain);
}
/**//*=====================================================================*/
/**//// <summary>
/// 通过 域名 加载相应的地区
/// </summary>
/// <returns></returns>
[AjaxPro.AjaxMethod]
public static AreaInfo GetAreaInfoByDomain()
...{
return AreaDAL.GetAreaInfoByDomain();
}
/**//*=====================================================================*/
/**//// <summary>
/// 返回 Cookie 对应的地区信息
/// </summary>
/// <returns></returns>
[AjaxPro.AjaxMethod]
public static AreaInfo GetAreaInfoByCookie()
...{
return AreaDAL.GetAreaInfoByCookie();
}
/**//*=====================================================================*/
/**//// <summary>
/// 通过 IP 加载相应的地区
/// </summary>
/// <returns></returns>
[AjaxPro.AjaxMethod]
public static AreaInfo GetAreaInfoByIP()
...{
return AreaDAL.GetAreaInfoByIP();
}
}
/**/ /// <summary>
/// 地区枚举(如果数据库设计合理,前两位省份,中间两位城市,最后两位县/区,那么就不需要这个枚举,代码量也少很多)
/// </summary>
public enum AreaEnum
... {
/**//// <summary>
/// 省
/// </summary>
SF,
/**//// <summary>
/// 市
/// </summary>
CS,
/**//// <summary>
/// 县
/// </summary>
Xian,
/**//// <summary>
/// 镇
/// </summary>
Zhen
}
完成
最后是测试页
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class _Default : System.Web.UI.Page
... {
protected void Page_Init()
...{
//this.AreaControl1.OnlySFCS = true;
}
protected void Page_Load(object sender, EventArgs e)
...{
//要通过给控件赋值,绑定相应地区,只需给 ID 即可,Name就不用了
//this.AreaControl1.SFID = 42;
//this.AreaControl1.CSID = 4205;
//this.AreaControl1.XianID = 420521;
//this.AreaControl1.ZhenID=35020303;
//this.AreaControl1.OnlySFCS = true;
this.AreaControl1.IsVertical=true;
this.AreaControl1.IsDisplayName = true;
//this.AreaControl1.IsDisabled=true;
}
protected void Button1_Click(object sender, EventArgs e)
...{
//添加一个按钮 用来读取 用户选择的地区信息
Response.Write(String.Format("{0}{4},{1}{5},{2}{6},{3}{7}", AreaControl1.SF, AreaControl1.CS, AreaControl1.Xian, AreaControl1.Zhen, AreaControl1.SFID, AreaControl1.CSID, AreaControl1.XianID, AreaControl1.ZhenID));
}
protected void Button2_Click(object sender, EventArgs e)
...{
//直接调用 AreaControl 里的 SaveCookie 把 用户选择的地区存入 Cookie (这是为了方便,集成的)
this.AreaControl1.SaveCookie();
}
}
<% ... @ Register Src="AreaControl.ascx" TagName="AreaControl" TagPrefix="uc1" %>
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >
< html xmlns ="http://www.w3.org/1999/xhtml" >
< head runat ="server" >
< title > 无标题页 </ title >
</ head >
< body >
< form id ="form1" runat ="server" >
< div >
< uc1:AreaControl id ="AreaControl1" runat ="server" ></ uc1:AreaControl >
< asp:Button ID ="Button1" runat ="server" Text ="跳转" OnClick ="Button1_Click" />
< asp:Button ID ="Button2" runat ="server" Text ="存 Cookie" OnClick ="Button2_Click" />
</ div >
</ form >
</ body >
</ html >
记得 是 AjaxPro 6.10.4.1 的版本
Web.Config 在<system.web>来上这句
< add verb ="POST,GET" path ="ajaxpro/*.ashx" type ="AjaxPro.AjaxHandlerFactory, AjaxPro.2" />
</ httpHandlers >