移动端省市区三级联动选择器

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

<!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 })()

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue省市县三级联动选择器是一个基于Vue框架开发的组件,主要用于在前端页面实现省市县三级地区选择功能。 在实现这个功能的时候,可以通过调用第三方库或者自己编写代码来实现。首先,需要有一个地区的数据源,可以是从后端接口获取到的数据,也可以是直接存储在前端的静态数据。 在使用Vue框架时,可以通过使用computed属性来动态生成省份的数据,再根据选中的省份来生成对应的城市数据,最后根据选中的城市来生成对应的县区数据。这样就实现了省市县三级联动选择的效果。 在Vue模板中,可以通过v-for指令来遍历省市县数据,然后通过v-model指令绑定选中的省市县数据,实现数据的双向绑定。同时,可以通过使用v-on指令来监听省市县选择时的事件,以便在选择变化时更新城市和县区的数据。 除了使用Vue框架的核心功能外,还可以使用第三方组件库或UI框架来美化选择器的样式,增加用户体验。 综上所述,Vue省市县三级联动选择器是一个基于Vue框架开发的组件,可以实现在前端页面上方便地选择地区的功能。通过动态生成省市县数据,并根据选中的选择生成对应的下级数据,实现了省市县三级联动。通过Vue框架的特性和指令,实现数据的双向绑定和事件监听,提升了交互效果。同时,可以使用第三方组件库或UI框架美化选择器的样式,增加用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值