JavaScript——PC端网页特效

本文详细介绍了JavaScript中关于元素偏移量offset、元素可视区client、元素滚动scroll的系列知识,包括各种属性和实战案例,如鼠标坐标、模态框拖动、京东放大镜效果。同时,深入探讨了动画函数的封装,包括实现原理、缓动效果,并提供了多个实用网页特效案例,如轮播图、返回顶部和筋斗云移动。

目录

一、元素偏移量offset系列

1. offset概述

2. 常见属性

3. offset与style区别

案例——鼠标在盒子内坐标

案例——拖动模态框

案例——京东放大镜

二、元素可视区client系列

flexible源码分析

立即执行函数

pageshow事件

三、元素滚动scroll系列

1. 页面被卷去头部

 案例——仿淘宝固定右侧侧边栏

 2. 页面被卷曲头部兼容性方案

四、三大系列总结

五、mouseenter和mouseover事件

六、动画函数封装

1. 动画实现原理

2. 动画函数的简单封装

3. 动画函数给不同元素记录不同定时器

4. 缓动效果动画

5. 动画函数在多个目标之间移动

6. 给动画函数添加回调参数

7. 动画函数封装到单独JS文件里面

案例——右侧盒子滑动

七、常见网页特效案例

案例——网页轮播图

1. 节流阀

短路运算简写callback函数

案例——返回顶部

案例——筋斗云移动


  

一、元素偏移量offset系列

1. offset概述

offset翻译过来就是偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。

  • 获取元素距离带有定位父元素的位置
  • 获得元素自身大小
  • 注意:返回的值都不带单位

2. 常见属性

	<!-- offset位置 -->
	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}

		.father {
			position: relative;
			width: 200px;
			height: 200px;
			background-color: pink;
			margin: 150px;
		}

		.son {
			width: 50px;
			height: 50px;
			background-color: blue;
			margin: 50px;
			padding: 10px;
			border: 2px solid red;
		}
	</style>
	<body>
		<div class="father">
			<div class="son">

			</div>
		</div>
		<script type="text/javascript">
			var father = document.querySelector('.father');
			var son = document.querySelector('.son');

			console.log(father.offsetTop);
			console.log(father.offsetLeft);
			//1.它是以有定位的父亲为准,若无父亲或无定位的父亲 以body为准
			console.log(son.offsetLeft);
			//2.可以得到元素的大小,宽高  包含padding+border+width
			console.log(son.offsetHeight);
			console.log(son.offsetWidth);
			//3. 返回带有定位的父亲,若无返回body
			console.log(son.offsetParent);
			console.log(son.parentNode);	//返回父亲 是最近一级的父亲 不管有没有定位
		</script>
	</body>

3. offset与style区别

案例——鼠标在盒子内坐标

    <!-- 鼠标在盒子内坐标 -->
	<style type="text/css">
		.box {
			width: 200px;
			height: 200px;
			background-color: pink;
			margin: 100px 100px;
		}
	</style>
	<body>
		<div class="box"></div>
		<script type="text/javascript">
			var box = document.querySelector('.box');
			box.addEventListener('mousemove', function(e) {
				// console.log(e.pageX);
				// console.log(e.pageY);
				var x = e.pageX - this.offsetLeft;
				var y = e.pageY - this.offsetTop;
				this.innerHTML = 'x坐标是' + x + 'y坐标是' + y;
			})
		</script>
	</body>

