08|BOM

对应的ECMAScript是JavaScript的核心这是毋庸置疑的,但是如果说要在Web中使用JavaScript的话,对应的BOM的使用就非常的重要了!

  • BOM提供了很多对象用于访问浏览器的功能,这些对象在浏览器上的已存在,很大程度上是因为提供了与浏览器的互操作性!
  • W3C为了把浏览器中JavaScript最基本的部分标准化,BOM的主要部分已经纳入了HTML5规范中!

01|Window对象

Window是BOM的核心对象,表示浏览器的实例.浏览器中window有双重角色

  • 通过JavaScript访问浏览器窗口的一个接口
  • ECMAScript规定的Global对象,网页中定义的任何一个对象都是以window作为全局对象的!
01|全局作用域

因为window对象扮演着ECMAScript中Global对象的角色,因此在全局作用于内声明的变量和函数都会变成window对象的属性和方法,通过简单的例子就能很好的说明

let age = 20;
function sayAge(){console.log(this.age);}
console.log(window.age);//20
sayAge();//20
window.sayAge();//20

其实通过以上的例子就能很清楚的明白:

  • age变量作为window对象的属性存在!
  • sayAge是作为window的方法存在!

但是定义全局变量和在window对象上定义属性还是存在一定的差别的:

  • 全局变量是不能够delete操作符删除
var age = 22;
window.color = "red";
delete window.age;
delete window.color;
console.log(window.age, window.color);//22 undefined

不能被删除的原因如下:

  • var语句添加的window属性有一个configurable特性,定义出来的特性值为false因此不能够被删除!

以下还有一点是值得我们注意的:

  • 尝试访问未被声明的变量会抛出对应的错误,但是通过查询window对象可以知道某个未被声明的变量是否存在!
// 这里会抛出错误,因为oldValue未被定义
var newValue = oldValue;

// 这里不会抛出错误,因为经过了以此window属性查询
var newValue = window.oldValue;//undefined
02|窗口关系及框架

其中如果说在页面中包含框架的话,那么对应的每一个框架中都会有自己的window对象,并且保存在frames集合中!

对应的通过框架集和访问window的方式有几种?

  • 通过 索引 从左到右从上到下进行访问
  • 通过框架名称进行访问

其实我们可以通过对应的代码实例解释这一点:



  
    
    
    
    Document
  

  
    
      
      
        
        
      
    
  

以上代码的结构还是比较好理解的:

  • 一个框架集,一个框架居上,两个框架居下!

问题来了,如果说访问上面框架的方式如何操作?

window.frames[0];//topFrame
window.frames["topFrame"];//topFrame

虽然说上面两种方式都是可以完成的,但是不推荐这么做! window对象都是指向框架当前实例

由此我们可以介绍一个对象,top对象:

  • 时钟指向最高或者最外层的框架,也就是所谓的浏览器窗口!

这样一来我们可以这么做:

top.frames["0"];//topFrame
top.frames["topFrame"];//topFrame

对应的还有另外一个对象,一看你就知道大体意思,parent对象:

  • parent时钟指向当前框架对象的直接上层框架对象
  • 因此可能等于top对象,没有框架存在的情况下parent指向最外层的浏览器窗口其实等于top
    
      
      
        
        
      
    

我们试想一下,如果说对应的代码存在于topFrame中的话,如果说是需要求出对应的parent对象的话,此时topFrame中的parent不就等同于top对象吗?

最后介绍到了对应的self对象:

  • self始终指向window对象,对应的目的也就是为了和parent和top对象区分开来,因此不包含别的类型的值!

对应的与此同时,以上三个对象指向的都是window对象,但是是不同层次的window对象,因此可以将不同的层次的window连缀起来使用!

但是另外需要注意的是:

  • 使用框架情况下浏览器会存在多个Global对象!
  • 在框架中定义的全局属性也因此会变成window对象的属性!
  • window对象中包含原生类型因此也包含原生类型的构造函数 构造函数一一对应但是并不相等!
