需求分析
思路分析
- 先做布局
- 通过监听右侧导航的滑动或点击,获取当前Y轴位置,赋予列表相同的位置,实现列表的滚动
- 列表的滚动,获取位置范围,完成右侧导航定位
一,页面布局
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width,user-scalable=no" /> <meta charset="UTF-8"> <title>城市列表</title> <style type="text/css"> ul { margin: 0; padding: 0; list-style: none; } .list-wrapper{ position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; background: #fff; } .index-list-content{ background: #fff; border-radius: 2px; } .index-list-title{ padding: 14px 16px; font-size: 14px; line-height: 1.6; color: #333; } .index-list-anchor{ padding: 16px 16px 10px 16px; line-height: 1; font-size: 14px; color: #999; background: #f7f7f7; } .index-list-item { position: relative; height: 50px; line-height: 50px; padding: 0 16px; font-size: 14px; color: #333; } .index-list-item:last-child{ border: none; } .index-list-item_active{ background: #ddd; } .index-list-fixed{ position: absolute; z-index: 1; top: 0; left: 0; width: 100%; padding: 16px 16px 10px 16px; box-sizing: border-box; font-size: 14px; line-height: 1; color: #999; background: #f7f7f7; } .index-list-nav { position: absolute; z-index: 30; right: 0; top: 50%; transform: translateY(-50%); font-family: Helvetica; } .index-list-nav ul { padding: 0; margin: 0; } .index-list-nav li{ padding: 6px 16px 0 16px; line-height: 1; text-align: center; box-sizing: border-box; font-size: 12px; color: gray; } .index-list-nav .active { color: blue; } </style> </head> <body> <div class="list-wrapper"> <div class="scroll-content"> <div class="index-list-content"> <div class="index-list-title"> 定位城市: </div> <ul> <li> <h2 class="index-list-anchor"> ★热门城市 </h2> <ul> <li class="index-list-item border-bottom-1px"> 北京市 </li> <li class="index-list-item border-bottom-1px"> 上海市 </li> </ul> </li> <li> <h2 class="index-list-anchor"> A </h2> <ul> <li class="index-list-item border-bottom-1px"> 鞍山市 </li> <li class="index-list-item border-bottom-1px"> 安庆市 </li> </ul> </li> <li> <h2 class="index-list-anchor"> B </h2> <ul> <li class="index-list-item border-bottom-1px"> 北京市 </li> <li class="index-list-item border-bottom-1px"> 巴音郭楞州 </li> <li class="index-list-item border-bottom-1px"> 博尔塔拉州 </li> </ul> </li> <li> <h2 class="index-list-anchor"> C </h2> <ul> <li class="index-list-item border-bottom-1px"> 成都市 </li> </ul> </li> <li> <h2 class="index-list-anchor"> E </h2> <ul> <li class="index-list-item border-bottom-1px"> 鄂尔多斯市 </li> <li class="index-list-item border-bottom-1px"> 鄂州市 </li> <li class="index-list-item border-bottom-1px"> 恩施州 </li> </ul> </li> <li> <h2 class="index-list-anchor"> F </h2> <ul> <li class="index-list-item border-bottom-1px"> 福州市 </li> <li class="index-list-item border-bottom-1px"> 佛山市 </li> <li class="index-list-item border-bottom-1px"> 防城港市 </li> </ul> </li> <li> <h2 class="index-list-anchor"> G </h2> <ul> <li class="index-list-item border-bottom-1px"> 广州市 </li> <li class="index-list-item border-bottom-1px"> 贵阳市 </li> </ul> </li> <li> <h2 class="index-list-anchor"> H </h2> <ul> <li class="index-list-item border-bottom-1px"> 杭州市 </li> <li class="index-list-item border-bottom-1px"> 和田地区 </li> </ul> </li> <li> <h2 class="index-list-anchor"> Z </h2> <ul> <li class="index-list-item border-bottom-1px"> 郑州市 </li> <li class="index-list-item border-bottom-1px"> 张家口市 </li> <li class="index-list-item border-bottom-1px"> 张家界市 </li> <li class="index-list-item border-bottom-1px"> 珠海市 </li> <li class="index-list-item border-bottom-1px"> 中山市 </li> <li class="index-list-item border-bottom-1px"> 自贡市 </li> <li class="index-list-item border-bottom-1px"> 资阳市 </li> <li class="index-list-item border-bottom-1px"> 枣庄市 </li> <li class="index-list-item border-bottom-1px"> 舟山 </li> <li class="index-list-item border-bottom-1px"> 遵义市 </li> <li class="index-list-item border-bottom-1px"> 淄博市 </li> <li class="index-list-item border-bottom-1px"> 株洲市 </li> <li class="index-list-item border-bottom-1px"> 中卫市 </li> </ul> </li> </ul> </div> </div> </div> <div class="index-list-nav"> <ul> <li data-index="0" class="active"> ★ </li> <li data-index="1"> A </li> <li data-index="2" class=""> B </li> <li data-index="3" class=""> C </li> <li data-index="4" class=""> E </li> <li data-index="5" class=""> F </li> <li data-index="6" class=""> G </li> <li data-index="7" class=""> H </li> <li data-index="8" class=""> Z </li> </ul> </div> <div class="index-list-fixed" style="display: none;"> A </div> <script type="text/javascript" src="./bscroll.js"></script> <script type="text/javascript" src="./city.js"></script> </body> </html>
由于js较大,分离开了
二,初始化(city.js)
- 封装匿名自执行函数
- 获取各个需要操作的元素
- 初始化
(function(){ //获取外框 var list = document.querySelector(".list-wrapper"); //获取导航的ul var indexListNav = document.querySelector(".index-list-nav"); //后面的步骤 setNav之后 var indexListNavs = indexListNav.querySelectorAll("li"); //获取顶部索引 var indexListFixed = document.querySelector(".index-list-fixed"); //nav获取之后操作 return index之后 var indexListContent = document.querySelector(".index-list-content"); //获取ul下所有li var indexLists = indexListContent.children[1].children; //初始化 var indexList = new BScroll(list,{ //事件派发 probeType:3 }) })();
三,监听右侧列表的滑动或者点击,获取位置
为了方便大家理解,我的调试步骤也在
indexListNav.addEventListener("touchstart",(e)=>{ //可以获取到dom节点 // console.log(e.target); //Y轴位置 坐标 // console.log(e.changedTouches[0].clientY); setIndex(e.changedTouches[0].clientY); }) indexListNav.addEventListener("touchmove",(e)=>{ // console.log(e.changedTouches[0].clientY); //可以获取到dom节点 setIndex(e.changedTouches[0].clientY); }) //设置坐标 function setIndex(y){ let index = getIndex(y); if(index < 0 || index >9){ //没有对应元素 return; } //滚动到对应元素上去 li 过渡时间 indexList.scrollToElement(indexLists[index],100); } //拿到坐标 function getIndex(y){ //第二步 获取它相对于可视区的距离 var navTop = indexListNav.getBoundingClientRect().top; var h = 18; //nav li的高 //计算一下 得到index // var index = y/18; 下方转换 // 转换成相对于nav的距离 var index = parseInt((y-navTop)/18); //0-8 //打印出来看一下 // console.log(index); return index; }
第一二步完美实现
第三步
定义一个设置右侧导航active的方法
//nav active 控制 function setNav(index){ //先获取所有的a标签 indexListNavs.forEach((li)=>{ li.classList.remove("active"); }) //效果演示 indexListNavs[index].classList.add("active"); }
监听列表滚动事件,导航定位进行对应改变
indexList.on("scroll",(e)=>{ //拿到y轴 做一个比较 var y = -e.y; //是个负值 为了方便计算 转一下 我们要获取top值 //排除定位城市:背景这一行 第0项 未超过第一项就不显示顶部 if(y < indexLists[0].offsetTop){ setNav(0); //最后一步 第0项不需要显示 indexListFixed.style.display = "none"; //演示 清掉所有的 return; } //过了第[0]项 实际为第一项 显示它 indexListFixed.style.display = "block"; //到倒数第二项 //循环indexLists 下面每个li //最后一个单独处理 因为最后一项i+1这个表达式就不成立了 for(var i = 0; i < indexLists.length - 1; i++){ //滚动距离是否大于当前项,并且小于下一项,是的话,就说明还在当前项 if(y >= indexLists[i].offsetTop && y < indexLists[i+1].offsetTop){ setNav(i); //最后一步 给个值 indexListFixed.innerHTML = indexLists[i].children[0].innerHTML; return; } } setNav(indexLists.length - 1); //最后一项设置 indexListFixed.innerHTML = indexLists[indexLists.length - 1].children[0].innerHTML; })
大功告成,完结撒花