案例——拖动模态框

	<!-- 拖动模态框 -->
	<style type="text/css">
		.login-header {
			text-align: center;
		}

		a {
			margin: 0;
			padding: 0;
		}

		.login {
			display: none;
			width: 512px;
			height: 280px;
			position: fixed;
			border: 1px solid #EBEBEB;
			left: 50%;
			top: 50%;
			background-color: #FFFFFF;
			box-shadow: 0 0 20px #DDDDDD;
			z-index: 9999;
			transform: translate(-50%, -50%);
		}

		.login-title {
			width: 100%;
			margin: 10px 0 0 0;
			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 0 auto;
			line-height: 40px;
			font-size: 14px;
			border: 1px solid #EBEBEB;
			text-align: center;
		}

		.login-bg {
			display: none;
			width: 100%;
			height: 100%;
			position: fixed;
			top: 0px;
			left: 0px;
			background-color: 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: 1px solid #EBEBEB;
			text-indent: 5px;
		}

		.login-input {
			overflow: hidden;
			margin: 0 0 20px 0;
		}

		.login-input label {
			float: left;
			width: 90px;
			padding-right: 10px;
			text-align: center;
			line-height: 35px;
			height: 35px;
			font-size: 14px;
		}

		.login-title span {
			position: absolute;
			font-size: 12px;
			right: -20px;
			top: -30px;
			background-color: #FFFFFF;
			border: #EBEBEB solid 1px;
			width: 40px;
			height: 40px;
			border-radius: 20px;
		}
	</style>
	<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" name="info[username]" id="username" placeholder="请输入用户名" 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.addEventListener('click', function() {
				mask.style.display = 'block';
				login.style.display = 'block';
			})
			//3.点击关闭
			closeBtn.addEventListener('click', function() {
				mask.style.display = 'none';
				login.style.display = 'none';
			})
			//4.开始拖拽
			//(1)当鼠标按下,获得鼠标在盒子内坐标
			title.addEventListener('mousedown', function(e) {
				var x = e.pageX - login.offsetLeft;
				var y = e.pageY - login.offsetTop;
				//(2)鼠标移动式,把鼠标在页面中的坐标,减去鼠标在盒子内的坐标(不变的)
				function move(e) {
					login.style.left = e.pageX - x + 'px';
					login.style.top = e.pageY - y + 'px';
				}
				document.addEventListener('mousemove', move);
				//(3)鼠标弹起,就让鼠标移动事件移除
				document.addEventListener('mouseup', function() {
					document.removeEventListener('mousemove', move);
				})
			})
		</script>

案例——京东放大镜

	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}

		.preview_img {
			position: relative;
			border: 1px solid #CCCCCC;
			height: 400px;
			width: 400px;
		}

		.preview img {}

		.mask {
			display: none;
			position: absolute;
			top: 0;
			left: 0;
			height: 300px;
			width: 300px;
			background-color: #fede4f;
			border: 1px solid #CCCCCC;
			opacity: .5;
			cursor: move;
		}

		.big {
			display: none;
			position: absolute;
			top: 0;
			left: 410px;
			width: 500px;
			height: 500px;
			border: 1px solid #CCCCCC;
			overflow: hidden;
		}

		.big img {
			position: absolute;
			top: 0;
			left: 0;
		}
	</style>
	<body>
		<div class="preview_img">
			<img src="img/load.png" />
			<div class="mask">1</div>
			<div class="big">
				<img src="img/load-big.jpg" class="bigImg">
			</div>
		</div>
	</body>
	<script type="text/javascript">
		var preview_img = document.querySelector('.preview_img');
		var mask = document.querySelector('.mask');
		var big = document.querySelector('.big');
		//1.当鼠标经过preview_img 就显示隐藏mask遮挡层,和big大盒子
		preview_img.addEventListener('mouseover', function() {
			mask.style.display = 'block';
			big.style.display = 'block';
		})
		preview_img.addEventListener('mouseout', function() {
			mask.style.display = 'none';
			big.style.display = 'none';
		})
		//2.鼠标移动让黄色盒子跟着鼠标走
		preview_img.addEventListener('mousemove', function(e) {
			//(1)先计算出鼠标在盒子内的坐标
			var x = e.pageX - this.offsetLeft;
			var y = e.pageY - this.offsetTop;
			//(2)减去盒子高度的一般,保证鼠标在中间
			var maskX = x - mask.offsetWidth / 2;
			var maskY = y - mask.offsetHeight / 2;
			//(3)黄色盒子不能出小盒子范围。
			//(3).1 如果x坐标小于0就让停在0的位置,大于小盒子宽度减去遮挡层宽度
			//遮挡层最大移动距离(正方形,长宽一样)
			var maskMax = preview_img.offsetWidth - mask.offsetWidth;
			if (maskX < 0) {
				maskX = 0;
			} else if (maskX >= maskMax) {
				maskX = maskMax;
			}
			//(3).2 如果y坐标小于0就让停在0的位置,大于小盒子高度减去遮挡层高度
			if (maskY < 0) {
				maskY = 0;
			} else if (maskY >= maskMax) {
				maskY = maskMax;
			}

			mask.style.left = maskX + 'px';
			mask.style.top = maskY + 'px';

			//大图片移动距离=遮挡层移动距离*大图片最大移动距离 / 遮挡层最大移动距离
			var bigImg = document.querySelector('.bigImg');
			//大图最大移动距离
			var bigMax = bigImg.offsetWidth - big.offsetWidth;
			//大图片移动距离 bigX 和 bigY
			var bigX = maskX * bigMax / maskMax;
			var bigY = maskY * bigMax / maskMax;

			bigImg.style.left = -bigX + 'px';
			bigImg.style.top = -bigY + 'px';
		})
	</script>

