有选择性的重复造一些轮子,未必是件坏事。Aaron的博客上加了一个悬浮菜单,貌似显得很高大上了。虽然这类小把戏也不是头一次见了,但是从未自己写过。今天就选择性的拿这个功能写一写。下面是这个轮子的开发过程,也可以当作是一篇需求文档的分析和实现过程。

演示地址:http://sandbox.runjs.cn/show/to8wdmuy

源码下载:https://github.com/bjtqti/study/tree/master/floatmenu

第一步创建dom节构:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>AppCarrier</title>
  6. <link rel="stylesheet" href="menu.css">
  7. </head>
  8. <body>
  9.  
  10. <div id="content">
  11. <h1 id="test1">test1</h1>
  12. <p>The past can hurt. But you can either run from it or learn from it</p>
  13. <p>过去是痛楚的,但你要么逃避,要么从中成长</p>
  14. <p>One meets his destiny on the road he takes to avoid it</p>
  15. <p>往往在逃避命运的路上,却与之不期而遇</p>
  16. <p>Rules are meant to be broken</p>
  17. <p>规则就该被打破。</p>
  18. <p>Years may wrinkle the skin, but to give up enthusiasm wrinkles the soul.</p>
  19. <p>岁月流逝只令容颜苍老,激情不再却使心灵枯萎。</p>
  20. <h1 id="test2">test2</h1>
  21. <p>只有不断地练习学到的知识,你才能真正掌握它。</p>
  22. <p>Live every day to the fullest.</p>
  23. <p>尽享每日。</p>
  24. <p>Keep your eyes on the stars, and your feet on the ground.</p>
  25. <p>志存高远,脚踏实地。</p>
  26. <p>Always be up for an unexpected adventure.</p>
  27. <p>随时准备开始一场意外冒险吧。</p>
  28. <p>Life is full of disappointment. You can't dwell on things. You have to move on.</p>
  29. <p>生活常不如意,别沉溺往事,要勇往直前。</p>
  30. <p>I'm a free spirit. I can't be caged.</p>
  31. <p>我的灵魂是自由的,不该被束缚。</p>
  32. <p>Sometimes the heart sees what is invisible to the eye.</p>
  33. <p>目不见者,心可感之</p>
  34. <p>The simple things are also the most extraordinary things, and only the wise can see them.</p>
  35. <p>最平凡的事也是最非凡的事,只有智者才明白。</p>
  36. <h1 id="test3">test3</h1>
  37. <p>how many xxxxxx</p>
  38. <p>how many xxxxxx</p>
  39. <p>how many xxxxxx</p>
  40. <p>how many xxxxxx</p>
  41. <p>how many xxxxxx</p>
  42. <p>how many xxxxxx</p>
  43. <p>how many xxxxxx</p>
  44. <p>how many xxxxxx</p>
  45. <p>how many xxxxxx</p>
  46. <p>how many xxxxxx</p>
  47. <p>how many xxxxxx</p>
  48. <p>how many xxxxxx</p>
  49. <p>how many xxxxxx</p>
  50. <p>how many xxxxxx</p>
  51. <p>how many xxxxxx</p>
  52. <p>how many xxxxxx</p>
  53. <h1 id="test4">test4</h1>
  54. <p>how many xxxxxx</p>
  55. <p>how many xxxxxx</p>
  56. <p>how many xxxxxx</p>
  57. <p>how many xxxxxx</p>
  58. <p>how many xxxxxx</p>
  59. <p>how many xxxxxx</p>
  60. <p>how many xxxxxx</p>
  61. <p>how many xxxxxx</p>
  62. <p>how many xxxxxx</p>
  63. <p>how many xxxxxx</p>
  64. <p>how many xxxxxx</p>
  65. <p>how many xxxxxx</p>
  66. <p>how many xxxxxx</p>
  67. <p>how many xxxxxx</p>
  68. <p>how many xxxxxx</p>
  69. <p>how many xxxxxx</p>
  70. </div>
  71.  
  72. <div class="menu" id="menubar">
  73. <p class="static">隐藏</p>
  74. <ul>
  75. <li><a href="#test1">test1</a></li>
  76. <li><a href="#test2">test2</a></li>
  77. <li><a href="#test3">test3</a></li>
  78. <li><a href="#test4">test4</a></li>
  79. </ul>
  80.  
  81. </div>
  82.  
  83. </body>
  84. <script src="menu.js"></script>
  85. </html>

