移动端效果之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 相关文章推荐
在模板页面的js使用办法
Apr 01 Javascript
汉化英文版的Dreamweaver CS5并自动提示jquery
Nov 25 Javascript
jquery仿QQ商城带左右按钮控制焦点图片切换滚动效果
Jun 27 Javascript
JS烟花背景效果实现方法
Mar 03 Javascript
深入分析下javascript中的[]()+!
Jul 07 Javascript
javascript解析xml实现省市县三级联动的方法
Jul 25 Javascript
js实现StringBuffer的简单实例
Sep 02 Javascript
js中利用cookie实现记住密码功能
Aug 20 Javascript
如何提高数据访问速度
Dec 26 Javascript
深入理解javascript中的 “this”
Jan 17 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
Feb 10 Javascript
jQuery实现为table表格动态添加或删除tr功能示例
Feb 19 jQuery
详解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
SONY ICF-SW07收音机电路分析
2021/03/02 无线电
pw的一个放后门的方法分析
2007/10/08 PHP
PHP 之Section与Cookie使用总结
2012/09/14 PHP
PHP中通过HTTP_USER_AGENT判断是否为手机移动终端的函数代码
2013/02/14 PHP
php正则表达式使用的详细介绍
2013/04/27 PHP
PHP用continue跳过本次循环中剩余代码的注意点
2017/06/27 PHP
ThinkPHP框架下微信支付功能总结踩坑笔记
2019/04/10 PHP
使用TextRange获取输入框中光标的位
2006/10/14 Javascript
跟着JQuery API学Jquery 之三 筛选
2010/04/09 Javascript
JavaScript高级程序设计 XML、Ajax 学习笔记
2011/09/10 Javascript
JavaScript不使用prototype和new实现继承机制
2014/12/29 Javascript
js控制文本框只输入数字和小数点的方法
2015/03/10 Javascript
jQuery实现手机自定义弹出输入框
2016/06/13 Javascript
Javascript类型系统之String字符串类型详解
2016/06/21 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
2016/11/01 Javascript
详解react如何在组件中获取路由参数
2017/06/15 Javascript
详解require.js配置路径的用法和css的引入
2017/09/06 Javascript
基于VUE.JS的移动端框架Mint UI的使用
2017/10/11 Javascript
JavaScript门道之标准库
2018/05/26 Javascript
JavaScript中引用vs复制示例详析
2018/12/06 Javascript
关于vue表单提交防双/多击的例子
2019/10/31 Javascript
JavaScript基于面向对象实现的无缝滚动轮播示例
2020/01/17 Javascript
Vue使用自定义指令实现拖拽行为实例分析
2020/06/06 Javascript
vue中利用three.js实现全景图的完整示例
2020/12/07 Vue.js
python 获取网页编码方式实现代码
2017/03/11 Python
使用TensorFlow实现二分类的方法示例
2019/02/05 Python
python 实现多维数组转向量
2019/11/30 Python
浅谈Pytorch中的自动求导函数backward()所需参数的含义
2020/02/29 Python
Python闭包装饰器使用方法汇总
2020/06/29 Python
Python pip 常用命令汇总
2020/10/19 Python
估算杭州有多少软件工程师
2015/08/11 面试题
营销主管自我评价怎么写
2013/09/19 职场文书
2014年中秋寄语
2014/08/11 职场文书
小学教师年度个人总结
2015/02/05 职场文书
详解Redis瘦身指南
2021/05/26 Redis
Pytest中conftest.py的用法
2021/06/27 Python