javascript手工制作悬浮菜单


Posted in Javascript onFebruary 12, 2015

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

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

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

javascript手工制作悬浮菜单

第一步创建dom节构:

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8">

    <title>AppCarrier</title>

    <link rel="stylesheet" href="menu.css">

</head>

<body>

    <div id="content">

              <h1 id="test1">test1</h1>

              <p>The past can hurt. But you can either run from it or learn from it</p>

              <p>过去是痛楚的,但你要么逃避,要么从中成长</p>

              <p>One meets his destiny on the road he takes to avoid it</p>

              <p>往往在逃避命运的路上,却与之不期而遇</p>

              <p>Rules are meant to be broken</p>

              <p>规则就该被打破。</p>

              <p>Years may wrinkle the skin, but to give up enthusiasm wrinkles the soul.</p>

              <p>岁月流逝只令容颜苍老,激情不再却使心灵枯萎。</p>

              <h1 id="test2">test2</h1>

              <p>只有不断地练习学到的知识,你才能真正掌握它。</p>

              <p>Live every day to the fullest.</p>

              <p>尽享每日。</p>

              <p>Keep your eyes on the stars, and your feet on the ground.</p>

              <p>志存高远,脚踏实地。</p>

              <p>Always be up for an unexpected adventure.</p>

              <p>随时准备开始一场意外冒险吧。</p>

              <p>Life is full of disappointment. You can't dwell on things. You have to move on.</p>

              <p>生活常不如意,别沉溺往事,要勇往直前。</p>

              <p>I'm a free spirit. I can't be caged.</p>

              <p>我的灵魂是自由的,不该被束缚。</p>

              <p>Sometimes the heart sees what is invisible to the eye.</p>

              <p>目不见者,心可感之</p>

              <p>The simple things are also the most extraordinary things, and only the wise can see them.</p>

              <p>最平凡的事也是最非凡的事,只有智者才明白。</p>

              <h1 id="test3">test3</h1>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <h1 id="test4">test4</h1>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

              <p>how many xxxxxx</p>

    </div>

    <div class="menu" id="menubar">

        <p class="static">隐藏</p>

        <ul>

            <li><a href="#test1">test1</a></li>

            <li><a href="#test2">test2</a></li>

            <li><a href="#test3">test3</a></li>

            <li><a href="#test4">test4</a></li>

        </ul>

    </div>

</body>

<script src="menu.js"></script>

</html>

第二步准备css文件:

ul {

    list-style-type: none;

}

a {

    text-decoration: none;

}

/*文章内容区*/

#content {

    width:400px;

    margin: 0 auto;

    font-size: 2em;

}

/*悬浮菜单*/

.menu {

    position: fixed;

    top:20%;

    right: 0;

    width:200px;

    border: 1px solid gray;

    border-radius: 5px;

}

.menu li {

    height: 2em;

    line-height: 2em;

}

.red {

    color : red;

}

.hide {

    display: none;

}

/*隐藏悬浮菜单*/

.slideIn {

    transform : translate3d(202px, 0, 0);

    transition-duration : .5s;

}

/*显示悬浮菜单*/

.slideOut {

    transform : translate3d(0, 0, 0);

    transition-duration : .5s;

}

.static {

    color:#007aff;

    text-align: center;

}

/*显示悬浮球*/

.toShow {

    display: block;

        width: 4.8em;

        height: 2em;

        line-height: 2em;

        border-radius: .5em;

    border:1px solid gray;

    transform : translate3d(-5em, 0, 0);

    transition-duration : 1s;

}

第三步开始编写js代码:

