最近好多天没有更新文章,是因为公司的项目忙的不行。今天有点时间,就突然想起在移动端项目中遇到三级联动的问题,网上查了很多资料,都是依赖各种插件,或者晦涩难于理解。于是,自己决定写一个出来。 当然,没有用到别的插件类库,也没有用ajax。写完这个小demo也学到不少,现在分享给大家代码。因为代码较多,我就不一个个解释了,源码里面添加了很多注释。 为了便于大家使用,我将html精简了许多。

结尾会有在线运行地址。

0 <!DOCTYPE html>
1 <html lang="en">
2 <head>
3 <meta charset="UTF-8">
4 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
5     <meta name="apple-mobile-web-app-capable" content="yes">
6 <title>三级联动</title>
7 <link rel="stylesheet" href="index.css">
8 </head>
9 <body>
10 <div class="select">
11 请选择区域
12 </div>
13 <script src="city.js"></script>
14 <script src="index.js"></script>
15 </body>
16 </html>

至于三级联动的数据,我重新定义了一个js文件,在文件中创建了一个json对象,复制了服务器的三级联动的数据过来。 下面是javascript代码

0 (function(){
1  
2 var sel = document.querySelector('.select'),
3 createDivFlag = true;
4 windowHeight = window.screen.availHeight,
5 startYFlag = 0;
6  
7 var div,cur,province,city,county,ok,resut,oneNum,twoNum,threeNum,touchFlag,
8 touchOn = true,
9 touchStop = true,
10 tochBegin = true;
11  
12 //判断是否能打开
13 sel.addEventListener('touchend',function(){
14  
15 createDivFlag && createDiv();
16  
17 })
18  
19 //开始生成盒子
20 function createDiv(){
21  
22 //判断避免重复生成
23 if(!div){
24 div = document.createElement('div'),
25 cur = document.createElement('div'),
26 ok = document.createElement('div'),
27 resut = document.createElement('div'),
28 province = document.createElement('div'),
29 city = document.createElement('div'),
30 county = document.createElement('div');
31  
32 div.className = 'win';
33 cur.className = 'current';
34 ok.className = 'ok';
35 resut.className = 'resut';
36 province.className = 'province';
37 city.className = 'city';
38 county.className = 'county';
39  
40 ok.innerHTML = '完成';
41 resut.innerHTML = '取消';
42  
43 //赋值translate
44 province.style.transform = 'translateY(80px)';
45 city.style.transform = 'translateY(80px)';
46 county.style.transform = 'translateY(80px)';
47 //给三个盒子绑定滑动事件
48 touchGo([province,city,county]);
49 div.appendChild(cur);
50 div.appendChild(ok);
51 div.appendChild(resut);
52 div.appendChild(province);
53 div.appendChild(city);
54 div.appendChild(county);
55 document.body.appendChild(div);
56 }
57  
58  
59 //填充数据
60 fillIn(province,city,county);
61  
62  
63 setTimeout(function(){
64 div.style.transform = 'translateY(-200px)';
65 },0);
66  
67 //确认选择
68 ok.addEventListener('touchend',function(){
69  
70 var one = province.querySelectorAll('span')[oneNum],
71 two = city.querySelectorAll('span')[twoNum] || null,
72 three = county.querySelectorAll('span')[threeNum] || null,
73 selId,
74 oneHtml,
75 twoHtml,
76 threeHtml;
77  
78 oneHtml = one.innerHTML || '';
79 twoHtml = two ? two.innerHTML : '';
80 threeHtml = three ? three.innerHTML : '';
81  
82 sel.innerHTML = oneHtml + twoHtml + threeHtml;
83  
84  
85 oneNodeValue = one ? one.attributes['data-id'].nodeValue : '';
86 twoNodeValue = two ? two.attributes['data-id'].nodeValue : '';
87 threeNodeValue = three ? three.attributes['data-id'].nodeValue : '';
88 selId = oneNodeValue + twoNodeValue + threeNodeValue + '';
89  
90 sel.setAttribute('data-id',selId);
91  
92 div.style.transform = 'translateY(0)';
93  
94 createDivFlag = true;
95  
96 })
97  
98 //取消选择
99 resut.addEventListener('touchend',function(){
100  
101 div.style.transform = 'translateY(0)';
102  
103 createDivFlag = true;
104  
105 })
106  
107 createDivFlag = false;
108  
109 }
110  
111  
112  
113 //给三级菜单填充内容
114 function fillIn(province,city,county){
115 var proStart,cityStart;
116  
117 //先将内容清空,避免后面累加
118 province.innerHTML = '';
119 city.innerHTML = '';
120 county.innerHTML = '';
121  
122 //初始化位置
123 for(k in region.p['000000']){
124 var span = document.createElement('span');
125 span.setAttribute("data-id",k);
126 span.innerHTML = region.p['000000'][k];
127 province.appendChild(span);
128 }
129  
130 proStart = province.querySelector('span').attributes['data-id'].nodeValue;
131  
132 cityBegin(proStart,city);
133  
134 cityStart = city.querySelector('span').attributes['data-id'].nodeValue;
135  
136 countyBegin(cityStart,county);
137  
138 //初始化时自动先获取一遍初始值
139 for(var i = 0; i < arguments.length; i += 1){
140  
141 //判断第二次打开,是否需要渲染二三级
142 if(arguments[i].querySelector('span')){
143  
144 selectCity(arguments[i]);
145  
146 }
147 }
148  
149 }
150  
151 //二级内容
152 function cityBegin(proStart,city){
153 var flag = true;
154  
155 if(region.c[proStart]){
156  
157 for(n in region.c[proStart]){
158 var span = document.createElement('span');
159 span.setAttribute('data-id',n);
160 span.innerHTML = region.c[proStart][n];
161 city.appendChild(span);
162 }
163  
164 }else{
165 flag = false;
166 }
167  
168 return flag;
169  
170 }
171  
172  
173 //三级内容
174 function countyBegin(cityStart,county){
175 for(j in region.d[cityStart]){
176 var span = document.createElement('span');
177 span.setAttribute('data-id',j);
178 span.innerHTML = region.d[cityStart][j];
179 county.appendChild(span);
180 }
181 }
182  
183  
184 //为三级菜单绑定拓展事件
185 function touchGo(objArr){
186  
187 for(var i = 0; i < objArr.length; i += 1){
188  
189 actionSwiper(objArr[i]);
190  
191 }
192  
193 //为三级菜单绑定事件
194 function actionSwiper(obj){
195  
196 var startPosition,movePosition,endPosition,deletaY,transY;
197  
198 //tochBegin,touchOn,touchStop;三个状态判断
199 obj.addEventListener('touchstart',function(event){
200 if(touchStop){
201 touchStop = false;
202 var touch = event.touches[0];
203 startPosition = {
204 x : touch.pageX,
205 y : touch.pageY
206 }
207 transY = Number(translateXY(obj));
208 objHeight = obj.offsetHeight;
209 tochBegin = true;
210 }
211  
212 })
213  
214  
215 //80 为两个span的高度,初始化时,距离上方80px
216 //200 为自定义select的高度。
217 obj.addEventListener('touchmove',function(event){
218  
219 if(tochBegin){
220  
221 touchOn = true;
222  
223 var touch = event.touches[0];
224  
225 movePosition = {
226 x : touch.pageX,
227 y : touch.pageY
228 };
229  
230 deletaY = movePosition.y - startPosition.y + transY;
231  
232 //向上划上限
233 //deletaY = deletaY > -objHeight - 80 + 200 ? deletaY : -objHeight - 80 + 200;
234 deletaY = deletaY > -objHeight + 120 ? deletaY : -objHeight + 120;
235  
236 //向下滑下限
237 deletaY = deletaY > 80 ? 80 : deletaY;
238  
239  
240 obj.style.transform = 'translateY('+ deletaY +'px)';
241  
242 //禁止浏览器默认黑色背景出现
243 event.preventDefault();
244  
245  
246 }
247  
248 })
249  
250 obj.addEventListener('touchend',function(){
251  
252 if(touchOn){
253  
254 touchStop = true;
255  
256 var touch = event.changedTouches[0];
257  
258 endPosition = {
259 x : touch.pageX,
260 y : touch.pageY
261 };
262  
263 setTimeout(function(){
264 objTouchEnd(obj);
265 },100);
266  
267 }
268  
269 })
270  
271 //滑动结束后处理函数
272 function objTouchEnd(obj){
273  
274 var objTranslateY = parseInt(Number(translateXY(obj))),
275 objType = '',
276 timer = null;
277  
278 if(endPosition.y - startPosition.y > 0){
279 objType = 'down';
280 }else{
281 objType = 'up';
282 }
283  
284 timer = setInterval(function(){
285  
286  
287 if(objType == 'up'){
288 if(Number(translateXY(obj)) % 40 != 0){
289 objTranslateY -= 1;
290 }
291 }
292  
293 if(objType == 'down'){
294 if(Number(translateXY(obj)) % 40 != 0){
295 objTranslateY += 1;
296 }
297 }
298  
299 obj.style.transform = 'translateY('+ objTranslateY +'px)';
300  
301 if(Number(translateXY(obj)) % 40 == 0){
302  
303 clearInterval(timer);
304 timer = null;
305  
306 tochBegin = false;
307  
308 //确定选择
309 selectCity(obj);
310  
311 }
312  
313  
314 },20);
315  
316  
317  
318 }
319  
320 }
321  
322 }
323  
324  
325 //获取设置选项
326 function selectCity(obj){
327 //80+80=160   Y为80 的时候是第一个
328 var objTranslateY = Number(translateXY(obj)),
329 one,
330 oneId,
331 onText,
332 two,
333 twoId,
334 twoText,
335 three,
336 threeId,
337 threeText,
338 twoGoThree;
339  
340 if(obj == province){
341  
342 oneNum =  Math.abs((objTranslateY + 80 - 160) / 40);
343  
344 //获取序号
345 one = province.querySelectorAll('span')[oneNum];
346  
347 //获取自定义属性值
348 oneId = one.attributes['data-id'].nodeValue;
349  
350 //清空下一级内容
351 city.innerHTML = '';
352  
353 //重置下一级translateY
354 city.style.transform = 'translateY(80px)';
355  
356 //重置第三级translateY
357 county.style.transform = 'translateY(80px)';
358  
359 //填充下一级内容
360 twoGoThree = cityBegin(oneId,city);
361  
362 //清空第三项
363 county.innerHTML = '';
364  
365 //默认第三级默认第二级第一项
366 if(twoGoThree){
367 countyBegin(city.querySelector('span').attributes['data-id'].nodeValue,county);
368 }
369  
370 }
371  
372 if(obj == city){
373  
374 twoNum =  Math.abs((objTranslateY + 80 - 160) / 40);
375  
376 //获取序号
377 two = city.querySelectorAll('span')[twoNum];
378  
379 //获取选中选项自定义属性值
380 twoId = two.attributes['data-id'].nodeValue;
381  
382 //清空第三项值
383 county.innerHTML = '';
384  
385 //重置第三项translateY
386 county.style.transform = 'translateY(80px)';
387  
388 //填充第三项
389 if(twoId){
390 countyBegin(twoId,county);
391 }
392  
393 }
394  
395 if(obj == county){
396  
397 threeNum =  Math.abs((objTranslateY + 80 - 160) / 40);
398  
399 //获取序号
400 three = county.querySelectorAll('span')[threeNum];
401  
402 //获取选中选项自定义属性值
403 threeId = three.attributes['data-id'].nodeValue;
404  
405 }
406  
407 }
408  
409 //获取translateY值
410 function translateXY(obj){
411     var beeTransform = obj.style.transform.replace(/\s/g,'');
412     beeTransform = beeTransform.replace('translateY','');
413     beeTransform = beeTransform.slice(1,-1);
414     beeTransform = beeTransform.replace('px','');
415     return beeTransform;
416 }
417  
418 })()