二、元素可视区client系列

通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等。

flexible源码分析

(function flexible(window,document){
	// 获取html的根元素
	var docEl=document.documentElement;
	// dpr像素比
	var dpr=window.devicePixelRatio	|| 1;
	
	// 设置body的字体大小
	function setBodyFontSize(){
		// 如果页面有body元素,就设置body页面文字大小
		if(document.body){
			document.body.style.fontSize=(12*dpr)+'px';
		}else{
			// 如果页面中无body,则等页面主要DOM元素加载完毕再设置body字体大小
			document.addEventListener('DOMContentLoaded',setBodyFontSize);
		}
	}
	setBodyFontSize();
	
	//设置html元素文字大小
	function setRumUnit(){
		var rem=docEl.clientWidth/10;
		docEl.style.fontSize=rem+'px';
	}
	setRumUnit();
	
	// 当我们页面尺寸大小发生变化,要重新设置rem的大小
	window.addEventListener('resize',setRumUnit());
	//pageshow使我们重新加载页面触发的事件
	window.addEventListener('pageshow',function(e){
		// e.persisted返回true,就是说如果这个页面是从缓冲取过来的页面,也需要重新计算rem大小
		if(e.persisted){
			setRumUnit();
		}
	})
	
	// 有些移动端不支持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))

立即执行函数

  1. 立即函数不需要调用,立马自己执行
  2. 也可以传递参数
  3. 立即执行函数最大的作用是:独立创建了一个作用域,里面所有变量都是局部变量,不会有命名冲突情况
//创建方法
<script>
	(function(){})()
	(function(){}())
</script>
//也可以传递参数
<script>
	(function sum(a,b){
		console.log(a+b);
	})(1,2)    //第二个小括号可以看做调用函数,可以传递参数
</script>
//独立创建了一个作用域,里面所有变量都是局部变量,不会有命名冲突情况
<script>
	(function sum(a,b){
		var num=10;
	})();

	(function sum(a,b){
		var num=10;
	}())
</script>

pageshow事件

三、元素滚动scroll系列

使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等。

 

1. 页面被卷去头部

如果浏览器的高(或宽)度不足以显示整个页面时,会自动出现滚动条。当滚动条向下滚动时,页面上面被隐藏掉的高度,我们就称为页面被卷去的头部。滚动条在滚动时会触发onscroll事件

 案例——仿淘宝固定右侧侧边栏

  

    <style type="text/css">
		.slider-bar {
			position: absolute;
			left: 50%;
			top: 300px;
			margin-left: 600px;
			width: 45px;
			height: 130px;
			background-color: pink;
		}

		.w {
			width: 1200px;
			margin: 10px auto;
		}

		.header {
			height: 150px;
			background-color: lightgrey;
		}

		.banner {
			height: 400px;
			background-color: lightblue;
		}

		.main {
			height: 1000px;
			background-color: yellowgreen;
		}

		span {
			display: none;
			position: absolute;
			bottom: 0;
		}
	</style>
	<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>
	</body>
	<script type="text/javascript">
		var sliderbar = document.querySelector('.slider-bar');
		var banner = document.querySelector('.banner');
		
        //banner.offsetTop就是卷去的高度,要写在滚动外面
		var bannerTop = banner.offsetTop;
		//当我们侧边栏固定定位后应保持的top值
		var sliderbarTop=sliderbar.offsetTop-bannerTop;
		
        //获取主体元素
		var main=document.querySelector('.main');
		var goBack=document.querySelector('.goBack');
		var mainTop=main.offsetTop;
		
		//2.页面滚动事件
		document.addEventListener('scroll', function() {
			//3. 当我们页面卷去的头部大于 banner.offsetTop时, 侧边栏变成固定定位
			if (window.pageYOffset >= bannerTop) {
				sliderbar.style.position = "fixed";
				sliderbar.style.top=sliderbarTop+'px';
			} else {
				sliderbar.style.position = "absolute";
				sliderbar.style.top='300px';
			}
			
            //4.当页面滚动到main盒子,就显示goback模块
			if (window.pageYOffset >= mainTop) {
				goBack.style.display="block";
			} else {
				goBack.style.display="none";
			}
		})
	</script>

 2. 页面被卷曲头部兼容性方案

  

四、三大系列总结

 

 主要用法:

  1. offset 系列经常用于获取元素位置 offsetLeft offsetTop
  2. client 系列经常用于获取元素大小 clientWidth clientHeight
  3. scroll 经常用于获取滚动距离 scrollTop scrollLeft
  4. 注意页面的滚动距离通过  window.pageXoffset  获得

五、mouseenter和mouseover事件

  • 当鼠标移动到元素上会触发mouseenter和mouseover事件
  • 当mouseover鼠标经过自身盒子会触发,经过子盒子还会触发
  • mouseenter只会经过自身盒子才触发
  • 之所以这样,mouseenter不会冒泡
  • 跟mouseenter搭配 鼠标离开事件 mouseleave 同样不会冒泡

六、动画函数封装

1. 动画实现原理

核心原理:通过定时器setInterval()不断移动盒子位置

实现步骤:

  1. 获取当前盒子位置
  2. 让盒子在当前位置加上一个像素
  3. 利用定时器不断重复这个操作
  4. 加上结束定时器条件
  5. 注意!此元素要添加定位才行

常见网页特效案例

2. 动画函数的简单封装

注意需要传递2个参数,动画对象移动到的距离

//简单函数封装,obj目标对象,target目标位置
function animate(obj, target) {
	var timer = setInterval(function() {
		if (obj.offsetLeft >= target) {
			//停止动画,本质停止定时器
			clearInterval(timer);
		}
		obj.style.left = obj.offsetLeft + 1 + 'px';
	}, 30);
}

3. 动画函数给不同元素记录不同定时器

    <body>
		<button type="button">go</button>
		<div></div>
		<span></span>
		<script type="text/javascript">
			//简单函数封装,obj目标对象,target目标位置
			//当我们不断点击按钮,这个元素会越来越快,应为开启太多定时器
			function animate(obj, target) {
				obj.timer = setInterval(function() {
					if (obj.offsetLeft >= target) {
						//停止动画,本质停止定时器
						clearInterval(obj.timer);
					}
					obj.style.left = obj.offsetLeft + 2 + 'px';
				}, 30);
			}

			var div = document.querySelector('div');
			var span = document.querySelector('span');
			var btn = document.querySelector('button');
			animate(div, 300);
			btn.addEventListener('click', function() {
				animate(span, 200);
			})
		</script>
	</body>

以上优化有bug:当我们不断点击按钮,这个元素会越来越快,应为开启太多定时器

function animate(obj, target) {
	//先清楚以前定时器,只保留当前的定时器
	clearInterval(obj.timer);
	obj.timer = setInterval(function() {
		if (obj.offsetLeft >= target) {
			//停止动画,本质停止定时器
			clearInterval(obj.timer);
		}
		obj.style.left = obj.offsetLeft + 2 + 'px';
	}, 30);
}

解决方案:先清除以前定时器,只保留当前的定时器

4. 缓动效果动画

缓动动画就是让元素运动有所变化。

思路:

  1. 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
  2. 核心算法:(目标值-现在的位置)/ 10 ,作为每次移动的步长
  3. 停止条件:让当前盒子位置等于目标位置就停止定时器
  4. 注意步长值需要取整
function animate(obj, target) {
	clearInterval(obj.timer);
	obj.timer = setInterval(function() {
		//步长值写定时器里面
		var step=(target-obj.offsetLeft)/10;
		if (obj.offsetLeft >= target) {
			clearInterval(obj.timer);
		}
		//把每次加1改为慢慢变小,(目标值-现在的位置)/ 10 ,作为每次移动的步长
		obj.style.left = obj.offsetLeft + step + 'px';
	}, 15);
}

5. 动画函数在多个目标之间移动

可以让动画函数从800移动到500.

当我们点击按钮时,判断步长时正值还是负值

  1. 如果是正值,则步长往大了取整。
  2. 如果是负值,则步长向小了取整。
<body>
<button class="btn500">go500</button>
<button class="btn800">go800</button>
<div></div>
<span></span>
<script type="text/javascript">
	//简单函数封装,obj目标对象,target目标位置
	//当我们不断点击按钮,这个元素会越来越快,应为开启太多定时器
	function animate(obj, target) {
		clearInterval(obj.timer);
		obj.timer = setInterval(function() {
			//步长值写定时器里面
			// 把步长值改为整数,避免到不了固定位置
			// var step = Math.ceil((target - obj.offsetLeft) / 10);
			var step = (target - obj.offsetLeft) / 10;
			step = step > 0 ? Math.ceil(step) : Math.floor(step);
			if (obj.offsetLeft == target) {
				clearInterval(obj.timer);
			}
			//把每次加1改为慢慢变小,(目标值-现在的位置)/ 10 ,作为每次移动的步长
			obj.style.left = obj.offsetLeft + step + 'px';
		}, 15);
	}

	var div = document.querySelector('div');
	var span = document.querySelector('span');
	var btn500 = document.querySelector('.btn500');
	var btn800 = document.querySelector('.btn800');
	animate(div, 300);
	btn500.addEventListener('click', function() {
		animate(span, 500);
	})
	btn800.addEventListener('click', function() {
		animate(span, 800);
	})
</script>
</body>

6. 给动画函数添加回调参数

回调函数原理:函数可以作为一个参数。将这个函数作为参数传递到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫回调

回调函数写的位置:定时器结束的位置。

<body>
<button class="btn500">go500</button>
<button class="btn800">go800</button>
<div></div>
<span></span>
<script type="text/javascript">
	//简单函数封装,obj目标对象,target目标位置
	//当我们不断点击按钮,这个元素会越来越快,应为开启太多定时器
	function animate(obj, target, callback) {
		// console.log(callback);//等价于 callback=function(){}调用的时候callback()
		clearInterval(obj.timer);
		obj.timer = setInterval(function() {
			//步长值写定时器里面
			// 把步长值改为整数,避免到不了固定位置
			// var step = Math.ceil((target - obj.offsetLeft) / 10);
			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();
				}
			}
			//把每次加1改为慢慢变小,(目标值-现在的位置)/ 10 ,作为每次移动的步长
			obj.style.left = obj.offsetLeft + step + 'px';
		}, 15);
	}

	var div = document.querySelector('div');
	var span = document.querySelector('span');
	var btn500 = document.querySelector('.btn500');
	var btn800 = document.querySelector('.btn800');
	animate(div, 300);
	btn500.addEventListener('click', function() {
		animate(span, 500);
	})
	btn800.addEventListener('click', function() {
		animate(span, 800, function() {
			// alert('你好吗');
			span.style.backgroundColor='red';//等移动结束了再执行
		});
	})
