这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
这篇文章主要介绍了 javascript 手工制作悬浮菜单,主要也是想自己练练手,感觉还不错,这里推荐给大家。
有选择性的重复造一些轮子,未必是件坏事。Aaron 的博客上加了一个悬浮菜单,貌似显得很高大上了。虽然这类小把戏也不是头一次见了,但是从未自己写过。今天就选择性的拿这个功能写一写。下面是这个轮子的开发过程,也可以当作是一篇需求文档的分析和实现过程。
演示地址:http://sandbox.runjs.cn/show/to8wdmuy
源码下载:https://github.com/bjtqti/floatmenu
第一步创建 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 为复位。
分析完之后,就是编写代码了。这没有什么好说的。尽情享受敲击键盘产生的乐感吧。
写完之后,预览一下,点击菜单,跳入指定章节,同时点击项变红色,刷新当前页面,依赖显示正确。滑动一下滚轮,菜单项随着内容的变化而相应的变化,拖动一下滚动条,也是这样,最后点击一下隐藏,菜单缩回去,点击显示,菜单滑出来。这样悬浮功能就做完了。
来源: http://www.phperz.com/article/17/0424/272785.html