◆1-元素偏移量 offset系列
1.1 offset概述
offset翻译过来就是偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
获得元素距离带有定位父元素的位置
获得元素自身的大小 (宽度高度)
注意:返回的数值都不带单位
offset系列常用属性:
offset系列属性 | 作用 |
---|---|
element.offsetParent | 返回作为该元素带有定位的父级元素,如果父级都没有定位则返回body |
element.offsetTop | 返回元素相对带有定位父元素上方的偏移, |
element.offsetLeft | 返回元素相对带有定位父元素左边框的偏移 |
element.offsetWidth | 返回自身包括padding、边框、内容区的宽度,返回数值不带单位 |
element.offsetHeight | 返回自身包括padding、边框、内容区的高度,返回数值不带单位 |
element.offsetTop 和 element.offsetLeft 它以带有定位的父亲为准 ,如果么有父亲或者父亲没有定位 则以 body 为准。
element.offsetWidth 返回元素宽度,不包括margin值。
1.2 offset与style区别
offset
- offset可以得到任意样式表中的样式值
- offset 系列获得的数值是没有单位的 (Number)
- offsetWidth包含padding+border +with
- offsetWidth等属性是只读属性,只能获取不能赋值
- 所以,我们想要获取元素大小位置,用offset更合适
style
style 只能得到行内样式表中的样式值(获取)
style.width 获得的是带有单位的字符串(String)
style.width 获得不包含padding和border的值
style.width 是可读写属性,可以获取也可以赋值
所以,我们想要给元素更改值,则需要用style改变
案例 - 获取鼠标在盒子内的坐标 移动鼠标就可以获得鼠标在盒子内的位置。
①我们在盒子内点击,想要得到鼠标距离盒子左右的距离。
②首先得到鼠标在页面中的坐标( e.pageX, e.pageY )
③其次得到盒子在页面中的距离(box.offsetLeft, box.offsetTop)
④用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标
⑤如果想要移动-下鼠标,就要获取最新的坐标,使用鼠标移动事件mousemove。
案例 - 拖动模态框
模态框(Modal)是覆盖在父窗体上的子窗体。通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动。子窗体可提供信息、交互等。
①我们在盒子内点击,想要得到鼠标距离盒子左右的距离。
②首先得到鼠标在页面中的坐标( e.pageX, e.pageY )
③其次得到盒子在页面中的距离(box.offsetLeft, box.offsetTop)
④用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标。
⑤如果想要移动一下鼠标,就要获取最新的坐标,使用鼠标移动事件mousemove
⑥鼠标按下触发的事件源是最上面一行,就是id为title
⑦鼠标的坐标减去鼠标在盒子内的坐标,才是模态框真正的位置。
⑧鼠标按下,我们要得到鼠标在盒子的坐标。
⑨鼠标移动,就让模态框的坐标设置为:鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。D鼠标松开,就停止拖拽,就是可以让鼠标移动事件解除

案例 - 商品图片放大
黄色的遮挡层跟随鼠标功能。
把鼠标坐标给遮挡层不合适。因为遮挡层坐标以父盒子为准。
首先是获得鼠标在盒子的坐标。
之后把数值给遮挡层做为left和top值。
此时用到鼠标移动事件,但是还是在小图片盒子内移动。
发现,遮挡层位置不对,需要再减去盒子自身高度和宽度的-半。⑦遮挡层不能超出小图片盒子范围。
如果小于零,就把坐标设置为0
如果大于遮挡层最大的移动距离,就把坐标设置为最大的移动距离
遮挡层的最大移动距离:小图片盒子宽度减去遮挡层盒子宽度。
移动黄色遮挡层,大图片跟随移动功能。
- 求大图片的移动距离公式