</script>
</body>

7. 动画函数封装到单独JS文件里面

因为以后经常使用这个动画函数,可以单独封装到一个JS文件里面,使用的时候引用这个JS文件即可。

function animate(obj, target, callback) {
	// console.log(callback);//等价于 callback=function(){}调用的时候callback()
	clearInterval(obj.timer);
	obj.timer = setInterval(function() {
		//步长值写定时器里面
		// 把步长值改为整数,避免到不了固定位置
		// var step = Math.ceil((target - obj.offsetLeft) / 10);
		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();
			}
		}
		//把每次加1改为慢慢变小,(目标值-现在的位置)/ 10 ,作为每次移动的步长
		obj.style.left = obj.offsetLeft + step + 'px';
	}, 15);
}

案例——右侧盒子滑动

<script src="js/animate.js" type="text/javascript" charset="utf-8"></script>

<style type="text/css">
	*{
		margin: 0;
		padding: 0;
	}
	.slider-bar{
		float: right;
		position: relative;
	}
	span{
		position: absolute;
		width: 40px;
		height: 40px;
		background-color: pink;
		right: 0;
		text-align: center;
	}
	.con{
		position: absolute;
		height: 40px;
		width: 200px;
		background-color: #0000FF;
		z-index: -1;
		text-align: left;
		right: -160px;
	}
