最近好多天没有更新文章,是因为公司的项目忙的不行。今天有点时间,就突然想起在移动端项目中遇到三级联动的问题,网上查了很多资料,都是依赖各种插件,或者晦涩难于理解。于是,自己决定写一个出来。 当然,没有用到别的插件类库,也没有用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. outlook 2003配置连接exchange server 2010报错——无法完成此操作。 与 Microsoft Exchange Server 的连接不可用。 Outlook 必须联机或连接才可完成该操作

    最近安装了一台Exchange 2013邮件服务器,但在客户端Outlook 2013手动配置邮箱时却发现了如下错误:   这里说一个简单的解决办法,实际上第一次启动Outlook时可以自动发现,只需 ...

  2. 为什么没有好用的Android游戏引擎?

    随着Android平台的不断发展,最近Android开发人员数量呈现出上升势头,就连以往较为冷门的游戏开发领域也涌现出不少生力军.然而,全新的问题正摆在了刚開始学习的人面前,非常多他们从未遇过的问题開 ...

  3. HDU-Billboard-2795(线段树)

    hdu2795 Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  4. WinSock网络编程基础(1)

    记录学习windows网络编程过程中遇到的问题和相关笔记 基本概念: Socket: socket起源于UNIX,Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.基于&qu ...

  5. leetcode 60. Permutation Sequence(康托展开)

    描述: The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of t ...

  6. 关于Scrapy框架的基本概念

    Scrapy爬取网页基本概念 Scrapy爬取网页基本概念 怎么样用Scrapy生成project? scrapy startproject xxx 如何用Scrapy爬取网页? import scr ...

  7. R包——ggplot2(一)

    关于ggplot2包(一) 关于ggplot2包(一) ggplot2基本要素 数据(Data)和映射(Mapping) 几何对象(Geometric) 标尺(Scale) 统计变换(Statisti ...

  8. hdu 4162 Shape Number 最小表示法

    题目链接 给一个字符串, 将它想象成一个环, 然后从环中任意一个位置断开, 求断开后字典序最小的那种情况. 直接上模板.. #include <iostream> #include < ...

  9. bzoj 3289: Mato的文件管理 莫队+线段树

    题目链接 给一些询问,每个询问给出区间[L, R] , 求这段区间的逆序数. 先分块排序, 然后对于每次更改, 如果是更改L, 那么应该查询区间内比他小的数的个数, 如果更改R, 查区间内比他大的数的 ...

  10. Spring起步(一)Building a RESTful Web Service

    http://spring.io/guides/gs/rest-service/ 先放链接. 这个很小很小的一个功课,我却遇到了各种各样的奇葩错误,折腾了两天才弄好. 想要开始的话,需要一些准备工具 ...