移动端效果之IndexList详解


Posted in Javascript onOctober 20, 2017

写在前面

接着前面的移动端效果讲,这次讲解的的是IndexList的实现原理。效果如下:

移动端效果之IndexList详解

代码请看这里:github

移动端效果之picker

移动端效果之cellSwiper

1. 核心解析

总体来说的原理就是当点击或者滑动右边的索引条时,通过获取点击的索引值来使左边的内容滑动到相应的位置。其中怎样滑动到具体的位置,看下面分解:

1.1 基本html代码

<div class="indexlist">
 <ul class="indexlist-content" id="content">
  <!-- 需要生成的内容 -->
 </ul>
 <div class="indexlist-nav" id="nav">
  <ul class="indexlist-navlist" id="navList">
   <-- 需要生成的索引条 -->
  </ul>
 </div>
 <div class="indexlist-indicator" style="display: none;" id="indicator"></div>
</div>

1.2 DOM初始化

由于饿了么组件库中的indexList是采用vue组件生成DOM,我这里大致使用javascript来模拟生成DOM。

// 内容填充
function initialDOM() {
 // D.data 获取内容数据
 var data = D.data;
 var contentHtml = '';
 var navHtml = '';
 // 初始化内容和NAV
 data.forEach(function(d) {
  var index = d.index;
  var items = d.items;
  navHtml += '<li class="indexlist-navitem">'+ index +'</li>';
  contentHtml += '<li class="indexsection" data-index="'+ index +'"><p class="indexsection-index">'+ index +'</p><ul>';
  items.forEach(function(item) {
   contentHtml += '<a class="cell"><div class="cell-wrapper"><div class="cell-title"><span class="cell-text">'+ item +'</span></div></div></a>';
  });
  contentHtml += '</ul></li>';
 });

 content.innerHTML = contentHtml;
 navList.innerHTML = navHtml;
}

// 样式初始化
if (!currentHeight) {
 currentHeight = document.documentElement.clientHeight -content.getBoundingClientRect().top;
}
// 右边索引栏的宽度
navWidth = nav.clientWidth;
// 左边内容的初始化高度和右边距
// 高度为当前页面的高度与内容top的差值
content.style.marginRight = navWidth + 'px';
content.style.height = currentHeight + 'px';

1.3 绑定滑动事件

在右边的索引栏上加上滑动事件,当点击或者滑动的时候触发。在源代码中在touchstart事件的结尾处,在window上绑定了touchmove与touchend事件,是为了使得滑动得区域更大,只有在开始的时候在索引栏上触发了touchstart事件时,之后再window上触发滑动和结束事件,这就意味着我们在滑动的过程中可以在左侧的内容区域滑动,同时也能达到index的效果。

function handleTouchstart(e) {
 // 如果不是从索引栏开始滑动,则直接return
 // 保证了左侧内容区域能够正常滑动
 if (e.target.tagName !== 'LI') {
  return;
 }
 
 // 记录开始的clientX值,这个clientX值将在之后的滑动中持续用到,用于定位
 navOffsetX = e.changedTouches[0].clientX;
 
 // 内容滑动到指定区域
 scrollList(e.changedTouches[0].clientY);
 if (indicatorTime) {
  clearTimeout(indicatorTime);
 }
 moving = true;
 
 // 在window区域注册滑动和结束事件
 window.addEventListener('touchmove', handleTouchMove, { passive: false });
 window.addEventListener('touchend', handleTouchEnd);
}

这里面用到了e.changedTouches,这个API可以去MDN查一下。

如果不是用到多点触控,changedTouches和touches的区别并不是特别大,changedTouches在同一点点击两次,第二次将不会有touch值。具体可以看这篇文章

下面看一下如何滑动:

function scrollList(y) {
 // 通过当前的y值以及之前记录的clientX值来获得索引栏中的对应item
 var currentItem = document.elementFromPoint(navOffsetX, y);
 if (!currentItem || !currentItem.classList.contains('indexlist-navitem')) {
  return;
 }
 
 // 显示指示器
 currentIndicator = currentItem.innerText;
 indicator.innerText = currentIndicator;
 indicator.style.display = '';

 // 找到左侧内容的对应section
 var targets = [].slice.call(sections).filter(function(section) { 
  var index = section.getAttribute('data-index');
  return index === currentItem.innerText;
 });
 var targetDOM;
 if (targets.length > 0) {
  targetDOM = targets[0];
  // 通过对比要滑动到的区域的top值与最开始的一个区域的top值
  // 两者的差值即为要滚动的距离
  content.scrollTop = targetDOM.getBoundingClientRect().top - firstSection.getBoundingClientRect().top;
  
  // 或者使用scrollIntoView来达到相同的目的
  // 不过存在兼容性的问题
  // targetDOM.scrollIntoView();
 }
}