◆2-元素可视区client系列
client翻译过来就是客户端,我们使用client系列的相关属性来获取元素可视区的相关信息。通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等。
client系列属性 | 作用 |
---|---|
element.clientTop | 返回元素上边框的大小 |
element.clientLeft | 返回元素左边框的大小 |
element.clientWidth | 返回自身包括padding、内容区的宽度,不含边框,返回数值不带单位 |
element.clientHeight | 返回自身包括padding、内容区的高度,不含边框,返凹数值不带单位 |
2.1 立即执行函数
立即执行函数的主要作用:创建一个独立的作用域,避免了命名冲突问题。
- 不需要调用,立马能够自己执行的函数
- 写法 :(function() {})() (function(){}());
- 也可以传递参数进来
- 每个立即执行函数之间用 ; 隔开,代表一个独立的立即执行函数。
1 | (function(a, b) { |
- 立即执行函数最大的作用就是 独立创建了一个作用域, 里面所有的变量都是局部变量 ,不会有命名冲突的情况。比如flexible.js的源码,所有的代码都写在一个立即执行函数中。这样和其他js里面的命名即使相同,也不会冲突。
2.2 load 和 pageshow事件
下面三种情况都会刷新页面都会触发load事件。
a标签的超链接
F5或者刷新按钮(强制刷新)
前进后退按钮
但是火狐中,有个特点,有个“往返缓存”, 这个缓存中不仅保存着页面数据,还保存了DOM和JavaScript的状态;实际上是将整个页面都保存在了内存里。所以此时后退按钮不能刷新页面。
此时可以使用pageshow事件来触发。这个事件在页面显示时触发 ,无论页面是否来自缓存。在重新加载页面中, pageshow会在load事件触发后触发;根据事件对象中的persisted来判断是否是缓存中的页面触发的pageshow事件,注意这个事件给window添加。
1 | window.addEventListener('pageshow', function(e) { |
◆3-元素滚动 scroll系列
3.1元素scroll系列属性
scroll翻译过来就是滚动的,我们使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等。

scroll系列属性 | 作用 |
---|---|
element.scrollTop | 返回被卷去的上侧距离,返回数值不带单位 |
element.scrollLleft | 返回被卷去的左侧距离,返回数值不带单位 |
element.scrollWidth | 返回自身实际的宽度,不含边框,返回数值不带单位 |
element.scrollHeigh | 返回自身实际的高度,不含边框,返回数值不带单位 |
scrollWidth 和 clientWidth 的区别就是 :如果盒子里面的内容超过了盒子的尺寸,scrollWidth会包括超出盒子的部分,clientWidth不会包括这部分。
3.2页面被卷去的头部兼容性解决方案
需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:
1.声明了DTD ,使用document.documentElement.scrollTop
2.未声明DTD ,使用document.body.scrollTop
3.新方法window.pageYoffset
和window.pageXoffset
, IE9开始支持
案例 - 仿淘宝固定侧边栏
①需要用到页面滚动事件scroll因为是页面滚动,所以事件源是document
②滚动到某个位置,就是判断页面被卷去的上部值。
③页面被卷去的头部:可以通过window.pageYOffset 获得如果是 ,被卷去的左侧window.pageXOffset
④注意,元素被卷去的头部是element.scrollTop ,如果是页面被卷去的头部则是window.pageYOffset
3.3 三大系列总结
offset系列 经常用于获得元素位置offsetLeft offsetTop(即使页面滚动父元素被淹没,仍然是距离定位父元素的距离,通常是距离body元素的距离)
client 经常用于获取元素大小clientWidth clientHeight
scroll经常用于获取滚动距离scrollTop scrolleft
注意页面滚动的距离通过window. pageXOffset获得
3.4 mouseenter 和mouseover的区别
当鼠标移动到元素上时就会触发mouseenter事件类似mouseover ,它们两者之间的差别是
mouseover
鼠标经过自身盒子会触发,经过子盒子还会触发mouseenter
只会经过自身盒子触发。之所以这样,就是因为mouseenter不会冒泡
跟mouseenter搭配鼠标离开mouseleave同样不会冒泡
◆4-动画函数封装
4.1动画实现原理
核心原理:通过定时器setInterval()不断移动盒子位置。实现步骤:
1.获得盒子当前位置
2.让盒子在当前位置加上1个移动距离
3.利用定时器不断重复这个操作
4.加一个结束定时器的条件
5.注意此元素需要添加定位,才能使用element.style.left
4.2 动画函数简单封装
函数需要传递2个参数,动画对象和移动到的距离。
function animate(obj, target){}
4.3 动画函数给不同元素记录不同定时器
如果多个元素都使用这个动画函数,每次都要var声明定时器。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。
1 | //把定时器当做对象的一个属性 |
核心原理:利用JS是一门动态语言,可以很方便的给当前对象添加属性。
解决bug - 多计时器问题
比如我们通过一个按钮启动动画,但是每次点击按钮,就会触发一个计时器,这样动画就停不下来而且还会加速,形成bug,解决就是在每个动画函数的开头先清除所有的计时器。
1 | clearInterval(obj.timer); |
4.4 缓动效果原理
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来思路:
1.让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
2.核心算法:(目标值-现在的位置) / 10
做为每次移动的距离步长
3.停止的条件是:让当前盒子位置等于目标位置就停止定时器
4.步长值需要进行取整。由于刚才的步长公式结果可能是小数,就造成了不精确问题。
4.5 动画函数多个目标值之间移动
可以让动画函数从800移动到500。
当我们点击按钮时候,判断步长是正值还是负值
1.如果是正值,则步长往大了取整
2.如果是负值,则步长向小了取整
1 | var step = (target - obj.offsetLeft) / 10; |
4.6 缓动动画添加回调函数
回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面 ,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。
回调函数写的位置:定时器结束的位置。
1 | function anomate(obj, target, callback){ |
4.7 动画函数封装到单独JS文件里面
因为以后经常使用这个动画函数,可以单独封装到一个Js文件里面,使用的时候引用这个js文件即可。
- 单独新建一个Js文件。
2.在html页面中需要引入这个动画js,引入的位置可以是任意位置。
1 | <script src="js/animate.js"></script> |
◆5-常见网页特效案例
网页轮播图
轮播图也称为焦点图,是网页中比较常见的网页特效。
功能需求:
1.鼠标经过轮播图模块 ,左右按钮显示,离开隐藏左右按钮。
2.点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。
3.图片播放的同时,下面小圆圈模块跟随一起变化。
4.点击小圆圈,可以播放相应图片。
5.鼠标不经过轮播图 ,轮播图也会自动播放图片。
6.鼠标经过 ,轮播图模块, 自动播放停止。
1)动态生成小圆圈
核心思路:小圆圈的个数要跟图片张数一致
所以首先先得到ul里面图片的张数 (图片放入li里面,所以就是Ii的个数)
利用循环动态生成小圆圈(这个小圆圈要放入ol里面)
创建节点createElement(1i’)
插入节点ol. appendChild(li)
第一个小圆圈需要添加current类
2)小圆圈的排他思想
点击当前小圆圈,就添加current类
其余的小圆圈就移除这个current类
注意:我们在刚才生成小圆圈的同时,就可以直接绑定这个点击事件了。
3)点击小圆圈滚动图片
此时用到animate动画函数,将js文件引入(注意,因为index.js 依赖animate.js所以,animate.js 要写到index.js上面)
使用动画函数的前提,该元素必须有定位
注意是ul移动而不是小li
滚动图片的核心算法:点击某个小圆圈,就让图片滚动小圆圈的 索引号 * 图片的宽度 做为ul移动距离
此时需要知道小圆圈的索引号,我们可以在生成小圆圈的时候,给它设置-个自定义属性,点击的时候获取这个自定义属性即可。
思考 - 动画

1 | animate(ul, -index * focusWidth); |
开始我在想从左到右点击轮播图,第二个参数就会让ul元素左移,但是如果从右往左呢,怎么到回来呢?
后来发现animate俩面的target参数(第二个参数), 是ul这个元素距离他的定位父元素的距离,他的父元素是固定的,因此target参数是正负不断变化的,ul可以朝左可以朝右。
4)点击右侧按钮一次,就让图片滚动一张。
声明一个变量num,点击一次, 自增1,让这个变量乘以图片宽度, 就是ul的滚动距离。
图片无缝滚动原理
把ul第一个li复制一份,放到ul的最后面
当图片滚动到克隆的最后一张图片时,让ul快速的、 不做动画的跳到最左侧: left 为0;
number为0 ,重新开始滚动
复制一份li毕竟不够灵活,而且影响左下角小圆圈的生成,所以我么需要克隆第一张图片
- 克隆ul第一个li cloneNode()加true 深克隆,复制里面的子节点,false 浅克隆。
- 添加到ul最后面appendChild。
1 | var first = ul.children[0].cloneNode(true); |
5)点击右侧按钮,小圆圈跟随变化
②最简单的做法是再声明一个变量circle,每次点击自增1,注意,左侧按钮也需要这个变量,因此要 声明全局变量。
bug:比如轮播图处于第一页,小圆圈index是0,num也是0(小圆圈正确);然后点击第二个小圆圈,轮播图处于第二页,小圆圈的index是1,num是0(小圆圈正确);然后我们点击右侧按钮,num = 1 ,轮播图本应该是处于第三页,但是因为num是1,所以动画只移动了第一张图片。
首先需要明确的是:num 和 circle是同步的,也就是点击按钮,一定会触发小圆圈的变化。因此问题可以归结为num(circle) 和 index不同步。
因此我们小圆圈的点击事件中,index的改变需要告诉num值,我已经移动到第二张图片啦,下次点击左按钮,应该是第三张图片啦。
1 | num = circle = index; |
理解一下num和circle,以及index值
- index是随着小圆圈自身变化(圆圈的点击事件)的,范围是0-3
- num是用来控制轮播图ul相对focus父盒子相对移动的个数,范围也是0 — 4(克隆了一张图片)
- 临界值 0 意味着轮播图此时是第一张图片,此时点击左侧按钮需要跳转到第4张图片:
- 先迅速切换到第5张图片(num = 4)
- 缓慢移动到第4张图片(num=3)
- circle要切换成3
- 临界值 3 意味着轮播图此时是第4张图片,此时点击右侧按钮需要跳转到第1张图片:
- 先移动到第5张图片(num = 4)
- 迅速移动到第一张图片(num=0)
- circle切换为0
- 临界值 0 意味着轮播图此时是第一张图片,此时点击左侧按钮需要跳转到第4张图片:
- circle是用来控制左右按钮点击时同步小圆圈的变化,范围是0-3,这个变量可以和num合并为一个值。它和num同增同减。
6)自动播放功能
添加一个定时器
自动播放轮播图,实际就类似于点击了右侧按钮
此时我们使用手动调用右侧按钮点击事件
arrow_r.click()
,就会调用arrow_r元素的click事件。鼠标经过focus就停止定时器
鼠标离开focus 就开启定时器
节流阀
防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量var flag= true;
if(flag) {flag= false; do something}
关闭水龙头
利用回调函数动画执行完毕, flag=true打开水龙头
1 | var flag= true;//打开状态 |
案例
1- 缓动返回顶部
滚动窗口至文档中的特定位置。window.scroll(x, y)
注意里面的x和y不跟单位,直接写数字
带有动画的返回顶部
此时可以继续使用我们封装的动画函数 ,只需要把所有的left相关的值改为跟页面垂直滚动距离相关就可以了
页面滚动了多少,可以通过window.pageYOffset得到 ,最后是页面滚动,使用window.scroll(x,y)
内容见<<仿淘宝固定侧边栏.html>>
2- 筋头云案例
需求:
1)鼠标经过某个小li,筋斗云跟这到当前小i位置
2)鼠标离开这个小li ,筋斗云复原为原来的位置
3)鼠标点击了某个小li,筋斗云就会留在点击这个小li的位置
案例分析
利用动画函数做动画效果 ,原先筋斗云的起始位置是0 ,鼠标经过某个小li ,把当前小li的offsetLeft位置做为目标值即可 ,鼠标离开某个小li ,就把目标值设为0。
如果点击了某个小li ,就把li当前的位置存储起来,做为筋斗云的起始位置,需要一个变量current存储筋斗云需要返回的位置。