第二步准备css文件:

  1. ul {
  2. list-style-type: none;
  3. }
  4. a {
  5. text-decoration: none;
  6. }
  7. /*文章内容区*/
  8. #content {
  9. width:400px;
  10. margin: 0 auto;
  11. font-size: 2em;
  12. }
  13. /*悬浮菜单*/
  14. .menu {
  15. position: fixed;
  16. top:20%;
  17. right: 0;
  18. width:200px;
  19. border: 1px solid gray;
  20. border-radius: 5px;
  21. }
  22.  
  23. .menu li {
  24. height: 2em;
  25. line-height: 2em;
  26. }
  27.  
  28. .red {
  29. color : red;
  30. }
  31.  
  32. .hide {
  33. display: none;
  34. }
  35.  
  36. /*隐藏悬浮菜单*/
  37. .slideIn {
  38. transform : translate3d(202px, 0, 0);
  39. transition-duration : .5s;
  40. }
  41.  
  42. /*显示悬浮菜单*/
  43. .slideOut {
  44. transform : translate3d(0, 0, 0);
  45. transition-duration : .5s;
  46. }
  47.  
  48. .static {
  49. color:#007aff;
  50. text-align: center;
  51. }
  52.  
  53. /*显示悬浮球*/
  54. .toShow {
  55. display: block;
  56. width: 4.8em;
  57. height: 2em;
  58. line-height: 2em;
  59. border-radius: .5em;
  60. border:1px solid gray;
  61. transform : translate3d(-5em, 0, 0);
  62. transition-duration : 1s;
  63. }

第三步开始编写js代码:

  1. (function(doc){
  2. //收集各章节的链接位置
  3. var pos = [],
  4. //收集菜单上的项目
  5. links = doc.getElementsByTagName('a'),
  6. //收集章节的标题
  7. titles = doc.getElementsByTagName('h1'),
  8. //悬浮菜单
  9. menu = doc.getElementById('menubar'),
  10. //当前选择项
  11. currentItem=null;
  12.  
  13. //添加红色样式
  14. var addClass = function (element){
  15. currentItem && currentItem.removeAttribute('class');
  16. element.setAttribute('class','red');
  17. currentItem = element;
  18. },
  19.  
  20. //网页被卷去的高:
  21. getScrollTop = function (){
  22. return Math.ceil(document.body.scrollTop)+1;
  23. },
  24.  
  25. //计算滚动位置
  26. startScroll = function (){
  27. var scrollTop = getScrollTop(),
  28. len = titles.length,
  29. i = 0;
  30.  
  31. //第一条
  32. if(scrollTop>=0 && scrollTop<pos[0]){
  33. addClass(links[0]);
  34. return;
  35. }
  36. //最后一条
  37. if(scrollTop>=pos[len-1]){
  38. addClass(links[len-1]);
  39. return;
  40. }
  41. //中间
  42. for(;i<len;i++){
  43. if(scrollTop > pos[i] && scrollTop < pos[i+1]){
  44. addClass(links[i]);
  45. break;
  46. }
  47. }
  48. };
  49.  
  50. //点击列表中的链接变色
  51. menu.onclick=function(e){
  52. var target = e.target || e.srcElement;
  53.  
  54. if(target.nodeName.toLowerCase() === 'a'){
  55. //列表项状态指示
  56. addClass(target);
  57. return;
  58. }
  59.  
  60. if(target.nodeName.toLowerCase() === 'p'){
  61. if(target.className == 'static'){
  62. //隐藏菜单
  63. this.className = 'menu slideIn';
  64. setTimeout(function(){
  65. target.className = 'static toShow';
  66. target.innerHTML = '显示';
  67. },1000);
  68. }else{
  69. //显示菜单
  70. target.className = 'static';
  71. target.innerHTML = '隐藏';
  72. this.className = 'menu slideOut';
  73. }
  74. }
  75. }
  76.  
  77. //计算各章节的初始位置
  78. var ln = titles.length;
  79. while(--ln>-1){
  80. //titles[len].offsetParent.offsetTop = 0;
  81. pos.unshift(titles[ln].offsetTop);
  82. }
  83.  
  84. startScroll();
  85.  
  86. //监听滚动
  87. window.onscroll = function(){
  88. startScroll()
  89. }
  90.  
  91. })(document);