03|窗口位置

对应的用来确定window对象位置的属性和方法有很多,IE,Opera,Safari和Chrome都提供了screenLeft和screenTop属性,用来表示窗口相对于屏幕的左边和上边的位置!

其中除了Opera不能够使用screenX和screenY来获取准确的位置之外,FireFox可以通过这两个属性获取和screenLeft和screenTop相同的值! 除此之外对应的几个浏览器是支持这两个属性的!

因此我们在跨浏览器开发中的时候,可以通过判断属性来在不同的浏览器使用不同的API获取准确的位置属性值!

但是与此之外有些地方还是需要我们注意的,就是在IE和Opera中,如果说window是最外层的对象并且浏览器窗口紧贴最上端,那么通过screenTop获取到的值就是页面可见区域上方浏览器工具栏的像素高度! 但是如果说在Safari和Chrome以及FireFox中的话对应的值则为0!

但是问题又来了,就是Chrome和FireFox和Safari始终返回页面中每个框架的top.screenX和top.screenY,即使设置了对应的外边距发生了偏移的情况下还是会返回相同的位置值! 但是对应的IE,Opera则会给出屏幕边界精确的坐标值!

这其实也就引发了一些问题,就是在跨浏览器开发的时候,无法获得窗口左边和窗口右边的精确坐标值! 但是我们在对于位置的移动上面确实非常的精确! 其中有两个API:

  • moveTo:接收新坐标的X和Y坐标值
  • moveBy:接受的是水平和垂直方向上移动的像素数!
window.moveTo(0,0);//将窗口移动到屏幕的左上角
window.moveBy(0,100);//窗口向下移动100像素
window.moveTo(200,300);//将窗口移动到X:200,Y:300
window.moveBy(0,-50);//窗口向上移动50像素

但是对应的该方法在浏览器中可能会被禁用,Opera和IE7及以上的版本中默认就是被禁用的,与此同时,两个方法都是不适用于框架的,只能够对外层的Window对象使用!

04|窗口属性

跨浏览器确定窗口大小并不是简单的事情,IE9+,FireFox和Safari以及Opera和Chrome为此提供了4个属性用来确定:

  • innerWidth:容器中页面视图区的大小(去除边框的宽度)
  • innerHeight:
  • outerWidth:除了Opera中表示视图容器的大小,别的浏览器则是返回浏览器窗口本身的尺寸!
  • outerHeight:

对应的在Chrome中四个属性则是返回的Viewport的大小! 而在别的几个浏览器中要想获取视口的宽度和高度则是需要使用以下代码获取:

let viewportWidth = document.documentElement.clientWidth;
let viewportHeight = document.documentElement.clientHeight;

对应的混杂模式需要将对应的 documentElement 替换成为 body Chrome不管是什么模式下两种模式都能够获取到视口的大小!

虽然说不能够获取窗口本身的大小,但是确实可以获取页面视口的大小!

let pageWidth = window.innerWidth;
let pageHeight = window.innerHeight;
if(typeof pageWidth !== "number"){
    if(document.compatMode === "CSS1Compat"){
            pageWidth = document.documentElement.clientWidth;
            pageHeight = document.documentElement.clientWidth;
     }else{
            pageWidth = document.body.clientWidth;
            pageHeight = document.body.clientHeight;
     }
}
  1. 我们先通过window.innerWidth拿到对应视口的值,并且判断该值的类型是否是number
  2. 之后如果说是不为number类型的话再通过 document.compatMode 通过稳当的适配模式确定是否为标准的模式!
    1. 如果为标准模式则使用:**documentElement **document.documentElement.clientWidth/clientHeight
    2. 如果不是为标准模式则使用:body document.body.clientWidth/clientHeight

简而言之,由于对应的桌面浏览器存在这些差异,我们最好是检测以下用户是否在使用移动设备,然后再决定使用哪种属性

