浏览器事件及其内置对象详解

61 阅读3分钟

什么是浏览器对象模型

BOM :Browser Object Model(浏览器对象模型),浏览器模型提供了独立于内容的、可以与浏览器窗口进行滑动的对象结构,就是浏览器提供的 API 其主要对象有:

  1. window 对象——BOM 的核心,是 js 访问浏览器的接口,也是 ES 规定的 Global 对象
  2. location 对象:提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属 性,也是 document 的对象属性
  3. navigation 对象:获取浏览器的系统信息
  4. screen 对象:用来表示浏览器窗口外部的显示器的信息等
  5. history 对象:保存用户上网的历史信息

Window 对象

windows 对象是整个浏览器对象模型的核心,其扮演着既是接口又是全局对象的角色。 常见接口有alert()、confirm()、prompt()、open()、onerror()、setTimeout()、setInterval(),还有窗口位置、窗口大小等等接口,详情可参阅segmentfault.com/a/119000001…

Location 对象

提供当前窗口中的加载的文档有关的信息和一些导航功能。既是 window 对象属性,也是 document 的对象属性。 location 对象的主要属性:hash、host、hostname、href、pathname、port、protocol、search

Navigation 对象

navigation 接口表示用户代理的状态和标识,允许脚本查询它和注册自己进行一些活动

History 对象

history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起,history 对象是用窗口的浏览历史用文档和文档状态列表的形式表示。

  • go()
  • back() === go(-1)
  • forword() === go(1)
  • length

浏览器事件模型详解

1. 详解浏览器事件捕获,冒泡

浏览器事件模型中的过程主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段。 这里先看一下这张经典的图

事件模型.jpg

这里要注意addEventListener的第三个参数, 如果为true,就是代表在捕获阶段执行。如果为false,就是在冒泡阶段进行 空口这么说可能不好理解,咱们来看一下代码。

const parent = document.getElementById("parent");
const child = document.getElementById("child");
const son = document.getElementById("son");
window.addEventListener("click", function (e) {
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
parent.addEventListener("click", function (e) {
    console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);

child.addEventListener("click", function (e) {
    console.log("child 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
son.addEventListener("click", function (e) {
    console.log("son 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
window.addEventListener("click", function (e) {
    console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

parent.addEventListener("click", function (e) {
    console.log("parent 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
child.addEventListener("click", function (e) {
    console.log("child 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
son.addEventListener("click", function (e) {
    console.log("son 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

下面是html结构 屏幕截图 2021-11-25 104135.png

当我们点击son这个元素时,运行结果如下:

image.png

因此当第三个参数为true时为事件捕获,为false时则为事件冒泡。

2. 阻止事件传播e.stopPropagation()

很多人看到e.stopPropagation很自然的想到了阻止事件冒泡,但它不仅仅阻止事件冒泡,还能阻止事件捕获,准确来说就是阻止事件的传播。

parent.addEventListener("click", function (e) {
    e.stopPropagation();
    console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);

当我们在parent节点阻止事件传播时,点击son时

image.png

只能捕获到son外面一层的parent节点。

3. 阻止默认行为e.preventDefault()

e.preventDefault()可以阻止事件的默认行为发生,默认行为是指:点击a标签就转跳到其他页面、拖拽一个图片到浏览器会自动打开、点击表单的提交按钮会提交表单等等,因为有的时候我们并不希望发生这些事情,所以需要阻止默认行为.

4. 兼容性-addEventListener

最后我们来完成一下浏览器的兼容性:

//使用类和构造函数来完成一下
class BomEvent{
    constructor(element){
        this.element = element;
    }
    addEvent(type, handler){
        if(this.element.addEventListener){
            this.element.addEventListener(type, handler, false)
        }else if(this.element.attachEvent){
            this.element.attachEvent('on' + type, function(){
                handler.call(element);
            })
        }else{
            this.element['on' + type] = handler;
        }
    }
    removeEvent(type, handler) {
        if (this.element.removeEnentListener) {
            this.element.removeEnentListener(type, handler, false);
        } else if (element.datachEvent) {
            this.element.detachEvent('on' + type, handler);
        } else {
            this.element['on' + type] = null;
        }
    }
}


// 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
function stopPropagation(ev) {
    if (ev.stopPropagation) {
        ev.stopPropagation(); // 标准w3c
    } else {
        ev.cancelBubble = true; // IE
    }
}

// 取消事件的默认行为
function preventDefault(event) {
    if (event.preventDefault) {
        event.preventDefault(); // 标准w3c
    } else {
        event.returnValue = false; // IE
    }
}