移动端效果之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中关于indexOf的使用方法与问题小结
Aug 05 Javascript
JQuery入门—编写一个简单的JQuery应用案例
Jan 03 Javascript
关于在IE下的一个安全BUG --可用于跟踪用户的系统鼠标位置
Apr 17 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
Mar 30 Javascript
jQuery实现圣诞节礼物动画案例解析
Dec 25 Javascript
Vue2.0基于vue-cli+webpack同级组件之间的通信教程(推荐)
Sep 14 Javascript
jQuery实现的淡入淡出与滑入滑出效果示例
Apr 18 jQuery
react-native动态切换tab组件的方法
Jul 07 Javascript
微信小程序修改swiper默认指示器样式的实例代码
Jul 18 Javascript
详解使用VUE搭建后台管理系统(vue-cli更新至3.0)
Aug 22 Javascript
Vuejs开发环境搭建及热更新【推荐】
Sep 07 Javascript
webpack打包非模块化js的方法
Oct 24 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
php基础知识:类与对象(5) static
2006/12/13 PHP
mysql+php分页类(已测)
2008/03/31 PHP
PHP获取163、gmail、126等邮箱联系人地址【已测试2009.10.10】
2009/10/11 PHP
phpmyadmin导入(import)文件限制的解决办法
2009/12/11 PHP
php cli换行示例
2014/04/22 PHP
PHP中应该避免使用同名变量(拆分临时变量)
2015/04/03 PHP
PHP面向对象程序设计高级特性详解(接口,继承,抽象类,析构,克隆等)
2016/12/02 PHP
php封装一个异常的处理类
2017/06/08 PHP
从JQuery源码分析JavaScript函数的apply方法与call方法
2014/09/25 Javascript
JavaScript实现判断图片是否加载完成的3种方法整理
2015/03/13 Javascript
jQuery实现动态添加和删除一个div
2015/08/12 Javascript
jQuery实现动态表单验证时文本框抖动效果完整实例
2015/08/21 Javascript
Javascript模仿淘宝信用评价实例(附源码)
2015/11/26 Javascript
jquery ztree实现树的搜索功能
2016/02/25 Javascript
AngularJs基本特性解析(一)
2016/07/21 Javascript
Bootstrap Table使用方法解析
2016/10/19 Javascript
VueJS全面解析
2016/11/10 Javascript
ionic进入多级目录后隐藏底部导航栏(tabs)的完美解决方案
2016/11/23 Javascript
BootStrap实现响应式布局导航栏折叠隐藏效果(在小屏幕、手机屏幕浏览时自动折叠隐藏)
2016/11/30 Javascript
jQuery EasyUI ProgressBar进度条组件
2017/02/28 Javascript
JavaScript+Html5实现按钮复制文字到剪切板功能(手机网页兼容)
2017/03/30 Javascript
Angular2使用Guard和Resolve进行验证和权限控制
2017/04/24 Javascript
ElementUI radio组件选中小改造
2019/08/12 Javascript
用Python解决计数原理问题的方法
2016/08/04 Python
python导入时小括号大作用
2017/01/10 Python
Python 数据结构之旋转链表
2017/02/25 Python
python实现数独游戏 java简单实现数独游戏
2018/03/30 Python
python 列表中[ ]中冒号‘:’的作用
2019/04/30 Python
为什么说Python可以实现所有的算法
2019/10/04 Python
踩坑:pytorch中eval模式下结果远差于train模式介绍
2020/06/23 Python
如何使用Python进行PDF图片识别OCR
2021/01/22 Python
canvas实现有递增动画的环形进度条的实现方法
2019/07/10 HTML / CSS
毕业生医学检验求职信
2013/10/16 职场文书
2015年班级工作总结范文
2015/04/03 职场文书
CSS实现两列布局的N种方法
2021/08/02 HTML / CSS
利用JuiceFS使MySQL 备份验证性能提升 10 倍
2022/03/17 MySQL