当前位置: 首页 > news >正文

JS13-事件的绑定和事件对象Event

绑定事件的两种方式/DOM事件的级别

DOM0的写法:onclick

    element.onclick = function () {}

举例:

<body>
<button>点我</button>
<script>var btn = document.getElementsByTagName("button")[0];//这种事件绑定的方式,如果绑定多个,则后面的会覆盖掉前面的btn.onclick = function () {console.log("事件1");}btn.onclick = function () {console.log("事件2");}</script>
</body>

点击按钮后,上方代码的打印结果:

事件2

我们可以看到,DOM对象.事件 = 函数的这种绑定事件的方式:一个元素的一个事件只能绑定一个响应函数。如果绑定了多个响应函数,则后者会覆盖前者。

DOM2的写法:addEventListener(高版本浏览器)

    element.addEventListener('click', function () {}, false);

参数解释:

  • 参数1:事件名的字符串(注意,没有on)

  • 参数2:回调函数:当事件触发时,该函数会被执行

  • 参数3:true表示捕获阶段触发,false表示冒泡阶段触发(默认)。如果不写,则默认为false。【重要】

举例:

<body>
<button>按钮</button>
<script>var btn = document.getElementsByTagName("button")[0];// addEventListener: 事件监听器。 原事件被执行的时候,后面绑定的事件照样被执行// 这种写法不存在响应函数被覆盖的情况。(更适合团队开发)btn.addEventListener("click", fn1);btn.addEventListener("click", fn2);function fn1() {console.log("事件1");}function fn2() {console.log("事件2");}</script>
</body>

点击按钮后,上方代码的打印结果:

    事件1事件2

我们可以看到,addEventListener()这种绑定事件的方式:

  • 一个元素的一个事件,可以绑定多个响应函数。不存在响应函数被覆盖的情况。执行顺序是:事件被触发时,响应函数会按照函数的绑定顺序执行。

  • addEventListener()中的this,是绑定事件的对象。

  • addEventListener()不支持 IE8 及以下的浏览器。在IE8中可以使用attachEvent来绑定事件(详见下一小段)。

DOM2的写法:attachEvent(IE8及以下版本浏览器)

    element.attachEvent('onclick', function () {});

参数解释:

  • 参数1:事件名的字符串(注意,有on)

  • 参数2:回调函数:当事件触发时,该函数会被执行

举例:

    <body><button>按钮</button><script>var btn = document.getElementsByTagName('button')[0];btn.attachEvent('onclick', function() {console.log('事件1');});btn.attachEvent('onclick', function() {console.log('事件2');});</script></body>

在低版本的IE浏览器上,点击按钮后,上方代码的打印结果:

    事件2事件1

我们可以看到,attachEvent()这种绑定事件的方式:

  • 一个元素的一个事件,可以绑定多个响应函数。不存在响应函数被覆盖的情况。注意:执行顺序是,后绑定的先执行。

  • attachEvent()中的this,是window

兼容性写法

上面的内容里,需要强调的是:

  • addEventListener()中的this,是绑定事件的对象。

  • attachEvent()中的this,是window。

既然这两个写法的this不同,那么,有没有一种兼容性的写法可以确保这两种绑定方式的this是相同的呢?我们可以封装一下。代码如下:

    <body><button>按钮</button><script>var btn = document.getElementsByTagName('button')[0];myBind(btn , "click" , function(){alert(this);});//定义一个函数,用来为指定元素绑定响应函数/** addEventListener()中的this,是绑定事件的对象* attachEvent()中的this,是window*  需要统一两个方法this*//** 参数:*  element 要绑定事件的对象*  eventStr 事件的字符串(不要on)*  callback 回调函数*/function myBind(element , eventStr , callback){if(element.addEventListener){//大部分浏览器兼容的方式element.addEventListener(eventStr , callback , false);}else{/** this是谁,由调用方式决定* callback.call(element)*///IE8及以下element.attachEvent("on"+eventStr , function(){//在匿名函数 function 中调用回调函数callbackcallback.call(element);});}}</script></body>

事件对象

当事件的响应函数被触发时,会产生一个事件对象event。浏览器每次都会将这个事件event作为实参传进之前的响应函数。

这个对象中包含了与当前事件相关的一切信息。比如鼠标的坐标、键盘的哪个按键被按下、鼠标滚轮滚动的方向等。

获取 event 对象(兼容性问题)

所有浏览器都支持event对象,但支持的方式不同。如下。

(1)普通浏览器的写法是 event。比如:

(2)ie 678 的写法是 window.event。此时,事件对象 event 是作为window对象的属性保存的。

于是,我们可以采取一种兼容性的写法。如下:

    event = event || window.event; // 兼容性写法

代码举例:

<!DOCTYPE html>
<html>
<head lang="en"><meta charset="UTF-8"><title></title>
</head>
<body>
<script>//点击页面的任何部分document.onclick = function (event) {event = event || window.event; 兼容性写法console.log(event);console.log(event.timeStamp);console.log(event.bubbles);console.log(event.button);console.log(event.pageX);console.log(event.pageY);console.log(event.screenX);console.log(event.screenY);console.log(event.target);console.log(event.type);console.log(event.clientX);console.log(event.clientY);}
</script>
</body>
</html>

event 属性

event 有很多属性,比如:

由于pageX 和 pageY的兼容性不好,我们可以这样做:

  • 鼠标在页面的位置 = 滚动条滚动的距离 + 可视区域的坐标。

Event举例

举例1:使 div 跟随鼠标移动

代码实现:

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title></title><style type="text/css">#box1 {width: 100px;height: 100px;background-color: red;/** 开启box1的绝对定位*/position: absolute;}</style><script type="text/javascript">window.onload = function() {/** 使div可以跟随鼠标移动*///获取box1var box1 = document.getElementById("box1");//给整个页面绑定:鼠标移动事件document.onmousemove = function(event) {//兼容的方式获取event对象event = event || window.event;// 鼠标在页面的位置 = 滚动条滚动的距离 + 可视区域的坐标。var pagex = event.pageX || scroll().left + event.clientX;var pagey = event.pageY || scroll().top + event.clientY;//   设置div的偏移量(相对于整个页面)// 注意,如果想通过 style.left 来设置属性,一定要给 box1开启绝对定位。box1.style.left = pagex + "px";box1.style.top = pagey + "px";};};// scroll 函数封装function scroll() {return {//此函数的返回值是对象left: window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop,right:window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft};}</script></head><body style="height: 1000px;width: 2000px;"><div id="box1"></div></body>
</html>

举例2:获取鼠标距离所在盒子的距离

关键点:

    鼠标距离所在盒子的距离 = 鼠标在整个页面的位置 - 所在盒子在整个页面的位置

代码演示:

<!DOCTYPE html>
<html>
<head lang="en"><meta charset="UTF-8"><title></title><style>.box {width: 300px;height: 200px;padding-top: 100px;background-color: pink;margin: 100px;text-align: center;font: 18px/30px "simsun";cursor: pointer;}</style>
</head>
<body>
<div class="box"></div><script src="animate.js"></script>
<script>//需求:鼠标进入盒子之后只要移动,哪怕1像素,随时显示鼠标在盒子中的坐标。//技术点:新事件,onmousemove:在事件源上,哪怕鼠标移动1像素也会触动这个事件。//一定程度上,模拟了定时器//步骤://1.老三步和新五步//2.获取鼠标在整个页面的位置//3.获取盒子在整个页面的位置//4.用鼠标的位置减去盒子的位置赋值给盒子的内容。//1.老三步和新五步var div = document.getElementsByTagName("div")[0];div.onmousemove = function (event) {event = event || window.event;//2.获取鼠标在整个页面的位置var pagex = event.pageX || scroll().left + event.clientX;var pagey = event.pageY || scroll().top + event.clientY;//3.获取盒子在整个页面的位置// var xx =// var yy =//4.用鼠标的位置减去盒子的位置赋值给盒子的内容。var targetx = pagex - div.offsetLeft;var targety = pagey - div.offsetTop;this.innerHTML = "鼠标在盒子中的X坐标为:" + targetx + "px;<br>鼠标在盒子中的Y坐标为:" + targety + "px;"}</script>
</body>
</html>

实现效果:

举例3:商品放大镜

代码实现:

(1)index.html:

<!DOCTYPE html>
<html>
<head lang="en"><meta charset="UTF-8"><title></title><style>* {margin: 0;padding: 0;}.box {width: 350px;height: 350px;margin: 100px;border: 1px solid #ccc;position: relative;}.big {width: 400px;height: 400px;position: absolute;top: 0;left: 360px;border: 1px solid #ccc;overflow: hidden;display: none;}/*mask的中文是:遮罩*/.mask {width: 175px;height: 175px;background: rgba(255, 255, 0, 0.4);position: absolute;top: 0;left: 0;cursor: move;display: none;}.small {position: relative;}img {vertical-align: top;}</style><script src="tools.js"></script><script>window.onload = function () {//需求:鼠标放到小盒子上,让大盒子里面的图片和我们同步等比例移动。//技术点:οnmοuseenter==onmouseover 第一个不冒泡//技术点:οnmοuseleave==onmouseout  第一个不冒泡//步骤://1.鼠标放上去显示盒子,移开隐藏盒子。//2.老三步和新五步(黄盒子跟随移动)//3.右侧的大图片,等比例移动。//0.获取相关元素var box = document.getElementsByClassName("box")[0];var small = box.firstElementChild || box.firstChild;var big = box.children[1];var mask = small.children[1];var bigImg = big.children[0];//1.鼠标放上去显示盒子,移开隐藏盒子。(为小盒子绑定事件)small.onmouseenter = function () {//封装好方法调用:显示元素show(mask);show(big);}small.onmouseleave = function () {//封装好方法调用:隐藏元素hide(mask);hide(big);}//2.老三步和新五步(黄盒子跟随移动)//绑定的事件是onmousemove,而事件源是small(只要在小盒子上移动1像素,黄盒子也要跟随)small.onmousemove = function (event) {//新五步event = event || window.event;//想要移动黄盒子,必须要知道鼠标在small小图中的位置。var pagex = event.pageX || scroll().left + event.clientX;var pagey = event.pageY || scroll().top + event.clientY;//x:mask的left值,y:mask的top值。var x = pagex - box.offsetLeft - mask.offsetWidth / 2; //除以2,可以保证鼠标mask的中间var y = pagey - box.offsetTop - mask.offsetHeight / 2;//限制换盒子的范围//left取值为大于0,小盒子的宽-mask的宽。if (x < 0) {x = 0;}if (x > small.offsetWidth - mask.offsetWidth) {x = small.offsetWidth - mask.offsetWidth;}//top同理。if (y < 0) {y = 0;}if (y > small.offsetHeight - mask.offsetHeight) {y = small.offsetHeight - mask.offsetHeight;}//移动黄盒子console.log(small.offsetHeight);mask.style.left = x + "px";mask.style.top = y + "px";//3.右侧的大图片,等比例移动。//如何移动大图片?等比例移动。//    大图片/大盒子 = 小图片/mask盒子//    大图片走的距离/mask走的距离 = (大图片-大盒子)/(小图片-黄盒子)
//                var bili = (bigImg.offsetWidth-big.offsetWidth)/(small.offsetWidth-mask.offsetWidth);//大图片走的距离/mask盒子都的距离 = 大图片/小图片var bili = bigImg.offsetWidth / small.offsetWidth;var xx = bili * x;  //知道比例,就可以移动大图片了var yy = bili * y;bigImg.style.marginTop = -yy + "px";bigImg.style.marginLeft = -xx + "px";}}</script>
</head>
<body>
<div class="box"><div class="small"><img src="images/001.jpg" alt=""/><div class="mask"></div></div><div class="big"><img src="images/0001.jpg" alt=""/></div>
</div>
</body>
</html>

(2)tools.js:

/*** Created by smyhvae on 2018/02/03.*///显示和隐藏
function show(ele) {ele.style.display = "block";
}function hide(ele) {ele.style.display = "none";
}function scroll() {  // 开始封装自己的scrollTopif (window.pageYOffset != null) {  // ie9+ 高版本浏览器// 因为 window.pageYOffset 默认的是  0  所以这里需要判断return {left: window.pageXOffset,top: window.pageYOffset}}else if (document.compatMode === "CSS1Compat") {    // 标准浏览器   来判断有没有声明DTDreturn {left: document.documentElement.scrollLeft,top: document.documentElement.scrollTop}}return {   // 未声明 DTDleft: document.body.scrollLeft,top: document.body.scrollTop}
}

效果演示:

http://www.lryc.cn/news/322166.html

相关文章:

  • pycorrector检测OCR错字实践
  • RDD算子介绍(三)
  • Redis的脑裂问题
  • 【算法】雪花算法生成分布式 ID
  • FFplay使用滤镜添加字幕到现有视频显示
  • 【Python + Django】Django模板语法 + 请求和响应
  • 大数据面试总结 四
  • Spring Boot: 使用MongoOperations操作mongodb
  • PyTorch 深度学习(GPT 重译)(六)
  • MyBatis3源码深度解析(十七)MyBatis缓存(一)一级缓存和二级缓存的实现原理
  • Go --- Go语言垃圾处理
  • 力扣每日一题30:串联所有单词的子串
  • vim | vim的快捷命令行
  • 项目管理平台-01-BugClose 入门介绍
  • web集群-lvs-DR模式基本配置
  • 基于深度学习的面部情绪识别算法仿真与分析
  • C语言经典面试题目(十六)
  • 【C语言】文件操作揭秘:C语言中文件的顺序读写、随机读写、判断文件结束和文件缓冲区详细解析【图文详解】
  • JAVA八股文面经问题整理第6弹
  • pytest相关面试题
  • Keras库搭建神经网络
  • 适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼
  • Elasticsearch8搭建及Springboot中集成使用
  • asp.net在线租车平台
  • Beamer模板——基于LaTeX制作学术PPT
  • 性能测试-Jmeter中IF控制器使用
  • 华为综合案例-普通WLAN全覆盖配置(2)
  • 这里是一本关于 DevOps 企业级 CI/CD 实战的书籍...
  • 机器学习 - save和load训练好的模型
  • 【动态规划】【同余前缀和】【多重背包】[推荐]2902. 和带限制的子多重集合的数目