javascript之有趣的【BOM】深入学习

Bom知识不难,就是东西比较多,耐心理解此篇文章,会让你收获满满。相信自己,认真看完。`

BOM(全称:BrowserObjectModel)浏览器模型

有很多小白同学一听到Bom这个词,瞬间晕倒,根本不懂到底是什么,看以上的全称来翻译,就是浏览器中的东西,我们前端浏览器的主要方式在开发中来讲,核心就是window。很多同学还听过一个词叫Dom,初学者来讲,这两个很容易让人有“跳楼”的想法,其实学好了这两个,js中也就明白了一半的知识。

先说说这两个的区别,学过html的同学都知道,html主要是使用标签,标签在页面中其实就是以节点的方式存在的,比如各种嵌套,就是分了很多的标签节点,然后才能开发出想要的布局页面。那么Dom其实就是在用js控制这些标签节点,然后操作各种事情。比如用js创建一个a标签,就可以说创建了一个节点;再或者,用js写出a标签的样式,就可以说控制了节点的样式。完全可以这样理解,但心里要明白,这个标签是js创建出来的,js控制了Dom节点,而非html写出来的,两者是有本质上的区别。那么Bom是来操作浏览器窗口的,比如你alert出一个弹窗,就是在操作Bom,你打开一个新的窗口,也是在操作Bom。所以理解为Bom是操作浏览器window的,这样两者的区别就很显然了。

--window对象和全局作用域--

bom的核心对象是window,它表示浏览器的一个实例。在浏览器中,window对象有双重角色,即是javascript访问浏览器窗口的一个接口,又是ECMAscript规定的Global(全局)对象。因此所有在全局作用域中声明的变量、函数都会变成window对象的属性和方法。如:

var name = 'xiaoming';
function lookName(){
  alert(this.name);
}

console.log(window.name);  //xiaoming
lookName();                //xiaoming
window.lookName();         //xiaoming

从上看出,我们在全局作用域下定义的name,被归在了window对象下,所以可以通过window.name访问,也可以用通过window.lookName()访问函数lookName()。由于是全局作用域,所以this指向了window对象,那么this.name自然也能访问到。

delete操作符

️注意:全局定义的属性不能用delete操作符删除,在window对象上直接定义的属性可以。

var name1 = 'xiaoming';  // 全局定义name1
window.name2 = 'xiaoli'; // 在window上定义name2
console.log(delete window.name1);   // 由于全局定义的不能用delete删除,所以会返回false
console.log(delete window.name2);   // window上的可以被delete删除,会返回true

--window窗口--

窗口位置:

在各个浏览器当中,IE、Safari、Opera、Chrome 都提供了位置属性:screenLeftscreenTop
分别表示:“浏览器窗口相对于屏幕左边和上边的位置”。
但是火狐 (firefox) 却提供了不同的属性:screenXscreenY来表示上述位置。
更有趣的是欧朋浏览器(Opera),四个属性都提供,但screenX、screenY 和 screenLeft、screenTop属性却不对应,所以不建议在Opera中使用。

我们可以用自己的电脑试着打印一下你的窗口位置(用Chrome)举例:

var left = window.screenLeft;
var top = window.screenTop;
console.log(left);
console.log(top);

但是这个案例并不能跨浏览器兼容,因为刚才提到过,firefox不支持screenLeftscreenTop,所以我们要跨浏览器兼容,需要做个判断:

var left = (typeof window.screenLeft == 'number') ? window.screenLeft : window.screenX
var top = (typeof window.screenTop == 'number') ? window.screenTop : window.screenY

这样使用一个三目运算就可以兼容firefox来获取浏览器窗口的位置。

窗口大小:

如果需要跨浏览器兼容,来确定一个窗口的大小也略有不同。

IE9+、firefox、Safari、Opera、Chrome都提供了4个属性: innerHeightinnerWidthouterHeightouterWidth
这四个属性均可以返回浏览器窗口大小,不过略有不同:

IE9+、firefox、Safari中,outerHeightouterWidth返回浏览器窗口本身的尺寸。
Opera、Chrome中,innerHeightinnerWidth表示窗口容器的大小;outerHeightouterWidth表示的是视图区域的大小。

javascript之有趣的【BOM】深入学习

IE、firefox、Safari、Opera、Chrome中,有两个相同的方法均提供了页面可视窗口的大小,分别为:

document.documentElement.clientHeight // 视图区域的高度
document.documentElement.clientWidth // 视图区域的宽度

上述图片的视图区域宽高,就是用此方法打印出来的。
不过,这两个方法必须要在标准模式css1Compat下才有效;混杂模式BackCompat下需要通过下边方法才能有效获取宽高信息:

document.body.clientHeight // 视图区域的高度
document.body.clientWidth // 视图区域的宽度

两种模式我们可以用console.log(document.compatMode == "CSS1Compat" ? "当前处于标准模式" : "当前处于混杂模式")来判断,现在目前几乎都是标准模式了。(如果不清楚两种模式的区别,推荐一篇简书中的文章:https://www.jianshu.com/p/4aa37da38b81 ,看起来还不错。)

所以,要跨模式获取可视区域的窗口大小,需要进行判断当前的模式:

// 判断方法:document.compatMode

if(document.compatMode == 'css1Compat'){
  var h = document.documentElement.clientHeight
  var w = document.documentElement.clientWidth 
}else{
  var h = document.body.clientHeight
  var w = document.body.clientWidth 
}

console.log(h)
console.log(w)

// 这样就获取到了当前可视区域的大小

当然,移动端开发也有窗口的大小,如果你沉迷于技术上的钻研,推荐一位移动开发咨询师写的文章:https://quirksmode.org/mobile/viewports2.html 全英文版,如果你的英语不好,可以使用浏览器编译出中文,也能理解到大概的含义。

--导航和打开窗口--window.open()

window.open()方法即可以导航到一个特定的URL,也可以打开一个新的浏览器窗口。

window.open()可接收4个参数:1.url地址 2.窗口目标target 3.窗口设置的字符串 4.取代当前页面的布尔值,分别说一下:`