其中介绍两个API,调整窗口大小的API,都是接收两个参数:

  • resizeTo: 接收浏览器窗口的新的宽度和高度
  • resizeBy: 接收新窗口与旧窗口的宽度之差和高度之差
05|导航和打开窗口

使用window.open既可以导航到一个特定的URL或者说打开一个新的浏览器窗口!

对应的接收四个API:

  • 需要加载的URL
  • 窗口目标
  • 特性字符串
  • 表示新页面是否取代浏览器历史记录中当前加载页面的布尔值!

其中对应的第二个参数如果说带有框架名称的话,就会在该框架的窗口上加载该URL!

  1. 弹出窗口

如果第二个参数并不是一个已经存在的窗口或者说框架的话

  • 那么就会根据第三个参数所谓的特性字符串创建一个新的窗口或者说标签页!
  • 如果说没有第三个参数就会打开一个拥有全部默认设置的新浏览器窗口
window.open("github.com/probedream","wroxwindow","height=400,height=400,top=10,left=10,resizable=yes");

像以上这段代码的意思其实比较好理解,浏览器默认打开一个400400的页面并且是可以调整窗口的,距离屏幕左边和上边10px素的窗口!*

但是对应的通过window.open方法会返回一个新窗口对象的引用,和window对象大致相似,但是对应的我们可以对其进行更多的控制!

可以使用resizeTo和move对其窗口进行设置和位置调整! 还可以通过 reference.close() 关闭弹出的窗口 浏览器的主窗口在没有经过用户的允许下面是不能关闭的! 就算是调用了对应的close方法之后关闭了该窗口,但是对应的引用还是存在的! 我们可以通过 reference.closed来确定该窗口是否被关闭 仅此而已!

对应的 reference.opener 保存着打开它的原始窗口对象,指向着调用window.open的窗口或者说框架!

其中如果说对应的两个标签页不需要进行通信的话,可以将 reference.opener=null 将标签间的联系切断!

之后就讲到了浏览器的安全限制相关的内容,主要是广告弹窗达到了肆无忌惮的程度,因此不同的浏览器之间会有对应的限制,对浏览器弹窗配置方面增加限制!

那么如何检测当前浏览器是否屏蔽了弹窗没有呢?

let blocked = flase;
try{
    let worxWindow = window.open("github.com/probedream","_blank")
    if(worxWindow === null){
        blocked = true;
    }
}catch(error){
    blocked = true;
}
if(blocked){alert("The popup was Blocked!");}

通过我们手动调用打开新的窗口之后,可能浏览器拓展会阻止弹窗此时可能会抛出对应的一场因此我们的代码是写在trycatch中,等当前的代码为null的时候改变状态或者说捕获到了错误的时候改变状态为true!

一旦blocked为true的话,则弹出对应的会话提示! 该弹窗已经被屏蔽掉了!

06|间歇调用和超时调用

间歇调用就是所谓的setInterval,超时调用便是setTimeout,对应的都是接收两个参数,并且也是返回对应的标识!

  1. 第一个参数是函数
  2. 第二个参数表示时间戳,单位是ms毫秒 1s=1000ms 表示过多久时间把当前任务添加到队列中去!
  3. 返回的是间歇调用/超时调用的标识ID,用来清除对应的调用!
    1. 一个为clearTimeout
    2. 一个为clearInterval

虽然说对应的第一个参数可以传递JavaScript代码的字符串,但是不推荐,因为会导致性能丢失!

在我们使用间歇调用和超时调用的时候,会添加到一个任务队列中执行,只有等队列里面为空才会执行!按照顺序执行!

02|location对象

location对象是最有用的BOM对象之一,提供了与当前窗口中加载的文档有关的信息,还提供了一些导航功能,对应的他还是一个比较特殊的对象,对应的既是window对象的属性也是document对象的属性!

