基于setTimeout制作滚动广告板
很多网站在其门户页面的上方正中央都会放置一个滚动广告板,用于显示一些推荐信息,用户点击即可进入浏览。比较常见的就是各个公司的官网,电商网站的首页等。
下面是天猫的滚动广告板截图。
其实,不需要借助于什么复杂的技术,仅仅通过setTimeout函数,就能实现这种滚动广告板的效果。
分析
仔细观察这个滚动广告版,我们发现,其功能无非就两点:
- 无限循环的不停滚动显示每一条广告
- 当点击某一个广告的索引时,以那条广告为起点,无限循环滚动
先分析一下第一个功能点。
要做到无限循环的不停滚动显示每一条广告,那么只需要关注两个相邻广告页的切换(暂且称为函数doSwitch),然后通过设置定时任务不停的运行doSwitch就可以了。因此,我们有了一个基本的雏形:
function doSwitch() {
//switch adjacent ad pages
}
function autoSwitch() {
doSwitch();
};
setTimeout(autoSwitch, someInterval)
现在,我们只需要重点关注switch的实现就可以了。
上面截图中,广告页通过淡入淡出效果来进行切换,很容易就联想到css3中的opacity属性(天猫也是这么实现的),但是考虑到IE8的存在,opacity就不适用了,由于具体的切换效果与今天的主题关系不大,所以改成了横向滚动切换效果。
横向滚动有很多种实现效果,最直接的方式,就是通过margin-left来实现。设广告页的宽度为w,以当前广告页左边的边框为基准线,将当前广告页的margin-left由0逐渐递减至-w,将下一广告页的margin-left由w逐渐减至0(广告板的父容器设置overflow:hidden)。因此,doSwitch可以简单实现如下:
function doSwitch() {
var curPage = document.getElementById(curPageId),
nextPage = document.getElementById(nextPageId);
curPage.style.marginLeft -= step; // 此处忽略了单位处理
nextPage.style.marginLeft -= step;
if (nextPage.style.marginLeft > 0) {
setTimeout(doSwitch, someInnerInterval);
} else {
setTimeout(autoSwitch, someInterval);
}
}
由于切换效果的时间应该远小于广告停留的时间,所以此处someInnerInterval小于someInterval.
注意到,每次广告页的切换,广告页下方的索引按钮也会跟着切换,因此,上方的autoSwitch函数中还要增加一项设置当前选中索引的功能,暂且成为setCurIndex函数,则autoSwitch实现修改如下:
function autoSwitch() {
setCurIndex();
doSwitch();
}
到此,无限循环滚动显示广告的功能就完成了.
上面的代码只做基本原理介绍,实际操作过程中还有很多细节需要处理。
再看第二个功能点。
当用户点击某个广告页的索引时,当前广告会立即被切换到选中的广告页,并从选中的广告页开始循环滚动。咋一看跟功能点一很像,似乎只需要在用户点击某个索引的时候将当前广告页设置为用户选中的广告页就可以了。但是很多时候,最直接的想法往往是不对的,这里需要考虑到setTimeout的原理。
setTimeout函数的正确使用姿势应该像下面的代码一样:
var timeout = setTimeout(function () {
//do something after at least 1s
}, 1000);
// clearTimeout(timeout); //cancel setTimeout handler function
我们知道,JavaScript是单线程的,定时器只是计划代码在未来的某个时间点执行,但是,执行时机是不能保证的。在页面的生命周期中,不同时间可能有其他代码控制着JavaScript线程。例如在页面下载完后的代码运行、事件处理程序、Ajax请求的回调函数等都必须使用同样的线程来执行。实际上,浏览器负责进行排序,指派某段代码在某个时间点运行的优先级。在浏览器内部管理着一个代码队列,随着页面生命周期的推移,代码会按照执行顺序添加入队列。例如,当某个按钮被按下时,它的事件处理程序代码就会被添加到队列中,并在下一个可能的时间里执行。当接到某个Ajax响应时,回调函数的代码会被添加到队列。浏览器通过事件循环的机制从这个队列中取出处理函数代码并执行。
定时器对队列的工作方式是,在指定时间过去后,将代码插入队列。请注意,给队列添加代码并不意味着它会立即执行,而只能表示它会尽快执行。与setTimeout函数成对出现的是clearTimeout函数,用于取消setTimeout设置的延时执行的函数。该函数只接受一个参数,那就是setTimeout返回的延时调用ID。
回到刚才的问题中,功能一中,通过setTimeout函数,不停的将doSwitch和autoSwitch函数添加到队列中,如果当用户点击某个广告页索引时,只是简单的将当前广告设置为选中的广告页,然后调用autoSwitch的话,将会导致两个无限循环滚动同时运行,这必将导致广告页显示的混乱。
那么如何解决这个问题呢?
当用户点击某个索引时,我们只需要终止之前一直运行的循环滚动,然后开启新的循环滚动即可。那么问题就聚焦在如何终止上一个循环滚动上面来了。实际上,我们可以通过clearTimeout来实现。我们只需要在doSwitch中添加一个状态检测,如果用户当前点击了某个索引,则退出函数执行。样例如下:
function doSwitch() {
if (paused) {
return;
}
// other
}
这时候,我们只需要在用户点击某个广告索引时,设置paused为true,然后在新一轮的循环滚动开始前将paused设置为false就可以了。代码如下:
indexDom.onclick = function () {
setCurIndex();
paused = true;
setTimeout(function () {
paused = false;
autoSwitch();
}, someInterval);
}
需要注意的一点是,这里的someInterval与功能点一中的someInterval要保持相同。由于someInnerInterval小于someInterval,所以在下一个循环滚动开始之前,上一个循环滚动已经停止了。
到此,实际上基本功能就已经结束了,但是在完成基本功能之后,我们还要照顾到异常场景的存在。这里就需要处理短时间内连续点击不同索引的情况。
其实也很简单,只需要在onclick时间处理函数中保存一个curClick索引,然后在延时函数中比对curClick是否与当前的curIndex一致就可以了。
所以上面的onclick可以改写如下:
indexDom.onclick = function () {
var curClick = indexDom["data-index"]; //get the index of indexDom
setCurIndex();
curIndex = curClick;
setTimeout(function () {
if (curIndex !== curClick) {
return;
}
paused = true;
setTimeout(function () {
paused = false;
authSwitch();
}, someInterval)
}, 0);
}
到此,整个滚动广告板就做完了,但是实现功能仅仅是第一步,下一步还需要将其组件化,将一些内部状态隐藏,抽象出组件接口。在使用的时候,只需要实例化一个组件实例,然后使用必要的数据调用组件接口就可以了。
下面是实现的效果图:
源代码稍后放出:)
基于setTimeout制作滚动广告板的更多相关文章
- 基于html5页面滚动背景图片动画效果
基于html5页面滚动背景图片动画效果是一款带索引按钮的页面滚动动画特效代码.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div id="fullpage&q ...
- 基于JQuery实现滚动到页面底端时自动加载更多信息
基于JQuery实现滚动到页面底端时自动加载更多信息 关键代码: 代码如下: var stop=true; $(window).scroll(function(){ totalheight = par ...
- 【转】基于laravel制作APP接口(API)
这篇文章主要介绍了基于laravel制作APP接口(API)的相关资料,需要的朋友可以参考下 前期准备 前言,为什么做以及要做个啥本人姓小名白,不折不扣编程届小白一名,但是自从大一那会儿接触到编程这件 ...
- 基于CSS3制作的鼠标悬停动画菜单
之前分享了好多款css3实现的鼠标悬停效果.今天再给大家带来一款基于CSS3制作的鼠标悬停动画菜单.这款菜单适用浏览器:360.FireFox.Chrome.Safari.Opera.傲游.搜狗.世界 ...
- 制作滚动视图(ScrollView)
怎样判断是否应当使用滚动视图 所谓的滚动视图,是指一个可以滑动的视窗,视窗大小和位置固定不变,视窗内的内容用户可以通过手指滑动或者拖动滚动天来进行滚动浏览. 滚动视图的目的是为了解决同类内容过多,一个 ...
- Docker系列06—基于容器制作镜像并上传到Docker Registry
本文收录在容器技术学习系列文章总目录 1.制作镜像 1.1 镜像的生成途径 基于容器制作 dockerfile,docker build 本篇主要详细讲解基于容器制作镜像:基于dockerfile 制 ...
- 基于jQuery实现滚动新闻代码下载
分享一款基于jQuery实现滚动新闻代码下载.这是一款基于bootstrup 3实现的响应式jQuery滚动新闻插件.效果图如下: 在线预览 源码下载 实现的代码. html代码: <div ...
- 利用jquery制作滚动到指定位置触发动画
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>利用 ...
- Expression Design与Blend制作滚动的小球动画教程
原文:Expression Design与Blend制作滚动的小球动画教程 一,开发工具 Microsoft Expression Design & Blend 4.0 (3.0亦可). 这两 ...
随机推荐
- Ubuntu 16.04 安装jdk
Ubuntu 16.04 安装jdk 准备工作 安装版本:jdk-8u91-linux-x64.tar.gz 官方下载 创建目录作为JDK的安装目录,这里选择安装位置为:/usr/java/ sudo ...
- [转]windows7远程桌面连接失败:发生身份验证错误。要求的函数不受支持
转至:https://jingyan.baidu.com/article/d169e18604ca86436611d821.html 系统升级后出现远程连接报错,“发生身份验证错误.要求的函数不受支持 ...
- MVC - Routing - 网址路由
1. Routing : 路由 主要是比对通过浏览器传来的http要求与响应适当的网址给浏览器. @Html.ActionLink("关于","About", ...
- 文字相对于 div 垂直居中
通用方法 height 跟line-height div{ border: 1px solid black; text-align: left; height: 200px; line-height ...
- EventTrigger
EventTrigger事件触发器. 相比较数据,属性,事件触发器是XAML的UI层中最重要的一个部分. 事件触发器中,触发的效果是动画,不再是setter. 也是很有意思的 <对象.Style ...
- 在win7系统上搭建django+oracle 11g时,注意事项
在win7系统上搭建django+oracle 11g时,注意事项[示例用的是python 2.7]: 重要:python.oracle.oracle client这三个的OS bit 一定一定要相同 ...
- python操作RabbitMQ、Redis、Memcache、SQLAlchemy
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度 ...
- Tarjan 点双+割点+DFS【洛谷P3225】 [HNOI2012]矿场搭建
P3225 [HNOI2012]矿场搭建 题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤 ...
- (STM32F4) External Interrupt
外部中斷(External Interupt) 在MCU中是很常見而且很常用到的基本function,所以就不多做解釋.不過因為每顆MCU的配置都不太一樣所以在此記錄下來. External Inte ...
- docker加速器配置
我使用docker的原因 最近自己一直在强迫自己使用docker,一方面是docker的容器化服务,使得每一个配置相互独立,易于维护.而且如果到后面如果深入了的话,通过自己编写dockerfile,那 ...