url地址:就是要加载的浏览器地址。
窗口目标:类似与a标签中的target属性。如果当前有与target相同的窗口,则会在当前窗口加载url。当然,我们也可以传递特殊的名称,例如经常见到的 _blank_top_self_parent
窗口设置的字符串:设置这个的前提是我们加载的url就跳转到一个新的窗口,而不是在当前窗口加载,那么这个参数就很有趣了。我们可以随意设置新窗口的大小,和弹出的位置。如设置宽500,高500的正方形窗口,也可以设置窗口上边坐标与左边的坐标。但要记住,这个参数是以字符串的形式体现的。我们以博主的博客地址https://yq.aliyun.com/u/villin举例:

window.open('https://yq.aliyun.com/u/villin','_blank','width=500,height=500,top=100,left=100')

可以复制这个代码到你的浏览器,会看到弹出一个博客窗口,并且窗口宽高为500,位于屏幕下移100像素,左移100像素。
同时我们还可以通过resizeTo()moveTo()两个方法再次操作新打开窗口的大小和位置,也可以通过close()方法关闭窗口:

var winURL = window.open('https://yq.aliyun.com/u/villin','_blank','width=500,height=500,top=100,left=100');
// 再次调整大小
winURL.resizeTo(500,300);  // resizeTo()接收两个参数,一个是宽度,一个是高度,当窗口打开时,再次调整为宽500px,高300px。
// 再次移动位置
winURL.moveTo(200,200);    // moveTo()接收两个参数,一个是距屏幕top的距离,一个是距屏幕left的距离。
// 3s后关闭窗口
setTimeout(() => {
  winURL.close()
},3000)                    // setTimeout方法:等待一定时间后才开始执行某个任务,两个参数,第一个是方法,第二个是等待时间。

当然,这个参数不仅仅只有这四个属性,还有location,menubar,resizable,scrollbars,toolbar等等。都代表着窗口所显示的菜单栏或其他状态栏,不过目前用到的也比较少,因为每个浏览器兼容性并不一致。
取代当前页面的布尔值:这个参数只有在不打开新的窗口下使用,使用当前页面的浏览历史记录,然后打开新的浏览页面。

--超时调用和间歇调用--setTimeout()/setInterval()

setTimeout()超时调用:等待特定时间后,执行某个方法。两个参数,一个是要执行的代码方法,一个是要等待执行的时间(毫秒mm):

setTimeout(function(){
alert('hello,world')
},2000) // 等待2秒后,弹出hello,world

setTimeout(()=>{
alert('hello,world')
},2000) // 也可以使用箭头函数

setTimeout("alert('hello,world')") // 也可以直接写成字符串方法,不过本方法不推荐使用。

```setInterval()```**间歇调用:**```每间隔一段时间后,都执行某个方法```。两个参数,一个是要执行的代码方法,一个是要等待执行的时间(毫秒mm):

间歇调用与超时调用的方法一样,就是间歇调用是重复不断的执行某个方法,所以可能会某个执行程序还没执行完,就再次的调用了该方法,一般再我们开发中,不到不得已不建议用这个方法。要是用此方法,那么要在页面关闭前,一定要用```clearInterval()```清空这个方法,防止报错:

console.log('hello,world')
},1000) // 每隔一秒就打印一次hello,world

clearInterval(id) // 在页面执行后,记得清空这个方法