对应的location对象的属性如下所示:

  • hash
  • host
  • hostname
  • href
  • pathname
  • port
  • protocol
  • search
01|查询字符串参数

尽管location.search可以拿到对应的URL末尾的所有内容! 但是对应的不能够一个个访问其中的每个查询字符串参数

我们自己手写函数来解决这个问题:

let getQueryStringArgs = ()=>{
    let queryString = location.search.length > 1 ? location.search.substring("1") : "";
    let queryData = {};
    let items = queryString.length ? queryString.split("&") : [];
    for(let i=0;i

对应的简化版的:

let getQueryStringArgs = ()=>{
    let queryString = location.search.length > 1 ? location.search.substring("1") : "";
    let queryData = {};
    let items = queryString.length ? queryString.split("&") : [];
    for(let [index,variable] of items.entries()){
        let item = variable.split("=");
        queryData[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
    }
    return queryData;
}

这样的方法用来获取对应的查询参数就方便很多了!

02|位置操作

对应的location对象是可以通过很多方式来改变浏览器的位置的,首先最常用的方式就是通过assign方法来做!其次是通过location.href或者window.location进行操作对应的效果是一样的!

location.assign("https://wwww.baidu.com");
location.href = "https://www.baidu.com";
window.location = "https://www.baidu.com";

但是对应的问题出现在,使用修改URL进行的位置变化其实是可以通过后退键返回的,我们要禁用后退键! 我们可以使用replace方法进行位置的跳转而不是使用window.location或者说location.assign方法!

还有介绍了两个方法分别是load和reload方法对应的是加载和重新加载!

location.reload();//重新加载 有可能从缓存中加载
location.reload(true);// 重新加载 从服务器重新加载
03|Navigator对象

navigator已经成为识别客户端浏览器的事实标准!对应的每个navigator都有自己的一套属性!

文中的内容有点多这里就不进行详细介绍了:

for(let item in navigator){console.log(item);}
04|检测插件

其中对应的通过navigator的plugins属性获取对应的数组来判断是否存在某个插件!

我们就写一个比较常见的检测plugins插件的方法吧!

let hasPlugin = name=>{
    name = name.toLowerCase();
    for(let i = 0;i -1){
            return true;
        }
    }
    return false;
}
console.log(hasPlugin(onetab));

因为不同的浏览器实现检测插件的方式不同,IE需要ActiveXObject类型还需要配合对应的COM标识符!

05|注册处理程序

对应的介绍了两个方法一个为 registerContentHandlerregisterProtocolHandler的方法,对应的功能就是实现 让一个站点指明他可以处理的特性类型的信息

  • registerContentHandler:
    • 第一个参数:处理的MIME类型
    • 第二个参数为页面的URL
    • 第三个参数应用程序的名称

如果说我们需要指定站点为可以处理RSS源的处理程序:

navigator.registerContentHandler("application/rss+xml","http://www.somereader.com?feed=%s","Some Reader");
  • registerContentHandler:
    • 第一个参数为处理的协议
    • 第二个参数为处理该协议URL
    • 第三个参数为应用程序的名称
06|screen对象

screen对象表明客户端的能力,对应的包括浏览器窗口外部的显示器信息,还有像素宽和高! 对应的不同的浏览器包含的screen属性不同!

for(let i in screen){console.log(i);}

通过遍历该对象获取screen对象中的属性!

07|history

history也就是所谓的历史,就是对网页的浏览记录做操作! 开发人员无法知道用户的浏览过的URL,但是可以通过操作API进行前进和后退!

对应的方法常见的有:

  • go :
    • 如果为数字的话 前进n页 为负数的话后退n页
    • 为对应的字符串的话 跳转到当前对应的网址
  • back 后退
  • forward 前进
  • history.length 获取历史记录的数量!

涉及到的BOM的内容其实还是蛮多的,但是都是值得我们好好学习的,如果你有好的建议欢迎在评论区与我交流!

你可能感兴趣的:(08|BOM)