一、Offset
1.1 概述
offset ==> 偏移量 ,可以动态的获取的元素的位置、大小等属性。
- 获得元素距离带有定位父元素的位置
- 获得元素自身的大小(宽度高度) 返回的数值都不带单位
offset常用属性:
属性 | 作用 |
element.offsetParent |
返回作为该元素带有定位的父级元素如果父级都没有定位则返回body |
element.offsetTop |
返回元素相对带有定位父元素上方的偏移 |
element.offsetLeft |
返回元素相对带有定位父元素左边框的偏移 |
element.offsetWidth |
返回自身包括padding 、边框、内容区的宽度,返回数值不带单位 |
element.offsetHeight |
返回自身包括padding、边框、内容区的高度,返回数值不带单位 |
注意:
offsetLeft
如果没有父亲或者父亲没有定位,则以body
为准
在案例一演示
1.2 offset 和 style 的区别
1、offset
① offset 可以得到任意样式表中的样式值
② offset 系列获得的数值是没有单位的
③ offsetWidth、offsetHeight包含padding+border+width
④ offsetWidth、offsetHeight等属性是只读属性,只能获取不能赋值
所以,我们想要获取元素大小位置,用offset更合适。
2、style
① style 只能得到行内样式表中的样式值
② style.width 获得的是带有单位的字符串
③ style.width、style.height获得的是不包含padding和border 的值
④ style.width、style.height是可读写属性,可以获取也可以赋值
所以,我们想要给元素更改值,则需要用style改变。
offset案例
案例一
获取鼠标在盒子内的坐标
我们在盒子内点击, 想要得到鼠标距离盒子左右的距离。
首先得到鼠标在页面中的坐标( e.pageX, e.pageY)
其次得到盒子在页面中的距离(box.offsetLeft, box.offsetTop)
用鼠标距离页面的坐标减去盒子在页面中的距离, 得到鼠标在盒子内的坐标
<head> <meta charset="UTF-8"> <title>盒子坐标</title> <style> .box { width: 300px; height: 300px; background-color: pink; margin: 200px; } </style> </head> <body> <div class="box"></div> <script> var box = document.querySelector('.box'); box.addEventListener('mousemove', function(e) { // offsetLeft、offsetTop 盒子与边框的距离 var x = e.pageX - this.offsetLeft; var y = e.pageY - this.offsetTop; this.innerHTML = '鼠标坐标是(' + x + ',' + y + ')'; }) </script> </body>
案例二
拖动的模块框
- 点击弹出,则显示登录框
display:block
- 点击关闭,则关闭登录框
display:none
- 拖动原理:鼠标按下并且移动,松开鼠标
- 使用到鼠标事件:
mousedown
:鼠标按下、mousemove
:鼠标移动 、mouseup
:鼠标松开
<head lang="en"> <meta charset="UTF-8"> <title></title> <style> .login-header { width: 100%; text-align: center; height: 30px; font-size: 24px; line-height: 30px; } * { padding: 0px; margin: 0px; } .login { display: none; width: 512px; height: 280px; position: fixed; border: #ebebeb solid 1px; left: 50%; top: 50%; background: #ffffff; box-shadow: 0px 0px 20px #ddd; z-index: 9999; transform: translate(-50%, -50%); } .login-title { width: 100%; margin: 10px 0px 0px 0px; text-align: center; line-height: 40px; height: 40px; font-size: 18px; position: relative; cursor: move; } .login-input-content { margin-top: 20px; } .login-button { width: 50%; margin: 30px auto 0px auto; line-height: 40px; font-size: 14px; border: #ebebeb 1px solid; text-align: center; } .login-bg { display: none; width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; background: rgba(0, 0, 0, .3); } a { text-decoration: none; color: #000000; } .login-button a { display: block; } .login-input input.list-input { float: left; line-height: 35px; height: 35px; width: 350px; border: #ebebeb 1px solid; text-indent: 5px; } .login-input { overflow: hidden; margin: 0px 0px 20px 0px; } .login-input label { float: left; width: 90px; padding-right: 10px; text-align: right; line-height: 35px; height: 35px; font-size: 14px; } .login-title span { position: absolute; font-size: 12px; right: -20px; top: -30px; background: #ffffff; border: #ebebeb solid 1px; width: 40px; height: 40px; border-radius: 20px; } </style> </head> <body> <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div> <div id="login" class="login"> <div id="title" class="login-title">登录会员 <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span> </div> <div class="login-input-content"> <div class="login-input"> <label>用户名:</label> <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input"> </div> <div class="login-input"> <label>登录密码:</label> <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input"> </div> </div> <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div> </div> <!-- 遮盖层 --> <div id="bg" class="login-bg"></div> <script> // 1. 获取元素 var login = document.querySelector('.login'); var mask = document.querySelector('.login-bg'); var link = document.querySelector('#link'); var closeBtn = document.querySelector('#closeBtn'); var title = document.querySelector('#title'); // 2. 点击弹出层这个链接 link link.addEventListener('click', function () { mask.style.display = 'block'; login.style.display = 'block'; }) // 3. 点击 closeBtn 就隐藏 mask 和 login closeBtn.addEventListener('click', function () { mask.style.display = 'none'; login.style.display = 'none'; }) // 4. 开始拖拽,限制拖动的范围 title.addEventListener('mousedown', function (e) { // (1)当鼠标按下,获得鼠标在盒子内的坐标 var x = e.pageX - login.offsetLeft; var y = e.pageY - login.offsetTop; //(2)鼠标移动 document.addEventListener('mousemove', move) // (3) 鼠标弹起,鼠标移除事件 document.addEventListener('mouseup', function () { document.removeEventListener('mousemove', move); }) // 移动鼠标事件处理:鼠标移动的时候,把鼠标在页面中的坐标,减去鼠标在盒子内的坐标就是模态框的left和top值 function move(e) { login.style.left = e.pageX - x + 'px'; login.style.top = e.pageY - y + 'px'; } }) </script> </body>
mouseenter 与 mouseover 区别
mouseenter
事件
- 只会经过自身盒子触发,通常与
mouselevel
搭配使用,不会存在冒泡行为
mouseover
事件
- 鼠标经过自身盒子就会触发,经过子盒子还会触发
二、Client
1.1 client 介绍
client 字面意思就是客户端,client的相关属性可以动态获取到元素的边框大小、元素大小等。
client的属性
client相关属性 | 作用 |
element.clientTop |
返回元素上边框的大小 |
element.clientLeft |
返回元素左边框的大小 |
element.clientWidth |
返回自身包括padding、内容区的宽度、不含边框,返回数值不带单位 |
element.clientHeight |
返回自身包括padding、内容区的高度、不含边框,返回数值不带单位 |
client 的宽度和 offsetWidth 最大的区别就是 不包含边框
立即执行函数
立即执行函数最大的作用就是独立创建了一个作用域, 里面所有的变量都是局部变量不会有命名冲突的情况
<body> <script> // 1.立即执行函数: 不需要调用,立马能够自己执行的函数 function fn() { console.log(1); } fn(); // 2. 写法也可以传递参数进来 // 1.(function() {})(); (function(a, b) { console.log(a + b); var num = 10; })(1, 2); // 第二个小括号可以看做是调用函数 // 2. (function(){}()); (function sum(a, b) { console.log(a + b); var num = 10; // 局部变量 }(2, 3)); </script> </body>
flexible分许
/** * 立即执行函数 */ (function flexible(window, document) { // 获取的html 的根元素 var docEl = document.documentElement // dpr 物理像素比,若是浏览器没有物理像素比,则为1 var dpr = window.devicePixelRatio || 1 // adjust body font size 设置body的字体大小 function setBodyFontSize() { // 如果页面中有body这个元素就设置body的字体大小 if (document.body) { document.body.style.fontSize = (12 * dpr) + 'px' } else { // 如果页面中没有body这个元素,则等着页面主要的DOM元素加载完毕再去设置body的字体大小 document.addEventListener('DOMContentLoaded', setBodyFontSize) } } setBodyFontSize(); // set 1rem = viewWidth / 10 设置html元素的文字大小 function setRemUnit() { var rem = docEl.clientWidth / 10 docEl.style.fontSize = rem + 'px' } setRemUnit(); // reset rem unit on page resize 当页面尺寸大小发生变化的时候,要重新设置下rem的大小 window.addEventListener('resize', setRemUnit) // pageshow 是重新加载页面触发的事件,load是每次进入都会触发,具有缓存则不触发 window.addEventListener('pageshow', function (e) { // e.persisted 返回的是true 就是说如果这个页面是从缓存取过来的页面,也需要从新计算一下rem的大小 if (e.persisted) { setRemUnit() } }); // detect 0.5px supports 有些移动端的浏览器不支持0.5像素的写法 if (dpr >= 2) { var fakeBody = document.createElement('body') var testElement = document.createElement('div') testElement.style.border = '.5px solid transparent' fakeBody.appendChild(testElement) docEl.appendChild(fakeBody) if (testElement.offsetHeight === 1) { docEl.classList.add('hairlines') } docEl.removeChild(fakeBody) } }(window, document))
三、scroll
使用scroll系列相关属性可以动态获取该元素的大小、滚动距离等。
scroll系列属性 | 作用 |
element.scrollTop |
返回被滚动上去的上侧距离,不带单位 |
element.scrollLeft |
返回被滚动到左侧的距离,不带单位 |
element.scrollWidth |
返回自身实际的宽度,不含边框,不带单位 |
element.scrollHeight |
返回自身实际的高度,不含边框,不带单位 |
// scroll滚动事件当我们滚动条发生变化会触发的事件 div.addEventListener('scroll', function() { console.log(div.scrollTop); })
scrollWidth
和scrollHeight
指的返回自身实际宽和高的意思是,如果box盒子的宽和高都是200px,但是里面的内容已经超过了box盒子,溢出来了,那么scrollWidth
和scrollHeight
的返回自身的宽和高就是实际内容的宽和高。
<!-- box盒子的宽和高都是200px --> <div class="box"></div> <script> var box = document.querySelector(".box"); console.log(box.scrollHeight); // 200 console.log(box.scrollWidth); // 200 </script>
pageYOffset
可以获取页面被滚动上去的部分,pageXOffset
可以获取被滚动到左侧的部分。
<div class="box"></div> <script> var box = document.querySelector(".box"); // scroll滚动事件在滚动条发生变化时会被触发 box.addEventListener("scroll",function(){ console.log(box.scrollTop); }) </script>
案例
固定左侧侧边栏
- 原先侧边栏为绝对定位
- 页面滚动到一定的位置时,改变成固定定位
- 继续滚动页面,显示出回到顶部
<head> <meta charset="UTF-8"> <title>固定侧边栏</title> <style> .slider-bar { position: absolute; left: 50%; top: 300px; margin-left: 600px; width: 45px; height: 50px; background-color: gray; } .w { width: 1200px; margin: 10px auto; } .header { text-align: center; height: 150px; background-color: purple; } .banner { text-align: center; height: 250px; background-color: skyblue; } .main { text-align: center; height: 1000px; background-color: yellowgreen; } span { display: none; position: absolute; bottom: 0; } </style> </head> <body> <div class="slider-bar"> <span class="goBack">返回顶部</span> </div> <div class="header w">头部区域</div> <div class="banner w">banner区域</div> <div class="main w">主体部分</div> <script> // 获取元素 var sliderBar = document.querySelector('.slider-bar'); var banner = document.querySelector('.banner'); var main = document.querySelector('.main'); var goBack = document.querySelector('.goBack'); // 获取到banner的顶部值 var bannerTop = banner.offsetTop; // 侧边栏固定定位变化的数值 var sliderbarTop = sliderBar.offsetTop - bannerTop; // 获取到mainTop距离 var mainTop = main.offsetTop; // 页面滚动滚动事件 scroll document.addEventListener('scroll', function () { // 当页面向下滚动达到某个数值,则改成固定定位 if (window.pageYOffset >= bannerTop) { sliderBar.style.position = 'fixed'; sliderBar.style.top = sliderbarTop + 'px'; } else { sliderBar.style.position = 'absolute'; sliderBar.style.top = '300px'; } // 滚动到main位置显示出文本内容 if (window.pageYOffset >= mainTop) { goBack.style.display = 'block'; } else { goBack.style.display = 'none'; } }); </script> </body>
三大系列总结
主要应用场景:
offset系列 通常应用于获得元素的位置, offsetLeft 、offsetTop。
client系列 通常应用于获得元素的大小 ,clientWidth 、clientHeight。
scroll系列 通常应用于获取元素的滚动距离, scrollTop、 scrollLeft 。
页面的滚动距离通过 window.pageYOffset 和 window.pageXOffset 获得。
都有一个共同点,返回值都是数字且不带单位。
获取页面在Y轴上的滚动距离,可以通过window.pageYOffset、、document.documentElement.scrollTop、document.body.scrollTop 三种方式
四、动画特效
4.1 动画原理
- 获得盒子当前位置
- 让盒子在当前位置加上1个移动距离
- 利用定时器不断重复这个操作
- 加一个结束定时器的条件
- 注意该元素需要添加定位,才能使用element.style.left
<head> <meta charset="UTF-8"> <title>动画原理</title> <style> div { /*设置定位*/ position: absolute; left: 0; width: 100px; height: 100px; background-color: pink; } </style> </head> <body> <div></div> <script> // 获取元素 var d = document.querySelector('div'); // 设置定时器 var timer = setInterval(function () { // 设置结束条件 if (d.offsetLeft >= 500){ // 清除定时器 clearInterval(timer); } // 移动后位置 d.style.left = d.offsetLeft + 2 + 'px'; }, 50) </script> </body>
效果如下:
4.2 封装动画对象
- 封装动画函数对象,可以使不同的对象进行相同的操作,方便调用达到相同的效果
- 不同的对象添加不同的定时器,就不会出现迭代动画效果,比如下面的按钮事件,多次点击它不会出现移动的速度越来越快的效果
<head> <meta charset="UTF-8"> <style> div { position: absolute; left: 0; width: 100px; height: 100px; background-color: pink; } span { position: absolute; left: 0; top: 150px; display: block; width: 150px; height: 150px; background-color: purple; } </style> </head> <body> <button>点击夏雨荷才走</button> <div></div> <span>夏雨荷</span> <script> // 获取对象 var buttonElement = document.querySelector('button'); var divElement = document.querySelector('div'); var spanElement = document.querySelector('span'); // 封装定时器 function animate(obj, stopPosition) { // 将上一次的定时器清除掉,就不会出现迭代效果,点击按钮就不会,越点击,移动速度越快的效果 clearInterval(obj.timer); // 定时器 obj.timer = setInterval(function () { // 元素停止限制 if (obj.offsetLeft >= stopPosition) { // 清除定时器 clearInterval(obj.timer); } else { // 不断移动,距离左侧越来越远 obj.style.left = obj.offsetLeft + 1 + 'px'; } }, 40) } // 不同的对象调用同一个函数 animate(divElement,100); // span点了按钮才会开始动 buttonElement.addEventListener('click',function (){ animate(spanElement,150); }); </script> </body>
实现的效果如下所示:
4.3 缓冲动画
4.3.1 缓冲动画原理
元素运动的速度有所变化,停止的移动的距离慢慢减小
具体思路如下
盒子每次移动的距离越来越小,相当于速度越来越小
每次移动距离的步长:使用缓冲动画公式==(目标值 - 当前的位置)/ 10==
停止条件:当前盒子的位置等于目标位置,定时器停止
之前的是匀速动画,现在是缓冲动画,两者之间的区别:
匀速动画就是盒子是当前的位置 + 固定的值 10
缓动动画就是盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)一个目标元素来回移动:
<body> <button class="btn500">点击夏雨荷到500</button> <button class="btn800">点击夏雨荷到800</button> <span>夏雨荷</span> <script> function animate(obj, target) { // 先清除以前的定时器,只保留当前的一个定时器执行 clearInterval(obj.timer); obj.timer = setInterval(function () { // 把我们步长值改为整数 不要出现小数的问题 步长公式:(目标值 - 现在的位置) / 10 var step = (target - obj.offsetLeft) / 10; // ceil 向上取整,floor向下取整 step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); } obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } var span = document.querySelector('span'); var btn500 = document.querySelector('.btn500'); var btn800 = document.querySelector('.btn800'); btn500.addEventListener('click', function () { animate(span, 500); }) btn800.addEventListener('click', function () { animate(span, 800); }) </script> </body>
4.3.2 缓冲动画的回调函数
回调函数:
<head> <meta charset="UTF-8"> <title>Document</title> <style> span { position: absolute; left: 0; top: 40px; display: block; text-align: center; width: 150px; height: 150px; background-color: #b2dba1; } </style> </head> <body> <button class="start">起点位置</button> <button class="mid">中点位置</button> <button class="end">终点位置</button> <span>开始位置</span> <script> // callback 为形参,作为回调函数 function animate(obj, target, callback) { clearInterval(obj.timer); obj.timer = setInterval(function () { var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); // 回调函数写到定时器结束里面 if (callback) { // 调用函数 callback(); } } obj.style.left = obj.offsetLeft + step + 'px'; }, 15); } // 获取元素 var span = document.querySelector('span'); var start = document.querySelector('.start'); var mid = document.querySelector('.mid'); var end = document.querySelector('.end'); //回到起始位置 start.addEventListener('click', function () { animate(span, 0, function () { span.style.backgroundColor = 'grey'; span.innerHTML = '起点位置'; }) }) // 移动到中间 mid.addEventListener('click', function () { animate(span, 500, function () { span.style.backgroundColor = 'blue'; span.innerHTML = '中点位置'; }); }) // 移动到末端 end.addEventListener('click', function () { animate(span, 800, function () { span.style.backgroundColor = 'red'; span.innerHTML = '终点位置'; }); }) </script> </body>
动画函数的使用
将函数单独写道一个 JS 文件当中,在需要的的 html 中引用进来
用一个列子说明:
鼠标经过 / 离开侧边栏时的弹出,隐藏的效果
animate.js
function animate(obj, target, callback) { clearInterval(obj.timer); obj.timer = setInterval(function () { var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); callback && callback(); } obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }
html
设置
<head> <meta charset="UTF-8"> <title>Document</title> <style> .sliderbar { position: fixed; right: 0; bottom: 100px; width: 32px; height: 32px; text-align: center; line-height: 32px; cursor: pointer; color: blue; } .con { position: absolute; left: 0; top: 0; width: 200px; height: 32px; background-color: gray; z-index: -1; } </style> <script src="animate.js"></script> </head> <body> <div class="sliderbar"> <span><img src="../../Images/questionback.png"></span> <div class="con">问题反馈</div> </div> <script> // 1. 获取元素 var sliderbar = document.querySelector('.sliderbar'); var con = document.querySelector('.con'); // 当鼠标经过 sliderbar 就会让 con这个盒子滑动到左侧 sliderbar.addEventListener('mouseenter', function () { animate(con, -160, function () { // 当动画执行完毕,显示回图片 sliderbar.children[0].innerHTML = '<img src="../../Images/outquestion.png">'; }); }) // 当鼠标离开 sliderbar 就会让 con这个盒子滑动到右侧 sliderbar.addEventListener('mouseleave', function () { animate(con, 0, function () { sliderbar.children[0].innerHTML = '<img src="../../Images/questionback.png">'; }); }) </script> </body>
五、网页特效案例
5.1 轮播图功能需求
- 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
- 点击右侧按钮一次,图片往左播放一张,以此类推, 左侧按钮同理。
- 图片播放的同时,下面小圆圈模块跟随一起变化。
- 点击小圆圈,可以播放相应图片。
- 鼠标不经过轮播图, 轮播图也会自动播放图片。
- 鼠标经过,轮播图模块, 自动播放停止。
5.2 轮播图实现过程
给定一个大盒子,为了方便后面盒子的定位操作,再给它一个相对定位,把图片通过无序列表的形式添加进大盒子中,
因为我们要实现的轮播图效果是横向的,所以我们可以给图片添加float:left属性,
又因为图片所在的ul不够大,所以其他的图片会被挤到下面,所以我们可以手动修改图片所在的ul的大小,
接下来写一个无序列表用于放置小圆圈,通过绝对定位的方式将其定位到大盒子的下面,在将小圆圈加进去,方便我们实现点击对应的小圆圈,就跳转到相应图片的效果。
然后将左右箭头通过绝对定位分别定到大盒子两侧合适位置。最后,我们再将大盒子外面的内容隐藏掉。
5.3 轮播图代码实现
5.3.1 创建HTML代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>轮播图</title> <!--引入js,css--> <link rel="stylesheet" href="css/lunbotu.css"> <script src="js/lunbotu.js"></script> <script src="js/animate.js"></script> </head> <body> <div class="main"> <div class="focus"> <!-- 左侧按钮 --> <a href="javascript:;" class="prev"><</a> <!-- 右侧按钮 --> <a href="javascript:;" class="next">></a> <!-- 核心滚动区 --> <ul> <li> <a href="javascript:;"><img src="Images/1.jpeg" alt=""></a> </li> <li> <a href="javascript:;"><img src="Images/3.jpeg" alt=""></a> </li> <li> <a href="javascript:;"><img src="Images/5.jpeg" alt=""></a> </li> <li> <a href="javascript:;"><img src="Images/37.jpeg" alt=""></a> </li> <li> <a href="javascript:;"><img src="Images/38.jpeg" alt=""></a> </li> <li> <a href="javascript:;"><img src="Images/39.jpeg" alt=""> </a> </li> </ul> <!-- 小圆点 --> <ol class="circle"> </ol> </div> </div> </body> </html>
5.3.2 编写CSS代码
css在开发过程中尽量不要写在html文件中
lunbotu.css
* { margin: 0; padding: 0; } li { list-style: none; } img { width: 1920px; height: 1020px; border: 0; vertical-align: middle; } .main { width: 1920px; height: 1020px; } .focus { position: relative; width: 1920px; height: 1020px; background-color: pink; /*隐藏其他的图片*/ overflow: hidden; } .prev, .next { /*隐藏按钮*/ display: none; position: absolute; /* 绝对定位的盒子垂直居中 */ top: 50%; margin-top: -10px; /* 加了绝对定位的盒子可以直接设置高度和宽度 */ width: 50px; height: 60px; background-color: rgb(0, 0, 0, .3); text-align: center; line-height: 60px; color: #fff; font-size: 50px; text-decoration: none; } .prev { left: 0; border-top-right-radius: 15px; border-bottom-right-radius: 15px; z-index: 2; } .next { /* 如果一个盒子既有left属性又有right属性,则默认会执行left属性 同理 top bottom 会执行top */ right: 0; /* 绝对定位的盒子垂直居中 */ border-top-left-radius: 15px; border-bottom-left-radius: 15px; z-index: 2; } .focus ul { position: absolute; top: 0; left: 0; width: 700%; } .focus ul li { float: left } .circle { position: absolute; bottom: 120px; left: 960px; } .circle li { float: left; width: 18px; height: 18px; /*background-color: #fff;*/ border: 5px solid rgba(255, 255, 255, 0.5); margin: 0 5px; border-radius: 50%; /*鼠标经过显示小手*/ cursor: pointer; } .current { background-color: deepskyblue; }
5.3.3 动画封装
function animate(obj, target, callback) { clearInterval(obj.timer); obj.timer = setInterval(function () { var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); callback && callback();// 如果为真,就执行callback(),否则不执行 } obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }
5.3.4 编写JS代码
- 当鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
- 点击右侧按钮一次,图片往左播放一张,以此类推, 左侧按钮同理。
- 图片播放的同时,下面小圆圈模块跟随一起变化。
- 点击小圆圈,可以播放相应图片。
- 鼠标不经过轮播图, 轮播图也会自动播放图片。
- 鼠标经过,轮播图模块, 自动播放停止。
window.addEventListener('load', function () { // 1. 获取元素 // 左侧按钮 var prev = document.querySelector('.prev'); // 右侧按钮 var next = document.querySelector('.next'); // 轮播图 var focus = document.querySelector('.focus'); // 获取图片的宽度 var focusWidth = focus.offsetWidth; // 2. 鼠标经过focus就显示左右按钮 focus.addEventListener('mouseenter', function () { prev.style.display = 'block'; next.style.display = 'block'; clearInterval(timer); // 清除定时器变量 timer = null; }) // 鼠标离开则隐藏按钮 focus.addEventListener('mouseleave', function () { prev.style.display = 'none'; next.style.display = 'none'; timer = setInterval(function () { // 手动调用右侧按钮点击事件 next.click(); }, 2000) }) // 3.动态生成小圆圈:根据图片的数量创建对应个数的小圆圈 var ul = focus.querySelector('ul');// 根据ul里面的图片的数量 var ol = focus.querySelector('.circle'); // 创建对应个数的ol的li for (var i = 0; i < ul.children.length; i++) { // 创建一个小 li var li = document.createElement('li'); // 记录当前小圆圈的索引号 通过自定义属性来做 li.setAttribute('index', i); // 把li 追加到 ol 里面 ol.appendChild(li); // 4. 小圆圈的排他思想 可以直接在生成小圆圈的同时直接绑定点击事件 li.addEventListener('click', function () { // 把所有的小 li 清除 current 类名 for (var i = 0; i < ol.children.length; i++) { ol.children[i].className = ''; } // 当前的小 li 设置 current 类名 this.className = 'current'; // 5. 点击小圆圈,移动图片,当然移动的是 ul // ul 的移动距离 = 小圆圈的索引号 乘以 图片的宽度 注意是负值。 当点击了某个小 li 就拿到当前小 li 的索引号 var index = this.getAttribute('index'); // 当点击了某个小 li 就要把这个 li 的索引号给 num 和 circle num = circle = index; // console.log(focusWidth); animate(ul, -index * focusWidth); }) } // 把 ol 里面的第一个小 li 设置类名为 current ol.children[0].className = 'current'; // 6. 克隆第一张图片(li)放到最后面 var first = ul.children[0].cloneNode(true); ul.appendChild(first); // 7. 点击右侧按钮,图片滚动一张 var num = 0; // 声明一个变量 circle 控制小圆圈的播放 var circle = 0; // flag 节流阀 var flag = true; next.addEventListener('click', function () { // 如果走到了最后复制的一张图片,此时 ul 要快速复原 left 改为 0 if (flag) { flag = false;//关闭节流阀 if (num == ul.children.length - 1) { ul.style.left = 0 + 'px'; num = 0; } num++; animate(ul, -num * focusWidth, function () { flag = true;//打开节流阀 }); // 8. 点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放 circle++; // circle走到最后克隆的这张图片 我们就复原为0 if (circle == ol.children.length) { circle = 0; } //调用函数 circleChange(); } }) // 9. 左侧按钮做法 prev.addEventListener('click', function () { if (flag) { if (num == 0) { num = ul.children.length - 1; ul.style.left = -num * focusWidth + 'px'; } num--; animate(ul, -num * focusWidth, function () { flag = true; }); circle--; // 如果circle < 0 说明第一张图片 则小圆圈要改为第6个小圆圈 if (circle < 0) { circle = ol.children.length - 1; } circleChange(); } }) // 优化代码,封装函数 function circleChange() { for (var i = 0; i < ol.children.length; i++) { ol.children[i].className = ''; } // 留下当前的小圆圈的current类名 ol.children[circle].className = 'current'; } // 10. 自动播放轮播图 var timer = setInterval(function () { // 手动调用右侧按钮点击事件 next.click(); }, 2000) })
5.4 筋斗云特效
HTML编写
<body> <div id="c_nav" class="c-nav"> <span class="cloud"></span> <ul> <li class="current"><a href="#">首页新闻</a></li> <li><a href="#">八卦新闻</a></li> <li><a href="#">娱乐新闻</a></li> <li><a href="#">军事新闻</a></li> <li><a href="#">校园新闻</a></li> <li><a href="#">企业新闻</a></li> <li><a href="#">腾讯新闻</a></li> <li><a href="#">新浪新闻</a></li> </ul> </div> </body>
移动效果:
animate.js
function animate(obj, target, callback) { clearInterval(obj.timer); obj.timer = setInterval(function() { var step = (target - obj.offsetLeft) / 10; step = step > 0 ? Math.ceil(step) : Math.floor(step); if (obj.offsetLeft == target) { // 停止动画 本质是停止定时器 clearInterval(obj.timer); callback && callback(); } // 把每次加1 这个步长值改为一个慢慢变小的值 步长公式:(目标值 - 现在的位置) / 10 obj.style.left = obj.offsetLeft + step + 'px'; }, 15); }
css实现
* { margin: 0; padding: 0 } ul { list-style: none; } body { background-color: black; } .c-nav { width: 900px; height: 42px; background: #fff url(images/rss.png) no-repeat right center; margin: 100px auto; border-radius: 5px; position: relative; } .c-nav ul { position: absolute; } .c-nav li { float: left; width: 83px; text-align: center; line-height: 42px; } .c-nav li a { color: #333; text-decoration: none; display: inline-block; height: 42px; } .c-nav li a:hover { color: white; } .c-nav li.current a { color: #0dff1d; } .cloud { position: absolute; left: 0; top: 0; width: 83px; height: 42px; background: url(images/cloud.gif) no-repeat; }
主JS实现
window.addEventListener('load', function () { // 1. 获取元素 var cloud = document.querySelector('.cloud'); var c_nav = document.querySelector('.c-nav'); var lis = c_nav.querySelectorAll('li'); // 2. 给所有的小li绑定事件 // 这个current 做为筋斗云的起始位置 var current = 0; for (var i = 0; i < lis.length; i++) { // (1) 鼠标经过把当前小li 的位置做为目标值 lis[i].addEventListener('mouseenter', function () { animate(cloud, this.offsetLeft); }); // (2) 鼠标离开就回到起始的位置 lis[i].addEventListener('mouseleave', function () { animate(cloud, current); }); // (3) 当我们鼠标点击,就把当前位置做为目标值 lis[i].addEventListener('click', function () { current = this.offsetLeft; }); } })
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SPDcYKOQ-1671521678469)(https://xingqiu-tuchuang-1256524210.cos.ap-shanghai.myqcloud.com/2767/%E7%AD%8B%E6%96%97%E4%BA%91.gif)]