</style>

<body>
	<div class="slider-bar">
		<span><-</span>
		<div class="con">问题反馈</div>
	</div>
</body>

<script type="text/javascript">
	//1.获取元素
	var sliderbar=document.querySelector('.slider-bar');
	var con=document.querySelector('.con');
	sliderbar.addEventListener('mouseenter',function(){
		animate(con,-160,function(){
			// 当动画执行完毕,将左箭头指向右箭头
			sliderbar.children[0].innerHTML='->';
		});
	})
	sliderbar.addEventListener('mouseleave',function(){
		animate(con,0,function(){
			sliderbar.children[0].innerHTML='<-';
		});
	})
</script>

七、常见网页特效案例

案例——网页轮播图

轮播图也称焦点图

 

 

 

 

//js
window.addEventListener('load', function() {
	// 1.获取元素
	var arrow_l = document.querySelector('.arrow-l');
	var arrow_r = document.querySelector('.arrow-r');
	var focus = document.querySelector('.focus');
	var focusWidth = focus.offsetWidth;
	// 2.鼠标经过focus 就显示隐藏左右按钮
	focus.addEventListener('mouseenter', function() {
		arrow_l.style.display = 'block';
		arrow_r.style.display = 'block';
		clearInterval(timer);
		timer = null;
	})
	focus.addEventListener('mouseleave', function() {
		arrow_l.style.display = 'none';
		arrow_r.style.display = 'none';
		timer = setInterval(function() {
			// 手动调用事件
			arrow_r.click()
		}, 2000);
	})

	// 3.动态生成小圆圈 有几张图片,我就生成几个小圆圈
	var ul = focus.querySelector('ul');
	var ol = focus.querySelector('.circle');
	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() {
			for (var i = 0; i < ol.children.length; i++) {
				ol.children[i].className = '';
			}
			this.className = 'current';
			//5.点击小圆圈,移动图片 当然是ul
			//ul的移动距离就是小圆圈索引号乘以图片宽度 注意是负值
			// 当我们点击了某个小li,就拿到li的索引号
			var index = this.getAttribute('index');
			// 当我们点击了某个小li,就要把这个li的索引号给num
			num = index;
			//当我们点击了某个小li,就把li的索引号给circle1
			circle = index;
			animate(ul, -index * focusWidth);
		})
	}
	// 把ol里面第一个小li设置为current
	ol.children[0].className = 'current';
	// 6.克隆第一张图片放到ul最前面
	var first = ul.children[0].cloneNode(true);
	ul.appendChild(first);
	//7.右侧按钮点击事件
	var num = 0;
	var circle = 0; //控制小圆圈播放
	var flag = true; //节流阀
	arrow_r.addEventListener('click', function() {
		if (flag) {
			flag = false; //关闭节流阀
			// 如果走到最后,图片滚到第一张
			if (num == ul.children.length - 1) {
				ul.style.left = 0;
				num = 0;
			}
			num++;
			animate(ul, -num * focusWidth, function() {
				flag = true; //打开节流阀
			});
			// 8.点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
			circle++;
			// 如果circle==4 说明走到了克隆的图片,我们就复原
			if (circle == ol.children.length) {
				circle = 0;
			}
			circleChange();
		}
	})

	// 9.左侧按钮做法
	arrow_l.addEventListener('click', function() {
		if (flag) {
			flag = false;
			// 如果第一张,图片滚到最后一张
			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 说明走到了克隆的图片,我们就复原
			// if (circle < 0 ) {
			// 	circle = ol.children.length-1;
			// }
			circle = circle < 0 ? ol.children.length - 1 : circle;
			circleChange();
		}

	});

	function circleChange() {
		// 先清除其余小圆圈的current类名
		for (var i = 0; i < ol.children.length; i++) {
			ol.children[i].className = '';
		}
		// 留下当前的小圆圈current类名
		ol.children[circle].className = 'current';
	}

	// 10。自动播放
	var timer = setInterval(function() {
		// 手动调用事件
		arrow_r.click()
	}, 2000);
})
<!--html-->
<div class="focus fl">
	<!-- 左侧按钮 -->
	<a href="javascript:;" class="arrow-l">
		&lt;
	 </a>
	<!-- 右侧按钮 -->
	<a href="javascript:;" class="arrow-r">  </a>
	<!-- 核心的滚动区域 -->
	<ul>
		<li>
			<a href="#"><img src="upload/focus.jpg" alt=""></a>
		</li>
		<li>
			<a href="#"><img src="upload/focus1.jpg" alt=""></a>
		</li>
		<li>
			<a href="#"><img src="upload/focus2.jpg" alt=""></a>
		</li>
		<li>
			<a href="#"><img src="upload/focus3.jpg" alt=""></a>
		</li>
	</ul>
	<!-- 小圆圈 -->
	<ol class="circle">

	</ol>