在线运行   在线运行请在谷歌浏览器调试模式下模拟手机环境运行。暂未进行仔细测试,如有问题,欢迎留言共同探讨。

原文链接-摘自大公爵ddamy.com

移动端纯原生JS不依赖ajax后台服务器实现省市县三级联动的更多相关文章

  1. 纯原生js移动端图片压缩上传插件

    前段时间,同事又来咨询一个问题了,说手机端动不动拍照就好几M高清大图,上传服务器太慢,问问我有没有可以压缩图片并上传的js插件,当然手头上没有,别慌,我去网上搜一搜. 结果呢,呵呵...诶~又全是基于 ...

  2. 移动端lCalendar纯原生js日期时间选择器

    网上找过很多的移动端基于zepto或jquery的日期选择器,在实际产品中也用过一两种,觉得都不太尽如人意,后来果断选择了H5自己的日期input表单,觉得还可以,至少不用引用第三方插件了,性能也不错 ...

  3. ThinkPHP 中使用 IS_AJAX 判断原生 JS 中的 Ajax 出现问题

    问题: 在 ThinkPHP 中使用原生 js 发起 Ajax 请求的时候.在控制器无法使用 IS_AJAX 进行判断.而使用 jQuery 中的 ajax 是没有问题的. 在ThinkPHP中.有一 ...

  4. 省市县三级联动js代码

    省市县三级联动菜单,JS全国省市县(区)联动代码,一般可以用于用户注册或分类信息二手交易网站,需要的朋友直接复制代码就可以用了,不过有朋友反馈说缺少某些城市,具体缺少哪个尚不知,请想用的朋友自己补全吧 ...

  5. 纯原生js移动端城市选择插件

    接着上一篇纯js移动端日期选择插件,话说今天同事又来咨询省市县联动的效果在移动端中如何实现,还是老样子,百度上一搜,诶~又全是基于jquery.zepto的,更加可恨的是大多数都是PC版的,三个sel ...

  6. 类似jQuery的原生JS封装的ajax方法

    一,前言: 前文,我们介绍了ajax的原理和核心内容,主要讲的是ajax从前端到后端的数据传递的整个过程. Ajax工作原理和原生JS的ajax封装 真正的核心就是这段代码: var xhr = ne ...

  7. 原生JS写的ajax函数

    参照JQuery中的ajax功能,用原生JS写了一个ajax,功能相对JQuery要少很多,不过基本功能都有,包括JSONP. 调用的方式分为两种: 1. ajax(url, {}); 2. ajax ...

  8. ajax(省,市,县)三级联动

    下面我们用Jquery,ajax,做一个省,市,县的三级联动: 下面是我做三级联动下拉的步骤以及逻辑 第一步:先做一个省市区表格 第二步:建个PHP页面显示用我是在<body>里放< ...

  9. 第八篇 一个用JS写的省市县三级联动

    前些天,做网站用需要用到一个省市县的三级联动,数据要从数据库里面读取,我想了下思路,动手写了下来.    一.思路           js利用Ajax读取控制器里面的函数,利用函数读取存储过程,返回 ...

