一, 事件对象 event
1.1 preventdefault() 和 returnValue 阻止默认事件
通知浏览器不要执行与事件关联的默认动作.
preventdefault() 支持 Chrome 等高级浏览器
returnValue 支持 IE6,7,8
- var box = document.getElementById('box');
- var i = 0;
- // 鼠标在 box 盒子滚动时触发
- box.onmousewheel = function(event){
- var event = event || Windows.event;
- // 能力检测, 阻止默认事件
- if(event.preventDefault){
- event.preventDefault();
- }else{
- event.returnValue = true;
- }
- this.innerhtml = '你在我身上滚动了!' + i++;
- }
1.2 stopPropagation() 和 cancelBubble 阻止事件继续传播
stopPropagation() 支持 Chrome 等高级浏览器
cancelBubble 支持 IE6,7,8
- var box1 = document.getElementById('box1');
- var box2 = document.getElementById('box2');
- var box3 = document.getElementById('box3');
- box1.onclick = function(){
- alert('box1');
- }
- box2.onclick = function(event){
- alert('box2');
- // 阻止事件继续传播, 能力检测
- if(event.stopPropagation){
- event.stopPropagation();
- }else{
- event.cancelBubble = true;
- }
- }
- box3.onclick = function(){
- alert('box3');
- }
二, BOM
浏览器对象模型 (browser object model)
2.1 卷动事件
当窗口无论向上向下卷动的时候, 比如键盘↓了, 滚动鼠标滚轮, 拖拽滚动条, 都会触发这个事件.
- Windows.onscroll=function(){
- }
2.2 窗口的宽度和高度
认识一个对象:
document.documentElement |
就是页面 document, 想要得到窗口的宽度和高度, 不是 Windows 对象, 而是 document 对象, 所以:
document.documentElement.clientWidth document.documentElement.clientHeight |
但是去掉页面 DTD, 或 IE678 浏览器中, 把下面的语句当做浏览器窗口的宽度和高度
document.body.clientWidth document.body.clientWidth |
所以兼容语法:
document.documentElement.clientWidth || document.body.clientWidth; document.documentElement.clientHeight || document.body.clientWidth; |
2.3 窗口的卷动值
兼容语法:
document.documentElement.scrollTop || document.body.scrollTop |
兼容所有浏览器
document.documentElement.scrollTop |
兼容不写 DTD 的情况下:
document.body.scrollTop |
三, 鼠标位置
当我们给某一个盒子添加鼠标事件监听时 (click,mouseover,mouseenter,mouseout 等事件), 都一定会有以下四组值:
event.pageX event.pageY event.screenX event.screenY event.clientX event.clientY event.offsetX event.offsetY |
event.pageY 表示鼠标指针, 到页面顶端的距离. IE6,7,8 不兼容
event.screenY 表示鼠标指针, 到屏幕顶端的距离
event.clientY 表示鼠标指针, 到视口顶端的距离 (视口就是当前可视窗口)
event.offsetY 表示鼠标指针, 到盒子顶端的距离
规律:
1, 当页面没有卷动的时候, pageY 一定等价于 clientY. 或换句话说 pageY 等价于 clientY + 页面卷动的值 scrollTop.
2,IE678 不兼容 pageX,pageY
3,offsetX/Y 会被儿子影响.
offsetX/Y 指的不是距离你监听的那个盒子左上角的距离, 而是指的你现在鼠标指针所在位置到此时最内层盒子左上角的距离.
四, 盒子位置
任何一个元素都有 offsetParent 属性, 和 offsetLeft,offsetTop 属性
4.1 计算盒子在页面中的净位置
现在我们就可以用 offsetParent 和 offsetTop/Left 计算一个元素的净位置了, 是一个迭代的过程.
xiaoming 的净位置: xiaoming.offsetTop + xiaoming.offsetParent 的 xiaoming.offsetParent.borderTop ...
由于 IE8 很特殊, 所以我们迫切的需要知道浏览器是不是 IE8. 所以使用:
Windows.navigator.userAgent
来检测浏览器的版本.
|
|
var ie8 = window.navigator.userAgent.indexOf("MSIE 8.0") != -1; |
下面的函数就是得到一个元素在页面上的总净位置:
- function offset(o){
- // 初始值
- var result = {
- "top" : o.offsetTop,
- "left" : o.offsetLeft
- }
- // 判断浏览器是不是 IE8
- var isIE8 = Windows.navigator.userAgent.indexOf("MSIE 8.0") != -1;
- // 循环迭代, 寻找父亲
- while(o = o.offsetParent){
- // 计算后的边框的值
- if(Windows.getComputedStyle){
- var borderTop = parseInt(getComputedStyle(o)['border-top-width']);
- var borderLeft = parseInt(getComputedStyle(o)['border-left-width']);
- }else{
- var borderTop = parseInt(o.currentStyle['borderTopWidth']);
- var borderLeft = parseInt(o.currentStyle['borderLeftWidth']);
- }
- // 验证一下, 万一 borderTop 是 undefined 或 NaN, 此时修正为 0
- if(isNaN(borderTop)){
- borderTop = 0;
- }
- if(isNaN(borderLeft)){
- borderLeft = 0;
- }
- // 如果浏览器版本不是 IE8 那么就加上边框, 如果是 IE8 就不需要加边框, 抛出自己
- !isIE8 && (result.top += borderTop);
- !isIE8 && (result.left += borderLeft);
- result.top += o.offsetTop;
- result.left += o.offsetLeft;
- }
- return result;
- }
4.2 曲线救国得到鼠标在盒子中的位置:
- var box = document.getElementById("box");
- var result = document.getElementById("result");
- // 监听父亲鼠标移动的时候, 鼠标指针的 offsetX 值和 offsetY 值
- box.onmousemove = function(event){
- var event = event || Windows.event;
- var x = event.pageX - getAllOffset(box).left;
- var y = event.pageY - getAllOffset(box).top;
- result.innerHTML = x + "," + y;
- }
由于 IE 低版本不兼容 pageX 和 pageY, 所以用 clientX/Y 加上卷动值:
- var box = document.getElementById("box");
- var result = document.getElementById("result");
- // 监听父亲鼠标移动的时候, 鼠标指针的 offsetX 值和 offsetY 值
- box.onmousemove = function(event){
- var event = event || Windows.event;
- // 曲线救国!!!! 得到窗口卷动的值
- var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
- var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
- // 鼠标的 offsetX,offsetY 等于视口的值, 加上卷动值减去净位置.
- var x = event.clientX + scrollTop - getAllOffset(box).left;
- var y = event.clientY + scrollLeft - getAllOffset(box).top;
- result.innerHTML = x + "," + y;
- }
五, 拖拽
5.1 在页面上拖拽
页面上的元素, 能够被鼠标拖拽. 整体思路:
1 当鼠标在 img 上按下去的时候, 注册 document 的鼠标移动事件监听; 反之, 当鼠标在屏幕任何位置抬起的时候, 剥夺 document 的鼠标移动事件监听.
2 为了让鼠标能够一直按住图片的同一个位置, 所以要在 mousedown 的一瞬间记录误差 (见下图).
- var img = document.getElementsByTagName('img')[0];
- // 鼠标指针在图片上按下的时候
- img.onmousedown = function(event){
- var event = event || Windows.event;
- // 记录误差, 目的是当我按住 baby 的脑门子拖拽的时候, 鼠标指针一直在脑门子上.
- var dx = event.offsetX;
- var dy = event.offsetY;
- // 注册新的事件
- // 在 document 上移动的时候, 让 img 跟随鼠标
- document.onmousemove = function(event){
- var event = event || Windows.event;
- // 移动的时候 top 值等于当前的鼠标指针位置减去开始的时候的误差
- var x = event.clientX - dx;
- var y = event.clientY - dy;
- img.style.left = x + "px";
- img.style.top = y + "px";
- // 这个 return false 可以解决 IE8 的内置事件
- return false;
- }
- // 这个 return false 可以解决 IE8 的内置事件
- return false;
- }
- // 鼠标指针在任何位置抬起的时候, 删除 document 上的 move 监听
- document.onmouseup = function(){
- document.onmousemove = null;
- }
5.2 在容器中拖拽
图片在父级容器中拖拽的时候, 不仅仅是给图片加了一个限制区域, 图片的 top,left 参考点是父盒子左上角, 鼠标指针的位置点就不一致. 图片的 top,left 起点是 A, 而鼠标指针 clinetX,Y 参考点是 B 点.
大家参考点就不一样了.
方法: 只要把它们的坐标统一就可以了, 所以我们需要得到鼠标指针相对于盒子的坐标位置, 此时需要使用曲线救国, 因为 offsetX/Y 会被儿子影响.
- var img = document.getElementsByTagName('img')[0];
- var box = document.getElementById('box');
- // 得到盒子的净位置
- var boxoft = offset(box).top;
- var boxofl = offset(box).left;
- console.log(boxoft,boxofl)
- // 鼠标指针在图片上按下的时候
- img.onmousedown = function(event){
- var event = event || Windows.event;
- // 记录误差, 目的是让我按住 baby 的脑门拖拽的时候, 鼠标指针一直在脑门上
- var dx = event.offsetX;
- var dy = event.offsetY;
- // 鼠标按下, 然后执行鼠标移动时间, 接着在 document 上移动, 让 img 跟着移动
- document.onmousemove = function(event){
- var event = event || Windows.event;
- // 曲线救国!!!! 得到窗口卷动的值
- var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
- var scrollLeft = document.documentElement.scrollLeft|| document.body.scrollLeft;
- // 鼠标的 offsetX,offsetY 等于视口的值, 加上卷动值减去净位置
- // 移动的时候 top 值等价于鼠标指针位置减去开始按下的误差
- var X = event.clientX + scrollLeft - boxofl - dx;
- var Y = event.clientY + scrollTop- boxoft - dy;
- console.log(X,Y)
- // 验收
- if(X> 300){
- X = 300;
- }else if(X <0){
- X = 0;
- }
- if(Y> 300){
- Y = 300;
- }else if(Y <0){
- Y = 0;
- }
- img.style.left = X+'px';
- img.style.top = Y+'px';
- // 这个 return false 可以解决浏览器内置事件
- return false;
- }
- }
- // 在鼠标指针任何位置抬起的时候, 移除 document 上的 move 事件监听
- document.onmouseup = function(){
- document.onmousemove = null;
- }
5.3 放大镜效果
和刚刚的拖拽不一样, 鼠标指针不需要按下了, 所以逻辑变得简单了.
放大镜的放大原理: 不是真的放大, 只是当左边小放大镜移动的时候, 右边的大图按比例移动, 形成放大的感觉.
比例问题:
小图盒子 350 宽高, 放大镜 175 宽高
大图盒子 400 宽高, 图片 800 宽高
这里暗含了两个 1:2, 比例一定要相同, 如果比例不相同, 放大镜放大感觉就不一样了, 无法看全.
六, 鼠标滚轮事件
页面中经常有鼠标滚轮事件, 比如做一个内置有纵向滚动条的盒子
Chrome 和 IE 各个版本浏览器都支持 onmousewheel 事件, 表示鼠标滚轮滚动的时候触发, 火狐不支持这个事件, 它支持的是自己的 DOMMouseScroll 事件, 我们不需要进行能力检测, 因为所有的浏览器遇见别人添加监听的方法都不报错 (静默).
- var box = document.getElementById('box');
- // 除了火狐浏览器之外, 都支持以下这种监听滚轮事件
- box.onmousewheel = mousewheel;
- // 火狐独有的, 必须用 DOM2 级添加监听
- box.addEventListener('DOMMouseScroll',mousewheel,true);
- // 事件处理函数
- function mousewheel(){
- alert('滚动了!!!');
- }
鼠标滚轮事件的 event 对象有属性 wheelDelta, 火狐是 detail 属性, 可以反映你的滚轮方向和力度
非火狐向上 120(力度越大数字越大), 火狐向上是 - 3
非火狐向下 - 120(力度越大数字越大), 火狐向上是 3
所以要进行兼容性处理, 把它们的值统一为: 1 和 - 1
- box.onmousewheel = mousewheel;
- // 火狐独有的, 必须用 DOM2 级添加监听
- box.addEventListener('DOMMouseScroll',mousewheel,true);
- // 事件处理函数
- function mousewheel(event){
- // 进行方向的能力检测, 由于火狐和大家不一样, 用 if 分开判断
- if(event.wheelDelta){
- // 非火狐
- // if(event.wheelDelta> 0){
- // var direction = 1;
- // }else{
- // var direction = -1;
- // }
- var direction = event.wheelDelta> 0 ? 1 : -1;
- }else{
- // 火狐
- // if(event.detail> 0){
- // var direction = -1;
- // }else{
- // var direction = 1;
- // }
- var direction = event.detail> 0 ? -1 : 1;
- }
- console.log(direction)
- }
上一篇文章 DOM2 级小测试的正确答案: EFGHIBCD
解释:
1,DOM0 级只能添加到冒泡阶段
2,DOM0 级事件同名的会覆盖
3,true 表示捕获, false 表示冒泡, 先捕获, 后冒泡
4,DOM2 级的不会覆盖, 先写的先执行
5,DOM2 级最内层的不区分冒泡和捕获, 谁先写谁执行, 无论是 DOM0 还是 DOM2.
ps: 尽量让它越来越规范, 前期的文章都是本人的学习时的笔记整理, 希望看完后可以指点一二, 提提意见多多交流;
笔记流程: HTML>CSS>JavaScript>jQuery>html5/css3 > 移动端 > Ajax > 面向对象 > canvas>Node.JS>es678>vue>react > 小程序 > 面试问题
意见请留言, 邮箱: scarf666@163.com
来源: https://www.cnblogs.com/rope/p/10610260.html