分析:

1. 实现自动跳转到指定节

这一步可以利用<a>标签的锚功能来做,由于html5以后不支持name 属性(HTML5 不支持。规定锚的名称。),所以考虑用ID来跳转。

2. 标识悬浮菜单中的项属于左边内容中的哪个章节。

这一步是难点,先简单分析一下:

2.1 第一种情况,就是人为点击菜单项。这个很容易,只要标识点击的元素就可以了。

2.2 第二种情况,通过鼠标中键滚动或拖动滚动条,这个时候要关联左边内容和右边菜单项,这是最难的地方。考虑分步实施,先易后难,各各击破的策略。

  2.2.1 先收集标题元素的坐标高度。也就是所有的h1标签的垂直高度。存入数组1.

  2.2.2 收集菜单项中的a元素,存入数组2.

2.2.3  监听滚动事件,判断当前内容属于哪个菜单项。

做一步的时候,建议在稿纸上画一个图:

            A1

****************
                         *       A2
                         *
                         ****************
                         *       A3
                         *
                         ****************
                         *
                         *     A4
                         *

       每滚动一次,就判断当前滚动的距离是在哪一个区间,如果是0到A1则是第1章,A1到A2则是第2章,以此类推。

关于元素的位置高度,我这里简单地用element.offsetTop来获取,可能会存在兼容性问题,如果用jquery来做的话,应当是$('element').offset().top,

同样的,滚动条的高度,我也是简单的用了document.body.scrollTop来获取,如果换成jquery的话,应当是$(window).scrollTop();

画图的作用是把抽象的问题具体化,帮助我们思考,找出规律。也许称为“建模”会显得高大上一些吧。

需要强调的是数组1和数组2中的关系应当是一一对应的。如<a href="#h1">对应的是<h1 id="h1">。

2.3 第三种情况,直接进入页面时的菜单状态指示。比如通过index.html#h3这样的地址进来,菜单中的h3应当要突出显示。

3.  实现悬浮菜单的显示和隐藏动画。

3.1  这一步应当是比较简单的,可以考虑先做。利用css3的tramsform属性就可以了,简单高效,跨浏览器的话,注意兼容。

      注意transform : translate3d(x轴, y轴, z轴); 用3d是可以利用硬件加速,增加动画效果,但是功耗会增加,善用!第一个参数是控制左右方向,如果为正,则表示向右移动,如果为负则向左移动。这么说其实是不严谨的,实际上应当根据参考点来确定,比如元素的静止时的x坐标是0,那么增加x的值向右,减少为向左,0为复位。

分析完之后,就是编写代码了。这没有什么好说的。尽情享受敲击键盘产生的乐感吧。

写完之后,预览一下,点击菜单,跳入指定章节,同时点击项变红色,刷新当前页面,依赖显示正确。滑动一下滚轮,菜单项随着内容的变化而相应的变化,拖动一下滚动条,也是这样,最后点击一下隐藏,菜单缩回去,点击显示,菜单滑出来。这样悬浮功能就做完了。

查看源代码:http://runjs.cn/code/to8wdmuy

从http://www.cnblogs.com/afrog/p/4286538.html#3128047看的