随机推荐

  1. 调bug时候应该提高思维深度(多问二十个为什么)

    版权声明:本文为博主原创文章,未经博主允许不得转载. (一)关于思维深度 读书时 有的人做一份卷子有一份卷子的收获 有的人做100张卷子只有一份卷子的收获 写代码时 有的人调一个Bug可以收获多方面的 ...

  2. CouldnotcreateServerSocketonaddress0.0.0.0/0.0.0.0:9083

    错误记录 安装的时候遇到了如下错误 Exception in thread "main" org.apache.thrift.transport.TTransportExcepti ...

  3. C语言 大小端 字节对齐

    参考:http://www.cnblogs.com/graphics/archive/2011/04/22/2010662.html 1. 大端序:数据的高位字节存放在地址的低端,低位字节存放在地址的 ...

  4. 解决mac插入U盘不显示标识问题

    有时候,我们在使用U盘的时候,如果未能正常退出U盘,下次插入U盘可能会不显示U盘. 解决办法如下,打开Finder-->偏好设置,设置 成功解决问题.

  5. 能够免费做商业站点的CMS讨论

    眼下国内使用过PHPCMS   DEDECMS织梦    科讯CMS  帝国.Discuz.Ecshop等,可是他们都是个人非盈利免费,商业.政府.机构授权收费. 使用什么CMS能够免费做商业站点呢? ...

  6. Foundation 学习

    官网 Foundation是个跟bootstrap齐名的前端框架. 移动优先,响应式,最低支持IE8. html+css+jq构建 网格Grid Basic: .row父容器 子元素类.column  ...

  7. Ext.Net 使用总结之查询条件中的起始日期

    2.关于查询条件中起始日期的布局方式 首先上一张图,来展示一下我的查询条件的布局,如下: 大多数时候,我们的查询条件都是一个条件占一个格子,但也有不同的时候,如:查询条件是起始日期,则需要将这两个条件 ...

  8. Kettle 学习笔记

    一直用SSIS做ETL,越来越感觉这玩意不是亲生的.因此萌生换ETL工具的想法,不过Kettle社区版没什么调度系统,貌似错误处理也不是很方便,且先了解吧. 本文简略的记录了整个软件的使用流程. 开始 ...

  9. jvm栈和堆详解

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...

  10. .Net平台-MVP模式再探(二)

    PS:     本文与  上一遍文章  没有什么必然的联系,可以说是对于MVP的一定的加深,或许在理解上比上一篇多有点难度. 正文   一.简单讲讲MVP是什么玩意儿 如果从层次关系来讲,MVP属于P ...