**--系统对话框--**

浏览器通过三种对话框方式向用户展示消息:
```1.alert() 带有一个确认按钮的弹出框```  
```2.confirm() 带有一个确认按钮和一个取消按钮的弹出框```  
```3.prompt() 带有输入框的对话弹出框,两个参数:一个是提示信息,一个是输入框默认文本```  

alert()代码:

alert('请输入您的昵称')

显示如下:
![image](https://yqfile.alicdn.com/77c4e3f4cefc7ea752eb7f9275a75a5c80aafb9e.png)

confirm()代码:

var con = confirm('您输入的昵称为:villin')
if(con){
console.log('用户点击了确定')
// 在此可以写确定后的执行代码
}else{
console.log('用户点击了取消')
// 在此可以写取消后的执行代码
}
// 这样可以得到用户输入的返回值,记住,在chrome中,var后边定义的变量不能为name,本人尝试后得到的结果不准。


显示如下:
![image](https://yqfile.alicdn.com/474524aa61c0b2f905a858379cf17179a8be63a9.png)

prompt()代码:

var con = prompt('您输入名字','villin')
if(con){
console.log('用户点击了确定')
// 在此可以写确定后的执行代码
}else{
console.log('用户点击了取消')
// 在此可以写取消后的执行代码
}

显示如下:
![image](https://yqfile.alicdn.com/38a71a7ce328ee2c8b6f8ca8eaa76d6829c52f77.png)

```这种对话框也很有趣,有兴趣的,可以做一个反复弹出的对话框,恶搞你的朋友,可以练习一下。```


**--location对象--**```重要``````重要``````重要```

```location```对象对于Bom来讲,是最有用的对象之一,它提供了当前窗口中加载的文档有关的信息,还提供了一些导航功能。
```location```对象即是window对象的属性,又是document对象的属性。可以说```window.location```和```document.location```引用的是同一个对象。

**location中提供了一些属性:**

hash : 返回url中的hash(#号后边的参数),如果url不包含散列,则返回空字符串。如:"#villin"
host : 返回服务器名称和端口号(如果有端口号的话会返回)。如:“www.villin.com:8080”
hostname : 返回不带端口号的服务器名称。如:“www.villin.com”
href : 返回当前加载页面的完整url。
pathname : 返回url的目录文件名或文件路径。
port : 返回url中指定的端口号。
protocol : 返回页面使用的协议,“http”或“https”。
search : 返回url的查询字符串,这个字符串以“?”开头。


```举例:(每次修改属性后,页面都会重新加载,hash除外)```

假设原地址:www.villin.com/name/

1.添加一个hash地址:
location.hash = "#aaa" 改变后: www.villin.com/home/#aaa

2.添加一个搜索条件:
location.search = "?q=html" 改变后: www.villin.com/home/?q=html

3.将服务器名称修改为 www.abc.com ,后边home路径不变:
location.hostname = "www.abc.com" 改变后: www.abc.com/home/

4.修改原文件路径为/name:
location.pathname = "name" 改变后:www.villin.com/name/

5.添加一个8080端口号:
location.port = 8080 改变后:www.villin.com:8080/name/

打开一个新的页面的方法:

```window.location(www.baidu.com)```
```location.href(www.baidu.com)```
```location.assign(www.baidu.com)```
```location.replace(www.baidu.com)```

️这几种方法都可以跳转到新的页面,目前常用的是```location.href()```方法。修改url后都会生成一条新的记录,因此用户可以通过浏览器单击“后退”按钮,返回到前一个页面,若想禁用后退按钮,使用```location.replace()```方法,即可禁用后退按钮。

与其相关的方法还有一个```location.reload()```,此方法可以重新刷新当前页面。不过值得注意的是,这个方法会根据最有效的方式刷新页面,如果页面自上一次请求以来没有改变过,页面就会从浏览器缓存中重新加载。如果要强制从服务器中重新加载,传递一个参数true即可。```location.reload(true) // 从服务器重新加载```

**--history对象--**
```保存着用户浏览页面的历史记录```

简单介绍几个常见方法:

```history.go(-1) // 后退一页```
```history.go(1) // 前进一页```
```history.go(2) // 前进两页```
```history.go(0) // 重新加载当前页```

**--navigator对象--**
**--screen对象--**
由于window中以上两个个对象并不常用,在这里不做讲解。若有需要,我们可以自己去查阅相关资料。```navigator```对象,我们可以自己在代码中打印一下```console.log(window.navigator)```,自己可以扩展多了解一下浏览器的其他属性。

weChat:VillinWeChat

欢迎提出宝贵意见







上一篇:vue-cli3 之【框架搭建】教程


下一篇:js实现仿桌面右键,出现右键菜单功能