</div>
//css
.focus {
    position: relative;
    width: 721px;
    height: 455px;
    background-color: purple;
    overflow: hidden;
}

.focus ul {
    position: absolute;
    top: 0;
    left: 0;
    width: 600%;
}

.focus ul li {
    float: left;
}

.arrow-l,
.arrow-r {
    display: none;
    position: absolute;
    top: 50%;
    margin-top: -20px;
    width: 24px;
    height: 40px;
    background: rgba(0, 0, 0, .3);
    text-align: center;
    line-height: 40px;
    color: #fff;
    font-family: 'icomoon';
    font-size: 18px;
    z-index: 2;
}

.arrow-r {
    right: 0;
}

.circle {
    position: absolute;
    bottom: 10px;
    left: 50px;
}

.circle li {
    float: left;
    width: 8px;
    height: 8px;
    /*background-color: #fff;*/
    border: 2px solid rgba(255, 255, 255, 0.5);
    margin: 0 3px;
    border-radius: 50%;
    /*鼠标经过显示小手*/
    cursor: pointer;
}

.current {
    background-color: #fff;
}

1. 节流阀

防止轮播图点击按钮播放过快。

节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。

 

arrow_r.addEventListener('click', function() {
	if (flag) {
		flag = false; //关闭节流阀
		// 如果走到最后,图片滚到第一张
		if (num == ul.children.length - 1) {
			ul.style.left = 0;
			num = 0;
		}
		num++;
		animate(ul, -num * focusWidth, function() {
			flag = true; //打开节流阀
		});
		// 8.点击右侧按钮,小圆圈跟随一起变化,可以再声明一个变量控制小圆圈的播放
		circle++;
		// 如果circle==4 说明走到了克隆的图片,我们就复原
		if (circle == ol.children.length) {
			circle = 0;
		}
		circleChange();
	}
})