js滚动的更多相关文章

  1. js 滚动到一定位置导航定位在页面最顶部

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. kxbdSuperMarquee.js滚动的神器-推荐

    http://code.ciaoca.com/jquery/kxbdmarquee/ 版本:jQuery v1.3.2+ 查看 Demo 下载 jQuery kxbdMarquee 文档目录 使用方法 ...

  3. js滚动加载插件

    function $xhyload(o){ var that=this; if(!o){ return; }else{ that.win=$(o.config.obj); that.qpanel=$( ...

  4. js滚动到指定位置

    序言:在网络上百度,关键字:“js div滚动到指定位置”,结果基本上大同小异!各种大神都给我们总结出来了四种滚动到指定位置的办法,可惜再下愚钝,每个都不会用,所以写了一个超级简单的方法来使初学者一看 ...

  5. selenium webdriver——JS滚动到指定位置

    1.DOM滚动方法 1.scrollIntoView(alignWithTop)  滚动浏览器窗口或容器元素,以便在当前视窗的可见范围看见当前元素.如果alignWithTop为true,或者省略它, ...

  6. selenium webdriver——JS滚动到最底部

    JS控制滚动条的位置: window.scrollTo(x,y); 竖向滚动条置顶 window.scrollTo(0,0); 竖向滚动条置底 window.scrollTo(0,document.b ...

  7. js滚动监听

    下边代码,是监听滚动条只要移动,下方的返回顶部的div显示与隐藏的代码 ? 1 2 3 4 5 6 7 8 window.onscroll = function () {  var t = docum ...

  8. js滚动显示: 滚动条置顶/底

    <script> //当聊天室的内容超出页面范围时, 如何让页面刷新后 显示最下面的内容 document.getElementByIdx ( 'chatboard').scrollTop ...

  9. js 滚动的文字(走马灯)

    // 滚动的文字 function marqueeScroll() { //var $target = $(".marquee_outer:visible"); if($(&quo ...

随机推荐

  1. 浅谈Java三大框架与应用

    前言:对于一个程序员来说,尤其是在java web端开发的程序员,三大框架:Struts+Hibernate+Spring是必须要掌握熟透的,因此,下面谈谈java三大框架的基本概念和原理. JAVA ...

  2. dubbo之服务分组

    当一个接口有多种实现时,可以用group区分. 服务 <dubbo:service group="feedback" interface="com.xxx.Inde ...

  3. AI: DL方法与问题空间探索

    所谓问题的解决是生存参数空间的一种状态转移到另外一种状态,而目的状态恰好是主体所希望的.完成这种转换的一系列脚本变化过程叫做场景序列,也叫通路.驱动这一些列场景转换的主体参与过程,被称为主动执行.而主 ...

  4. 读书笔记「Python编程:从入门到实践」_5.if语句

    5.1 一个简单示例 cars = ['audi', 'bmw', 'subaru', 'toyota'] for car in cars: if car == 'bmw': print(car.up ...

  5. (转)Arcgis for JS之对象捕捉

    http://blog.csdn.net/gisshixisheng/article/details/44098615 在web操作,如绘制或者测量的时候,为了精确,需要捕捉到某一图层的对象,在此,讲 ...

  6. 初探CORBA组件化编程

    1.掌握组件化开发的概念,了解CORBA模型及ORB机制:2.掌握CORBA组件编程方法.二.实验内容(一).步骤1.配制环境JDK环境.2.编写编译IDL接口.3.编写编译服务端程序.4.编写编译客 ...

  7. Testbench文件编写纪要(Verilog)

    之前在使用Verilog做FPGA项目中.以及其他一些不同的场合下,零散的写过一些练手性质的testbench文件,开始几次写的时候,每次都会因为一些基本的东西没记住.写的很不熟练,后面写的时候稍微熟 ...

  8. PAT_A1111#Online Map

    Source: PAT A1111 Online Map (30 分) Description: Input our current position and a destination, an on ...

  9. sql积累

    mysql 修改一列自增长 set @rownum=0; update a SET id = ( select @rownum := @rownum +1 as nid) WHERE id < ...

  10. C#学习笔记_06_方法&函数

    06_方法&函数 方法的定义 方法就是一个功能的集合,可以把程序中某段具有特殊功能的代码提取出来: 声明方法 [ 访问权限修饰符 ] [ 其他的修饰符 ] 返回值类型 方法名 ( [形参列表] ...