事件对象——event
事件对象是用来记录一些事件发生时的相关信息的对象。事件对象只有事件发生时才会产生,并且只能是事件处理函数内部访问,在所有事件处理函数运行结束后,事件对象就被销毁!
div.onclick = function(e) {
console.log(e);
// e 就是事件对象 我们可以根据它获取到许多的信息
// 在IE中,时间对象没有传递给函数,而是在window上,名字叫做event
}
在IE浏览器中,通过window.event
获取事件对象,在其他浏览器中可以通过e
获取事件对象。因为在IE浏览器与其他浏览器获取事件对象存在兼容性问题,可以通过以下方式处理兼容性问题。
方式1:使用if…else
// 定义一个变量用于存放事件对象
var event = null;
// 不是IE浏览器
if(event == e){
event = e;
}else{
// 是IE浏览器
event = window.event;
}
方式2:三目运算
var event = e ? e : window.event;
方式3:短路运算(常用)
var event = e || window.event;
事件对象的重要属性
鼠标事件
altKey
热键alt键ctrlKey
热键ctrl键shiftKey
热键shift键
以上属性都是布尔值,表示是否按下,没有按下为false,按下为trueoffsetX
事件发生时鼠标位于元素内部的left位置(从鼠标位置到左边框内)offsetY
事件发生时鼠标位于元素内部的top位置(从鼠标位置到上边框内)clientX
事件发生时鼠标到视口的左边距离clientY
事件发生时鼠标到视口的上边距离pageX
事件发生时鼠标到页面的左边距离pageY
事件发生时鼠标到页面的上边距离screenX
事件发生时鼠标到屏幕的左边距离screenY
事件发生时鼠标到屏幕的上边距离currentTarget
绑定事件的元素target
触发事件的元素
键盘事件
key
表示当前的键对应的字符keyCode
表示当前的键对应的字符的ASCII码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
position: relative;
width: 500px;
height: 500px;
margin: 100px auto;
background-color: tomato;
border: 10px solid red;
}
.box1{
position: absolute;
width: 200px;
height: 200px;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: yellow;
border: 10px solid green;
}
</style>
</head>
<body>
<div id="box" class="box">
<div id="box1" class="box1"></div>
</div>
<script>
var box = document.getElementById("box");
var box1 = document.getElementById("box1");
box.onclick = function(e){
// 浏览器兼容 事件对象
// 方式1:if(){}else{}
// var event = null;
// if(event == e){
// event = e;
// }else{
// event = window.event;
// }
// 方式2:三目运算
// var event = e ? e : window.event;
// 方式3:短路运算
var event = e || window.event;
// 获取鼠标位置
// offsetX 事件发生时,鼠标到元素左边框内的距离。注意:会受到子元素的影响
console.log("鼠标到元素左边框内的距离:"+event.offsetX);
// offsetY 事件发生时,鼠标到元素上边框内的距离。注意:会受到子元素的影响
console.log("鼠标到元素上边框内的距离:"+event.offsetY);
// clientX 事件发生时,鼠标到视口的左边距离
console.log("鼠标到视口的左边距离"+event.clientX);
// clientY 事件发生时,鼠标到视口的上边距离
console.log("鼠标到视口的上边距离:"+event.clientY);
// pageX 事件发生时,鼠标到页面的左边距离
console.log("鼠标到页面的左边距离:"+event.pageX);
// pageY 事件发生时,鼠标到页面的上边距离
console.log("鼠标到页面的上边距离:"+event.pageY);
// screenX 事件发生时,鼠标到屏幕的左边距离
console.log("鼠标到屏幕的左边距离:"+event.screenX);
// screenY 事件发生时,鼠标到屏幕的上边距离
console.log("鼠标到屏幕的上边距离:"+event.screenY);
}
</script>
</body>
</html>
鼠标点击黄色区域任意位置:
鼠标点击红色区域任意位置:
事件绑定方式
DOM0级
- 绑定
- 元素.on事件类型 = 事件函数
- 只能绑定一个事件,因为它是对属性进行赋值
- 移除
- 元素.on事件类型 = null
注意: 一个对象的属性只能够保存一个值。 如果对一个对象属性进行多次赋值,后面赋值的属性会替换掉前面的属性。
DOM2级
-
绑定
- dom.addEventListener(type, handler, boolean);
- type: 事件类型字符串,不带
on
,要带双引号或单引号 - handler: 事件处理函数
- boolean: 布尔值。决定绑定到捕获阶段还是冒泡阶段,默认是false,表示冒泡阶段
- type: 事件类型字符串,不带
- 注意: 可以通过addEventListener方法进行多个事件函数的绑定,执行时是按照代码的书写顺序执行,因为代码的书写顺序决定了绑定顺序。
- dom.addEventListener(type, handler, boolean);
-
移除
- document.removeEventListener(type, handler, boolean);
- type: 事件类型字符串,不带
on
- handler: 事件处理函数,一定要保证函数地址是绑定的那个
- boolean: 布尔值。决定移除的是捕获阶段还是冒泡阶段,默认是false,表示冒泡
- type: 事件类型字符串,不带
- 注意: 结论: 第二个参数是要移除的函数,函数是引用类型,引用类型的比较的是地址。 所以一定要保证 移除的函数是当初绑定的那个函数本身
- document.removeEventListener(type, handler, boolean);
-
IE中的高级绑定方式(非DOM2级)
注意: IE中没有实现DOM2级- 绑定
- dom.attachEvent(type, handler);
- type: 事件类型字符串,带
on
- handler: 事件处理函数
- 没有第三个参数,意味着不能够绑定到捕获阶段
- type: 事件类型字符串,带
- 特点: 可以对同一个元素绑定多个同类型事件的处理函数,执行起来是倒着执行 ,先绑定的后执行,后绑定的先执行
- dom.attachEvent(type, handler);
- 移除
- dom.detachEvent(type, handler);
- type: 事件类型字符串,带
on
- handler: 事件处理函数,要注意函数的地址问题
- type: 事件类型字符串,带
- dom.detachEvent(type, handler);
- 绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 400px;
height: 200px;
background: red;
margin: 0 auto;
}
.text{
height: 60px;
background: green;
font-size: 24px;
line-height: 30px;
}
.btn{
width: 100px;
height: 30px;
text-align: center;
line-height: 30px;
}
</style>
</head>
<body>
<div id="box" class="box">
<p id="text" class="text"></p>
<button id="btn" class="btn">点我</button>
</div>
<script>
// 获取元素
var text = document.getElementById("text");
var btn = document.getElementById("btn");
// 为按钮绑定点击事件
// 方式1:DOM0级
btn.onclick = function(){
// 点击按钮,p标签内输出文字
text.innerHTML = "您点击了按钮,触发了事件,on事件";
}
// 方式2:DOM2级
// btn.addEventListener('click', function(){
// text.innerHTML = "您点击了按钮,触发了事件,addEventListener";
// });
</script>
</body>
</html>
使用方式1绑定事件,点击按钮:
使用方式2绑定事件,点击按钮:
事件流程
- 事件冒泡: 当点击时,事件从最精确的元素一层一层往上触发,直到最顶层元素,这个过程叫做事件冒泡
- 事件捕获: 当点击时,事件从最顶层元素一层一层的往下触发,直到最精确元素,这个过程叫做事件捕获
- 最精确元素: 鼠标点到谁,谁就是最精确元素
- 最顶层元素:
- 高级浏览器最顶层元素是
window
- IE浏览器最顶层元素是
document
- 高级浏览器最顶层元素是
阻止冒泡
高级浏览器中 可以通过e.stopPropagation()
进行阻止事件的冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box1{
position: relative;
width: 500px;
height: 500px;
margin: 100px auto;
background-color: tomato;
border: 10px solid red;
}
.box2{
position: absolute;
width: 200px;
height: 200px;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: yellow;
border: 10px solid green;
}
</style>
</head>
<body>
<div class="box1" id="box1">
<div class="box2" id="box2"></div>
</div>
<script>
var box1 = document.querySelector(".box1");
var box2 = document.querySelector(".box2");
box1.onclick = function() {
console.log("这是BOX1");
}
box2.onclick = function(e) {
// 阻止冒泡
// e.stopPropagation();
console.log("这是BOX2");
}
</script>
</body>
</html>
没阻止冒泡前,点击box1,再点击box2,可以看到:
点击box1时,box1触发了一次。点击box2时,先触发了box2,再触发box1,这是由于事件冒泡引起的。
阻止冒泡后,点击box1,再点击box2,可以看到:
点击box1时,box1触发了一次。点击box2时,只触发了box2,没有触发box1,这是由于已经阻止了事件冒泡的发生。
IE浏览器中 可以通过e.cancelBubble = true
进行阻止事件的冒泡
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box1{
position: relative;
width: 500px;
height: 500px;
margin: 100px auto;
background-color: tomato;
border: 10px solid red;
}
.box2{
position: absolute;
width: 200px;
height: 200px;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
background-color: yellow;
border: 10px solid green;
}
</style>
</head>
<body>
<div class="box1" id="box1">
<div class="box2" id="box2"></div>
</div>
<script>
var box1 = document.querySelector(".box1");
var box2 = document.querySelector(".box2");
box1.onclick = function() {
console.log("这是BOX1");
}
box2.onclick = function(e) {
var e = e || window.event;
e.cancelBubble = true;
console.log("这是BOX2");
}
</script>
</body>
</html>
停止默认行为
浏览器的一些事件中,带有一些默认行为。比如a标签的点击事件中,会带有跳转页面的行为。表单的点击事件中,带有提交的默认行为。滚轮事件中,带有改变页面卷动值的默认行为。
高级浏览器中 可以通过 e.preventDefault()
阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.addEventListener("click", function(e) {
console.log("点击了a标签1111");
e.preventDefault();
}, false);
IE浏览器中 可以通过 e.returnValue = false;
阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.attachEvent("onclick", function(e) {
console.log("点击了a标签1111");
e.returnValue = false;
});
DOM0级事件绑定方式中,可以通过return false
进行阻止默认行为
// 获取元素
var a = document.getElementsByTagName("a")[0];
// 设置点击事件
a.onclick = function() {
return false;
}
事件委托(事件代理)
思想: 将原本子元素做的事情,委托给父元素去做。将事件绑定给父元素,父元素事件触发时,通过e.target判定触发事件的元素。决定执行对应代码。
// 1 获取元素 获取不可能被移除的父元素
var tbody = document.querySelector("tbody");
// 2 给tbody绑定事件
tbody.onclick = function(e) {
// e.target 这个属性指向触发事件的元素
console.log(e.target)
// 判定 点击到的是什么
if (e.target.className === "del") {
// 点击到的是移除按钮
e.target.parentNode.remove();
}
}
实现一个拖拽功能
一个元素在页面中可以被随意拖拽。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
position: absolute;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box" class="box"></div>
<script>
// 获取元素
var box = document.getElementById("box");
// 鼠标按下事件
box.onmousedown = function(e){
// 记录鼠标此时的位置
var nowX = e.clientX;
var nowY = e.clientY;
// 记录元素此时的位置
var left = box.offsetLeft;
var top = box.offsetTop;
// 鼠标移动事件
document.onmousemove = function(e){
// 设置元素位置
box.style.left = left + e.clientX - nowX + "px";
box.style.top = top + e.clientY - nowY + "px";
}
}
// 鼠标弹起事件
box.onmouseup = function(){
// 移除事件
document.onmousemove = null;
}
</script>
</body>
</html>
实现一个区域拖拽功能
一个元素在一个范围内可以被随意拖拽,不能超出范围。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
position: relative;
width: 600px;
height: 400px;
background: green;
margin: 100px auto;
}
.box1{
position: absolute;
width: 100px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="box" class="box">
<div id="box1" class="box1"></div>
</div>
<script>
// 获取元素
var box = document.getElementById("box");
var box1 = document.getElementById("box1");
// 鼠标触发按下事件
box1.onmousedown = function(e){
// 浏览器兼容
var event = e || window.event;
// 记录鼠标此时的位置
var nowX = e.clientX;
var nowY = e.clientY;
// 记录元素此时的位置
var left = box1.offsetLeft;
var top = box1.offsetTop;
// 鼠标移动事件
box.onmousemove = function(e){
// 记录鼠标拖动到的位置
var moveX = e.clientX;
var moveY = e.clientY;
// 计算此时元素距离左边的距离
var resultX = moveX - nowX + left;
// 记录此时元素距离上边的距离
var resultY = moveY - nowY + top;
// 如果元素超出左边框
if(resultX < 0){
// 将其设为0,限制其超出
resultX = 0;
}else if(resultX > box.offsetWidth - box1.offsetWidth){
// 如果元素超出右边,限制其超出
resultX = box.offsetWidth - box1.offsetWidth;
}
// 如果元素超出上边框
if(resultY < 0){
// 将其设为0,限制其超出
resultY = 0;
}else if(resultY > box.offsetHeight - box1.offsetHeight){
// 如果元素超出下边框,限制其超出
resultY = box.offsetHeight - box1.offsetHeight;
}
// 设置元素位置
box1.style.left = resultX + "px";
box1.style.top = resultY + "px";
}
}
// 鼠标抬起,移除移动事件
document.onmouseup = function(){
// 移除事件
box.onmousemove = null;
}
</script>
</body>
</html>
实现一个在页面中点击任意位置创建元素功能1
在页面中任意位置点击,创建一个元素,再点击第二次,上一个元素消失。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script>
document.onclick = function(e){
var event = e || window.event;
// 点击第二次,前一次的消失
document.body.innerHTML = "";
// 创建元素
var box = document.createElement("div");
box.style.position = "absolute";
box.style.width = "100px";
box.style.height = "100px";
box.style.backgroundColor = "red";
box.style.left = event.clientX - 50 + "px";
box.style.top = event.clientY - 50 + "px";
// 元素上树
document.body.appendChild(box);
}
</script>
</body>
</html>
实现一个在页面中点击任意位置创建元素功能2
在页面上任意位置点击,创建一个元素,点击几次就创建几个,当鼠标点击已经创建的元素时,该元素消失。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script>
document.onclick = function(e){
var event = e || window.event;
// 创建元素
// 点击多少次就创建多少个div
var box = document.createElement("div");
box.style.position = "absolute";
box.style.width = "100px";
box.style.height = "100px";
box.style.backgroundColor = "red";
box.style.left = event.clientX - 50 + "px";
box.style.top = event.clientY - 50 + "px";
document.body.appendChild(box);
// 点击页面上创建出来的div后将其移除
box.onclick = function(e){
// 移除
box.remove();
// 阻止冒泡
e.stopPropagation();
}
}
</script>
</body>
</html>
实现一个留言板功能
在输入框输入留言内容,点击留言按钮,显示留言的内容并清空留言板,显示删除按钮和留言数量。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 800px;
height: 400px;
margin: 0 auto;
border: 2px solid #ccc;
}
h1{
height: 30px;
font-size: 20px;
line-height: 30px;
text-align: center;
}
ul{
height: 300px;
}
ul li{
list-style: none;
height: 20px;
font-size: 16px;
line-height: 20px;
display: flex;
}
ul li span{
flex: 9;
}
ul li i{
flex: 1;
cursor: pointer;
text-align: center;
}
.box .operate{
height: 70px;
display: flex;
}
.box .operate textarea{
height: 70px;
flex: 9;
resize: none;
}
.box .operate button{
height: 70px;
flex: 1;
}
</style>
</head>
<body>
<div class="box" id="box">
<h1>留言板<span id="num"></span></h1>
<ul id="list">
<!-- <li><span>人生得意须尽欢</span><i>×</i></li> -->
</ul>
<div class="operate">
<textarea name="" id="message"></textarea>
<button id="btn">留言</button>
</div>
</div>
<script>
// 获取元素
var btn = document.getElementById("btn");
var message = document.getElementById("message");
var list = document.getElementById("list");
var num = document.getElementById("num");
var count = 0;
// 绑定事件
btn.onclick = function(){
// 如果msg.value为空,则return
if(message.value === ""){
return;
}
// 只有当经过了信息验证的时候,说明是有效的留言信息,才累加
count++;
// 创建元素
var li = document.createElement("li");
// 使用字符串拼接代替创建元素
li.innerHTML = "<span>" + message.value + "</span><i>×</i>";
list.appendChild(li);
num.innerHTML = "(" + count + ")";
message.value = "";
// 获取元素
var dels = document.getElementsByTagName("i");
// console.log(dels);
// 给i绑定事件
for (var i = 0; i < dels.length; i++){
dels[i].onclick = function(){
// 移除li
this.parentNode.remove();
count--;
num.innerHTML = "(" + count + ")";
}
}
}
// 现在我们面临的问题:
// 1、未来元素没有事件
// 2、事件数量太多
// 3、防止内存泄漏
</script>
</body>
</html>
使用事件委托的方式实现留言板功能
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.box{
width: 800px;
height: 400px;
margin: 0 auto;
border: 2px solid #ccc;
}
h1{
height: 30px;
font-size: 20px;
line-height: 30px;
text-align: center;
}
ul{
height: 300px;
}
ul li{
list-style: none;
height: 20px;
font-size: 16px;
line-height: 20px;
display: flex;
}
ul li span{
flex: 9;
}
ul li i{
flex: 1;
cursor: pointer;
}
.box .operate{
height: 70px;
display: flex;
}
.box .operate textarea{
height: 70px;
flex: 9;
resize: none;
}
.box .operate button{
height: 70px;
flex: 1;
}
</style>
</head>
<body>
<div class="box" id="box">
<h1>留言板<span id="num"></span></h1>
<ul id="list">
<!-- <li><span>人生得意须尽欢</span><i class="dels">×</i></li> -->
</ul>
<div class="operate">
<textarea name="" id="message"></textarea>
<button id="btn">留言</button>
</div>
</div>
<script>
// 获取元素
var btn = document.getElementById("btn");
var message = document.getElementById("message");
var list = document.getElementById("list");
var num = document.getElementById("num");
var count = 0;
btn.onclick = function(){
// 如果msg.value为空,则return
if(message.value === ""){
return;
}
// 只有当经过了信息验证的时候,说明是有效的留言信息,才累加
count++;
// 创建元素
var li = document.createElement("li");
// 使用字符串拼接代替创建元素
li.innerHTML = "<span>" + message.value + "</span><i class='dels'>×</i>";
list.appendChild(li);
num.innerHTML = "(" + count + ")";
message.value = "";
}
// 为了解决之前留下的问题,我们研究出了一种叫做委托模式(代理模式)的设计模式
// 委托模式原理:给父元素添加事件,利用e.target做判定,只有点击的元素符合某种特征时,才执行对应的代码
list.onclick = function(e){
// 利用e.target判定最精确元素(判定点的是哪个元素)
// console.log(e.target);
if(e.target.className.toUpperCase() === "DELS"){
// console.log("点击到的是i标签了");
e.target.parentNode.remove();
count--;
num.innerHTML = "(" + count + ")";
}
}
</script>
</body>
</html>
淘宝放大镜功能1
鼠标移动到小图片上,显示一个放大镜蒙层,页面右边显示蒙层所在区域的放大图像,放大镜蒙层只能在小图片内移动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.small_box{
position: relative;
width: 400px;
height: 300px;
margin: 50px;
z-index: 1;
border: 1px solid #555;
}
.small_box img{
width: 100%;
height: 100%;
}
.floor_box{
display: none;
width: 160px;
height: 120px;
position: absolute;
background: #ffffcc;
filter: alpha(opacity = 50);
opacity: 0.5;
}
.mark{
cursor: move;
position: absolute;
display: block;
width: 100%;
height: 100%;
z-index: 10;
background: #fff;
filter: alpha(opacity = 100);
opacity: 0;
}
.big_box{
display: none;
position: absolute;
top: 0;
left: 460px;
width: 600px;
height: 400px;
overflow: hidden;
border: 1px solid #555;
z-index: 1;
margin: 50px;
}
.big_box img{
position: absolute;
z-index: 5;
}
</style>
</head>
<body>
<!-- 小图片 -->
<div id="small_box" class="small_box">
<!-- 蒙版层 -->
<div id="mark" class="mark"></div>
<!-- 放大镜 -->
<div id="floor_box" class="floor_box"></div>
<img src="../images/多肉.png" alt="" id="smallImg">
</div>
<!-- 大图片 -->
<div id="big_box" class="big_box">
<img src="../images/多肉.png" alt="" id="bigImg">
</div>
<script>
// 获取元素
var small_box = document.getElementById("small_box");
var floor_box = document.getElementById("floor_box");
var big_box = document.getElementById("big_box");
var bigImg = document.getElementById("bigImg");
var mark = document.getElementById("mark");
// 鼠标移入小图片
mark.onmouseover = function(){
floor_box.style.display = "block";
big_box.style.display = "block";
}
// 鼠标移出小图片
mark.onmouseout = function(){
floor_box.style.display = "none";
big_box.style.display = "none";
}
// 鼠标在小图片内移动
mark.onmousemove = function(e){
// 浏览器兼容
var event = e || window.event;
// 获取放大镜位置
var left = event.clientX - mark.offsetLeft - floor_box.offsetWidth/2;
var top = event.clientY - mark.offsetTop - floor_box.offsetHeight/2;
// 控制放大镜在小图片范围内
if(left < 0){
left = 0;
}else if(left > mark.offsetWidth - floor_box.offsetWidth){
left = mark.offsetWidth - floor_box.offsetWidth;
}
if(top < 0){
top = 0;
}else if(top > mark.offsetHeight - floor_box.offsetHeight){
top = mark.offsetHeight - floor_box.offsetHeight;
}
// 设置放大镜位置
floor_box.style.left = left + "px";
floor_box.style.top = top + "px";
// 设置大图片的位置:X/(A-B) = Y/(C-D)
var percentX = left / (mark.offsetWidth - floor_box.offsetWidth);
var percentY = top / (mark.offsetHeight - floor_box.offsetHeight);
bigImg.style.left = -percentX * (bigImg.offsetWidth - big_box.offsetWidth) + "px";
bigImg.style.top = -percentY * (bigImg.offsetHeight - big_box.offsetHeight) + "px";
}
</script>
</body>
</html>
淘宝放大镜功能
页面左边有一个小图片,小图片下方有图片列表,鼠标划过任意一张图片列表内的图片,上方的小图片相应改变,鼠标移到上方的小图片内,显示一个放大镜蒙层,页面右边显示放大后的效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>放大镜</title>
<style>
*{
margin: 0;
padding: 0;
}
.container{
width: 980px;
margin: 0 auto;
}
ul li{
list-style: none;
}
.fdj{
width: 350px;
position: relative;
}
.fdj .small{
width: 350px;
height: 350px;
border: 1px solid #ccc;
margin-bottom: 20px;
}
.fdj .small .glass {
display: none;
position: absolute;
top: 0;
left: 0;
width: 240px;
height: 240px;
background-color: rgba(44, 55, 66, .3);
cursor: move;
}
.fdj .list{
width: 350px;
height: 54px;
display: flex;
justify-content: space-around;
}
.fdj .list li{
width: 50px;
height: 50px;
/* transparent是全透明黑色(black)的速记法,即一个类似rgba(0,0,0,0)这样的值。 */
border: 2px solid transparent;
}
.fdj .list li.active{
border-color: red;
}
.big{
display: none;
position: absolute;
left: 110%;
top: 0;
width: 540px;
height: 540px;
overflow: hidden;
}
.big img {
position: absolute;
top: 0;
left: 0;
}
</style>
<!-- 引入封装好的js文件 -->
<script src="../js/GETCSS.js"></script>
</head>
<body>
<div class="content">
<!-- 版心 -->
<div class="container">
<div class="fdj">
<!-- 小图片 -->
<div class="small">
<img src="../images/small01.jpg" />
<!-- 放大镜 -->
<div class="glass"></div>
</div>
<!-- 小图片列表 -->
<ul class="list">
<!-- 为每个li设置自定义属性,默认是选中第一个li -->
<li data-small-img="../images/small01.jpg" data-big-img="../images/big01.jpg" class="active"><img src="../images/icon01.jpg" /></li>
<li data-small-img="../images/small02.jpg" data-big-img="../images/big02.jpg" class=""><img src="../images/icon02.jpg" /></li>
<li data-small-img="../images/small03.jpg" data-big-img="../images/big03.jpg" class=""><img src="../images/icon03.jpg" /></li>
</ul>
<!-- 大图片 -->
<div class="big">
<img src="../images/big01.jpg" />
</div>
</div>
</div>
</div>
<script>
// 获取元素
var glass = document.querySelector('.glass');
var small = document.querySelector('.small');
var big = document.querySelector('.big');
var lis = document.querySelectorAll('.list li');
var bigImg = big.querySelector('img');
var smallImg = small.querySelector('img');
// 放大镜元素右移的最大宽度
var maxLeft = 0;
// 放大镜元素下移的最大高度
var maxTop = 0;
// 小图片和大图片之间位移的像素比
var r = (350 - 240) / (800 - 540);
// 通过外部js文件获取small元素的left、top
var obj = GETCSS.offset(small);
// 鼠标进入事件
small.onmouseover = function(){
// 显示放大镜元素
glass.style.display = "block";
// 显示大图片
big.style.display = "block";
// 放大镜元素右移的最大宽度
maxLeft = small.clientWidth - glass.clientWidth;
// 放大镜元素下移的最大高度
maxTop = small.clientHeight - glass.clientHeight;
}
// 鼠标离开事件
small.onmouseout = function(){
// 隐藏放大镜元素
glass.style.display = "none";
// 隐藏大图片
big.style.display = "none";
}
// 鼠标移动事件
small.onmousemove = function(e){
// 浏览器兼容处理
var event = e || window.event;
// 计算放大镜元素此时的位置
var resultX = event.pageX - obj.left - glass.clientWidth / 2;
var resultY = event.pageY - obj.top - glass.clientHeight / 2;
// 控制放大镜在小图片区域内
if(resultX < 0){
resultX = 0;
}else if(resultX > maxLeft){
resultX = maxLeft;
}
if(resultY < 0){
resultY = 0;
}else if(resultY > maxTop){
resultY = maxTop;
}
// 设置放大镜元素随鼠标移动后的位置
glass.style.left = resultX + "px";
glass.style.top = resultY + "px";
// 设置大图片位置随放大镜的移动而移动,方向与放大镜移动的方向相反
bigImg.style.left = -resultX / r + "px";
bigImg.style.top = -resultY / r + "px";
}
// 鼠标弹起事件
document.onmouseup = function(){
document.onmousemove = null;
}
// 添加循环事件,用于设置点击小图片列表的图片,对应的li添加边框,小图片和大图片相应的改变
for (var i = 0; i < lis.length; i++){
// 设置鼠标进入事件
lis[i].onmouseenter = function(){
// 1、先清除其他li的acv=tive类,再给对应的li添加active类
for(var j = 0; j < lis.length; j++){
lis[j].className = "";
}
this.className = "active";
// 2、小图片获取自定义属性值,切换小图片的src
smallImg.src = this.getAttribute("data-small-img");
// 2、小图片获取自定义属性值,切换小图片的src
bigImg.src = this.getAttribute("data-big-img");
}
}
</script>
</body>
</html>