短路运算简写callback函数

// if (callback) {
//     // 调用函数
//     callback();
// }
callback && callback();

案例——返回顶部

滚动窗口至文档中特定位置

window.scroll(x,y)

	<style type="text/css">
		.slider-bar {
			position: absolute;
			left: 50%;
			top: 300px;
			margin-left: 600px;
			width: 45px;
			height: 130px;
			background-color: pink;
		}

		.w {
			width: 1200px;
			margin: 10px auto;
		}

		.header {
			height: 150px;
			background-color: lightgrey;
		}

		.banner {
			height: 400px;
			background-color: lightblue;
		}

		.main {
			height: 2000px;
			background-color: yellowgreen;
		}

		span {
			display: none;
			position: absolute;
			bottom: 0;
		}
	</style>
	<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>
	</body>
	<script type="text/javascript">
		var sliderbar = document.querySelector('.slider-bar');
		var banner = document.querySelector('.banner');
		//banner.offsetTop就是卷去的高度,要写在滚动外面
		var bannerTop = banner.offsetTop;
		//当我们侧边栏固定定位后应保持的top值
		var sliderbarTop = sliderbar.offsetTop - bannerTop;
		//获取主题冤死
		var main = document.querySelector('.main');
		var goBack = document.querySelector('.goBack');
		var mainTop = main.offsetTop;

		//2.页面滚动事件
		document.addEventListener('scroll', function() {
			console.log(window.pageYOffset);
			//3. 当我们页面卷去的头部大于 banner.offsetTop时, 侧边栏变成固定定位
			if (window.pageYOffset >= bannerTop) {
				sliderbar.style.position = "fixed";
				sliderbar.style.top = sliderbarTop + 'px';
			} else {
				sliderbar.style.position = "absolute";
				sliderbar.style.top = '300px';
			}
			//4.当页面滚动到main盒子,就显示goback模块
			if (window.pageYOffset >= mainTop) {
				goBack.style.display = "block";
			} else {
				goBack.style.display = "none";
			}
		})

		//3.当我们写了返回顶部模块,就让窗口返回正上方
		goBack.addEventListener('click', function() {
			animate(window, 0);
		})

        //纵向缓动动画
		function animate(obj, target, callback) {
			// console.log(callback);//等价于 callback=function(){}调用的时候callback()
			clearInterval(obj.timer);
			obj.timer = setInterval(function() {
				//步长值写定时器里面
				// 把步长值改为整数,避免到不了固定位置
				// var step = Math.ceil((target - window.pageYOffset) / 10);
				var step = (target - window.pageYOffset) / 10;
				step = step > 0 ? Math.ceil(step) : Math.floor(step);
				if (window.pageYOffset == target) {
					clearInterval(obj.timer);
					//回调函数写道定时器里面
					if (callback) {
						callback();
					}
				}
				//把每次加1改为慢慢变小,(目标值-现在的位置)/ 10 ,作为每次移动的步长
				// obj.style.left = window.pageYOffset + step + 'px';
				window.scroll(0, window.pageYOffset + step);
			}, 15);
		}
	</script>

 