(function(doc){

    //收集各章节的链接位置

     var pos = [],

         //收集菜单上的项目

         links = doc.getElementsByTagName('a'),

         //收集章节的标题

         titles = doc.getElementsByTagName('h1'),

         //悬浮菜单

         menu = doc.getElementById('menubar'),

         //当前选择项

         currentItem=null;

     //添加红色样式

     var addClass = function (element){

             currentItem && currentItem.removeAttribute('class');

             element.setAttribute('class','red');

             currentItem = element;

         },

         //网页被卷去的高:

        getScrollTop = function (){

            return Math.ceil(document.body.scrollTop)+1;

        },

         //计算滚动位置

        startScroll = function (){

            var scrollTop = getScrollTop(),

                len = titles.length,

                i = 0;

            //第一条

            if(scrollTop>=0 && scrollTop<pos[0]){

                addClass(links[0]);

                return;

            }

            //最后一条

            if(scrollTop>=pos[len-1]){

                addClass(links[len-1]);

                return;

            }

            //中间

            for(;i<len;i++){

                if(scrollTop > pos[i] && scrollTop < pos[i+1]){

                    addClass(links[i]);

                    break;

                }

            }

    };

     //点击列表中的链接变色

     menu.onclick=function(e){

         var target = e.target || e.srcElement;

         if(target.nodeName.toLowerCase() === 'a'){

             //列表项状态指示

             addClass(target);

             return;

         }

         if(target.nodeName.toLowerCase() === 'p'){

             if(target.className == 'static'){

                 //隐藏菜单

                 this.className = 'menu slideIn';

                 setTimeout(function(){

                     target.className = 'static toShow';

                     target.innerHTML = '显示';

                 },1000);

             }else{

                 //显示菜单

                 target.className = 'static';

                 target.innerHTML = '隐藏';

                 this.className = 'menu slideOut';

             }

         }

     }

    //计算各章节的初始位置

    var ln = titles.length;

    while(--ln>-1){

        //titles[len].offsetParent.offsetTop = 0;

        pos.unshift(titles[ln].offsetTop);

    }

    startScroll();

    //监听滚动

    window.onscroll = function(){

          startScroll()

    }

})(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为复位。

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

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

以上就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
基于jQuery图片平滑连续滚动插件
Apr 27 Javascript
ExtJS4 组件化编程,动态加载,面向对象,Direct
May 12 Javascript
使用node.js半年来总结的 10 条经验
Aug 18 Javascript
node.js中Socket.IO的进阶使用技巧
Nov 04 Javascript
JS实现左右拖动改变内容显示区域大小的方法
Oct 13 Javascript
Node.js获取前端ajax提交的request信息
Feb 20 Javascript
浅谈redux以及react-redux简单实现
Aug 28 Javascript
发布Angular应用至生产环境的方法
Dec 10 Javascript
小程序实现人脸识别功能(百度ai)
Dec 23 Javascript
关于layui 下拉列表的change事件详解
Sep 20 Javascript
微信小程序自定义组件components(代码详解)
Oct 21 Javascript
jquery+javascript编写国籍控件
Feb 12 #Javascript
JS实现的生成随机数的4个函数分享
Feb 11 #Javascript
JavaScript中的分号插入机制详细介绍
Feb 11 #Javascript
Javascript核心读书有感之语句
Feb 11 #Javascript
JavaScript数据结构和算法之二叉树详解
Feb 11 #Javascript
JavaScript中的函数模式详解
Feb 11 #Javascript
Javascript核心读书有感之表达式和运算符
Feb 11 #Javascript
You might like
重置版游戏视频
2020/04/09 魔兽争霸
php+js iframe实现上传头像界面无跳转
2014/04/29 PHP
Yii2.0使用阿里云OSS的SDK上传图片、下载、删除图片示例
2017/09/20 PHP
Laravel框架源码解析之模型Model原理与用法解析
2020/05/14 PHP
脚本吧 - 幻宇工作室用到js,超强推荐base.js
2006/12/23 Javascript
用JavaScript显示随机图像或引用
2009/04/21 Javascript
jQuery找出网页上最高元素的方法
2015/03/20 Javascript
js中日期的加减法
2015/05/06 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
javascript cookie的简单应用
2016/02/24 Javascript
Js动态设置rem来实现移动端字体的自适应代码
2016/10/14 Javascript
JavaScript实现清空(重置)文件类型INPUT元素值的方法
2016/11/17 Javascript
JavaScript中click和onclick本质区别与用法分析
2018/06/07 Javascript
ES6知识点整理之函数数组参数的默认值及其解构应用示例
2019/04/17 Javascript
vue-cli3中vue.config.js配置教程详解
2019/05/29 Javascript
微信小程序request请求封装,验签代码实例
2019/12/04 Javascript
vue element 关闭当前tab 跳转到上一路由操作
2020/07/22 Javascript
python发送邮件功能实现代码
2016/07/15 Python
Python简单实现Base64编码和解码的方法
2017/04/29 Python
PyQt5 pyqt多线程操作入门
2018/05/05 Python
Python Celery多队列配置代码实例
2019/11/22 Python
Python实现图片批量加入水印代码实例
2019/11/30 Python
基于Python脚本实现邮件报警功能
2020/05/20 Python
keras 获取某层的输入/输出 tensor 尺寸操作
2020/06/10 Python
pyqt5实现井字棋的示例代码
2020/12/07 Python
OpenCV+Python3.5 简易手势识别的实现
2020/12/21 Python
html5 canvas的绘制文本自动换行的示例代码
2018/09/17 HTML / CSS
canvas绘图按照contain或者cover方式适配并居中显示
2019/02/18 HTML / CSS
加拿大女包品牌:Matt & Nat
2017/05/12 全球购物
Ray-Ban雷朋西班牙官网:全球领先的太阳眼镜品牌
2018/11/28 全球购物
农林环境专业求职信
2014/03/13 职场文书
2014年社区教育工作总结
2014/12/02 职场文书
nginx配置虚拟主机的详细步骤
2021/07/21 Servers
Python实现视频中添加音频工具详解
2021/12/06 Python
Java完整实现记事本代码
2022/06/16 Java/Android
Zabbix对Kafka topic积压数据监控的问题(bug优化)
2022/07/07 Servers