2010 Mar 22

jQuery LocationSelect Plugin

最新版本的LocationSelect已经将其与jQuery分离,但做了一个jQuery的适配器,可以和jQuery一起使用。而且现在可以支持任意级别联动⋯⋯

介绍

用户的地址选择往往是网络应用中不可缺少的一部分,可是遇到了以下问题:

  • 地址数据难以收集
  • 用户选择烦琐,需要手动查找冗长的下拉菜单
  • 难以维护地理数据以及重用组件

LocationSelect插件具有以下特点,有效的解决了以上三个问题:

  • 基于广泛使用的jQuery插件库,轻易实现组件重用。你也可以选择使用不使用任何脚本库的版本。
  • 地理数据整理来自国家公布数据
  • 自动判断用户地理位置并进行最大努力的自动选择
  • 独立的json数据源,可以方便的进行维护

兼容性

我测试过如下浏览器:Safari5、Safari Mobile(iOS 4.0.1)、Firefox3、IE6、IE7、IE8、Opera10

演示

一个在线演示可以在http://pagetalks.com/share/LocationSelect找到。
该演示实现了一个自动探测用户地理位置并自行选择的标准案例。

下载

代码寄存在GitHub : http://github.com/RobinQu/LocationSelect-Plugin

安装

  1. (可选)引入jQuery脚本库,目前脚本仅在1.4.2的jQuery中进行过调试,推荐大家使用。同时,还可以使用Google的CDN进行加速:
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
  2. 由于需要用到JSON的解析器,脚本默认会调用JSON.parse方法来解析。如果你的项目里没有定义JSON.parse方法,请引用JSON.org的脚本。
    <script src="http://www.JSON.org/json2.js" type="text/javascript"></script>
  3. 现在已经不用手动引入第三方脚本了。引入地理查询引擎(可选)- 本脚本是使用Google Map API V2以及MAXMIND的Javascript API进行联合查询实现确定用户地理信息的。随着Google Map的反向地址解析更为强大后,脚本会考虑减少外部脚本的依赖性。目前如果您需要使用自动检测功能,您必须引入这两个脚本
    <script src="http://j.maxmind.com/app/geoip.js" type="text/javascript"></script>
    	<script src="http://maps.google.com/maps?file=api&v=2&key=XXXXXXX_YOUR_API_KEY_XXXX&sensor=false" type="text/javascript">
  4. 引入LocationSelect的脚本文件 –
    <script type="text/javascript" src="LocationSelect.js"></script>
  5. 你应该在生产环境中将调试信息关闭,LocationSelect.js中的第8行中
    com.elfvision.DEBUG = true; 

    改为

    com.elfvision.DEBUG = false;
  6. 在DOM Ready事件后调用,通常您应该传递响应数目的Select对象:
    	$(function() {
    	$("select").LocationSelect({
            name : "areas",
    	labels :["请选择一个省份或直辖市", "请选择一个城市", "请选择一个区"]
    	});

    还可以选择使用非jQuery的初始方法:

    var ls = new com.elfvision.kit.LocationSelect({
    				labels :["请选择一个省份或直辖市", "请选择一个城市", "请选择一个区"],
    				elements : $("select").get()
    			});

参数

name (String) 必须
默认: “areas.json” – json数据文件的地址,相对于当前页面
labels (Array) 必须
每个菜单的默认标签名,例如,["请选择一个省份或直辖市", "请选择一个城市", "请选择一个区"]。注意该元素的数量决定联动菜单中选项的数目,所以一定要为每个元素制定标签。
detectGeoLocation : (Boolean)
默认: true – 是否自动检测用户地址并进行选择
listHelper : (ListHelper)
默认: com.elfvision.kit.LocationSelect.ListHelper – 列表的工具类,该插件会使用次对象中的方法去加载对象、查询列表项目等操作。传入自定义的该对象可以进行该插件的深度定制。详细内容见后文。
detector : (Function)
默认: com.elfvision.kit.LocationSelect.GeoDetect – 自动探测方法。默认情况下会利用用户IP查询地理位置。

如何定制

有很多同学想要进行定制操作,从1.1版本开始,就已经把大部分重要的算法给独立到单独的接口里面,方便大家定制。首先讲一下这个插件的工作原理。

首先,插件会尝试使用ListHelper的fetch方法去取回所有要用的数据文件。默认情况下会访问ListHelper.dataUrl的地址,如果你不作任何配置,这个地址指向的是插件自带的areas_1.0.json。

当fetch方法返回之后,会执行一个回调函数。这个回调函数里回进行列表的初始划操作。

当列表都初始化完成,控件就已经可用了。如果自动探测的选项依然为true,就会继续接下来的探测逻辑。插件内置了根据IP判断地理位置的探测算法。

该算法是调用的Maxmind GEOCITY的API获得用户经纬度,然后使用Google Map的Geocoder WebService根据经纬度解析用户地理信息。然后利用返回结果去对列表进行“选择”。

可以看到还有个YQL的参与,这是Google Map V3的WebService已经不支持JSONP了,对跨域请求来说是噩梦。通过YQL作为一个Proxy返回的JSONP。

下面开始介绍如何进行深度定制。首先上一张Class Diagram。

基本来说,通过定制所传入的ListHelper对象detector函数来控制该插件的功能。

ListHelper是一个列表的工具接口。默认的ListHelper采用了Singleton的模式,但你可以选择不这么做。只要保证提供fetch和find方法即可。这两个方法必须实现如下操作:

  • fetch方法接受一个回调函数,在把所需要的JSON基本数据取得了之后就必须会被执行。
  • find方法根据传来level和id两个参数对fetch方法获得的数据进行查找进行记录的查找,必须返回一个装有记录的数组。
纪录的数据结构
该插件对数据项的结构有所规定。一个项目如下:

{
"id" : "112",
"text" : "Foobar"
}

注意该项目中所有的属性均为字符串。

level
evel的意义是标识进行find请求的是第几个List。该插件中,前一个List的选项进行改变后会出发下一个List更新其内容,那么查找的find方法必须知道前一个List的level。find方法被插件调用时会自动传入level的值,该值从0开始计数。在插件默认的ListHelper里面,会调用一个find(-1)的请求,这是在请求第一个List的默认数据。插件默认状况就是通过这个请求去请求“省份”的数据项目的。
id
id值即前一个List中被选项目的id值。

你可以用fetch方法从后台取得数据(不管是啥数据,只要复合数据项目的结构规定)之后,根据这些数据实现find方法。

你可以传入的另外一个元素是detector函数。这个是执行自动选择的函数。默认的detector函数执行了地理位置的探测,但你可以实现你自得探测算法。只要最终使用LocationSelect.select()方法选择一组数据项。例如:

that.select(["湖北省",“武汉市”]);

这些值始终会根据List的传入顺序进行比对。如果List的数目大于给出的数组元素的数量,将不会对那些没有对应数值的List进行选择;如果传入的数值数组元素个数大于List个数,剩下的数组元素将会被抛弃。

通过传入自定义的ListHelper和detector,你可以完全自定义出类似于多级商品门类选择之类的联动菜单应用。也就不局限于选择一下地址而已了⋯⋯

更新日志

1.0.0
LocationSelect的第一个发行版本
1.1.0
LocationSelect的重写版本,与jQuery独立,改善性能。

13 Comments

  1. Posted April 20, 2010 at 11:23 am | Permalink

    如果想改为2级的省市菜单怎么改呢

  2. Posted April 20, 2010 at 10:36 pm | Permalink

    just hide it by css

  3. xiaomai
    Posted July 14, 2010 at 4:35 pm | Permalink

    如何通过数据库存储的地址进行设置?

  4. Posted July 16, 2010 at 9:52 am | Permalink

    修改JSON文件的路径嘛~从Servlet那里获取一个JSON不就可以从数据库获取数据了?

  5. xiaomai
    Posted July 19, 2010 at 4:32 pm | Permalink

    jQuery LocationSelect Plugin》》》》

    现在这个插件只有读的功能,没有写的功能。比如:通过数据库取出存储的地址,再通过用js设置这个插件为这个地址。

  6. Posted August 30, 2010 at 10:33 pm | Permalink

    我用在一个asp表单里面,选取好之后存在SQL数据库里,然后需要修改的时候,不知道怎么给这个联动菜单赋值!就是说让它显示数据库里面的存的值?有办法吗?

  7. RobotXia
    Posted September 1, 2010 at 11:03 am | Permalink

    如何设置从数据库取出来的地址也是个问题啊!直接用JS可以实现,但是用插件异议就不大了,希升级,继续关注!

  8. Posted September 2, 2010 at 3:24 pm | Permalink

    如果想自己设置某个地区为选中状态,应该怎样修改代码啊。急等~

  9. PassCar
    Posted September 4, 2010 at 4:50 pm | Permalink

    期待v2.0,同时给v1.0提个小建议,建议在
    $(_s).find(“option[value!='0']“).remove();之后加上:

    if($(specs.selectors.province).val()==0){
    $(specs.selectors.city).find(“option[value!='0']“).remove();
    $(specs.selectors.district).find(“option[value!='0']“).remove();
    }

  10. Posted September 5, 2010 at 2:18 pm | Permalink

    近期就会更新!

  11. Posted September 5, 2010 at 2:20 pm | Permalink

    肯定需要服务器端写程序读取数据库的,JS没法读数据库~
    而且我不认为每次打开页面都要读取数据库的地址信息是一个明智的决定,应该是程序定期生成一个静态json文件让前端用~
    下一个会增强这方面的功能~

  12. Posted September 6, 2010 at 5:30 pm | Permalink

    Thanks to share something interestings.
    http://junjun0660.insanejournal.com/

  13. xiaoqiqi
    Posted May 26, 2011 at 5:57 pm | Permalink

    为什么我放到二级目录就不能成功?

One Trackback

  1. By Javascript MVC, again…… – PageTalks on September 22, 2010 at 8:43 pm

    [...] 这几天虽然在学校办事,也在抽空重写之前的那个LocationSelect插件,之前用jQuery写的逻辑太混乱了,算法效率也比较低,那个时候的目的仅仅是“急于实现一个地址联动的组件”给Map2fun这个项目用。其实这个插件里面是可以有很多学问的,webservice的使用、缓存、查询算法,最重要的是这个“联动”二字,3个下拉菜单看似简单却极为蛋疼的互动逻辑。干脆就用MVC的模式重写吧⋯⋯ [...]

Post a Comment

Your email is never shared. Required fields are marked *

*
*