关于elementFromPoint的API可以看这里

caniuse.com上关于getBoundingClientRect和scrollIntoView的兼容性

getBoundingClientRect

移动端效果之IndexList详解

scrollIntoView

移动端效果之IndexList详解

最后需要注销window上的滑动事件

window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('touchend', handleTouchEnd);

2. 总结
分析就这么多,多看源码能够学到优秀的设计理念。比如如果最开始让我来做的话,我可以就只会在右侧的索引栏上绑定事件,而不会关联左侧的内容,这样滑动的区域将会大大减小。

同时看源码可以学到一些比较偏僻的知识,促使自己去学习。比如文中的changedTouches以及elementFromPoint等API的学习。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
异步javascript的原理和实现技巧介绍
Nov 08 Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战一)
Aug 21 Javascript
简单实用的反馈表单无刷新提交带验证
Nov 15 Javascript
JavaScript在for循环中绑定事件解决事件参数不同的情况
Jan 20 Javascript
jQuery实现frame之间互通的方法
Jun 26 jQuery
node中使用es5/6以及支持性与性能对比
Aug 11 Javascript
js链表操作(实例讲解)
Aug 29 Javascript
vue-cli的eslint相关用法
Sep 29 Javascript
详解Javascript 中的 class、构造函数、工厂函数
Dec 20 Javascript
取消Bootstrap的dropdown-menu点击默认关闭事件方法
Aug 10 Javascript
Vue CLI 2.x搭建vue(目录最全分析)
Feb 27 Javascript
JS常见错误(Error)及处理方案详解
Jul 02 Javascript
详解webpack性能优化——DLL
Oct 20 #Javascript
vue利用better-scroll实现轮播图与页面滚动详解
Oct 20 #Javascript
浅谈如何使用 webpack 优化资源
Oct 20 #Javascript
利用jQuery实现简单的拖曳效果实例代码
Oct 20 #jQuery
Js利用prototype自定义数组方法示例
Oct 20 #Javascript
js 中rewrap-ajax.js插件实例代码
Oct 20 #Javascript
jQuery访问浏览器本地存储cookie、localStorage和sessionStorage的基本用法
Oct 20 #jQuery
You might like
完美解决dedecms中的[html][/html]和[code][/code]问题
2007/03/20 PHP
一步一步学习PHP(4) php 函数 补充2
2010/02/15 PHP
php 目录遍历、删除 函数的使用介绍
2013/04/28 PHP
jQuery timers计时器简单应用说明
2010/10/28 Javascript
jquery validate poshytip 自定义样式
2012/11/26 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
一个不错的js html页面倒计时可精确到秒
2014/10/22 Javascript
JavaScript时间转换处理函数
2015/04/14 Javascript
jQuery插件kinMaxShow扩展效果用法实例
2015/05/04 Javascript
JS判断字符串变量是否含有某个字串的实现方法
2016/06/03 Javascript
使用UrlConnection实现后台模拟http请求的简单实例
2017/01/04 Javascript
微信小程序 页面跳转和数据传递实例详解
2017/01/19 Javascript
jquery封装插件时匿名函数形参和实参的写法解释
2017/02/14 Javascript
深入学习 JavaScript中的函数调用
2017/03/23 Javascript
利用javascript如何随机生成一定位数的密码
2017/09/22 Javascript
小程序实现搜索框
2020/06/19 Javascript
vue项目启动出现cannot GET /服务错误的解决方法
2020/04/26 Javascript
[02:10]DOTA2亚洲邀请赛 EG战队出场宣传片
2015/02/07 DOTA
python如何修改装饰器中参数
2018/03/20 Python
Python调用C++,通过Pybind11制作Python接口
2018/10/16 Python
django框架CSRF防护原理与用法分析
2019/07/22 Python
Python文本处理简单易懂方法解析
2019/12/19 Python
python实现图书馆抢座(自动预约)功能的示例代码
2020/09/29 Python
HTML5新增加标签和功能概述
2016/09/05 HTML / CSS
全球500多个机场的接送服务:Suntransfers
2019/06/03 全球购物
2014年文学毕业生自我鉴定
2014/04/23 职场文书
促销活动总结怎么写
2014/06/25 职场文书
有关九一八事变的演讲稿
2014/09/14 职场文书
2014党员学习习主席讲话思想汇报
2014/09/15 职场文书
2015年推广普通话演讲稿
2015/03/20 职场文书
烈士陵园观后感
2015/06/08 职场文书
2015年库房管理工作总结
2015/10/14 职场文书
李清照的诗词赏析(20首)
2019/08/22 职场文书
k8s部署redis cluster集群的实现
2021/06/24 Redis
JavaScript函数柯里化
2021/11/07 Javascript
div与span之间的区别与使用介绍
2021/12/06 HTML / CSS