案例——筋斗云移动

 

 

 

<style>
	* {
		margin: 0;
		padding: 0
	}

	ul {
		list-style: none;
	}

	body {
		background-color: black;
	}

	.c-nav {
		width: 900px;
		height: 42px;
		background: #fff url(img/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;
	}

	.cloud {
		position: absolute;
		left: 0;
		top: 0;
		width: 83px;
		height: 42px;
		background: url(img/cloud.gif) no-repeat;
	}
</style>
</head>
<script src="./js/animate.js"></script>
<script type="text/javascript">
window.addEventListener('load', function() {
	var cloud = document.querySelector('.cloud');
	var c_nav = document.querySelector('.c-nav');
	var lis = c_nav.querySelectorAll('li');
	//current作为筋斗云起始位置
	var currnet=0;
	for (var i = 0; i < lis.length; i++) {
		//(1)鼠标经过把当前小li的位置作目标值
		lis[i].addEventListener('mouseenter', function() {
			animate(cloud, this.offsetLeft);
		})
		//(2)鼠标离开 复原为0
		lis[i].addEventListener('mouseleave', function() {
			animate(cloud, currnet);
		})
		// (3)当我们鼠标点击,就把当前位置作为目标值
		lis[i].addEventListener('click',function(){
			currnet=this.offsetLeft;
		})
	}
})
</script>
<body>
<div id="c_nav" class="c-nav">
	<span class="cloud"></span>
	<ul>
		<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>
		<li><a href="#">啥是佩奇</a></li>
	</ul>
</div>
</body>

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值