浏览器对象模型

152 阅读15分钟

BOM

Browser Object Model 浏览器对象模型

全局对象

window

每打开一个浏览器就会创建一个全局对象(window)

全局变量为全局对象的属性,全局函数为全局对象的方法 (window.变量名) 注:ES5声明

以ES6形式声明的方法和变量无法加入全局对象,而以ES5形式声明的全局变量和函数(包括函数表达式创建的函数、箭头函数)会成为全局对象的属性和方法,可以正常访问,但无法被删除。只能删除以全局对象新增或已存在的键名。

以字面量(函数声明式)方式声明的函数,全局对象是可以正常访问和调用的。

let i = 10;
console.log(window.i);//undefined

var j = 23;
console.log(window.j);//23

//无法删除以ES5声明形式创建的全局变量的键名
delete window.j;
console.log(window.j);//23

//可以删除以全局对象新增或已存在的键名
window.k = "hello";
console.log(window.k);//hello
delete window.k;
console.log(window.k);//undefined


var myFunction = function () {
    console.log("hello");
}
window.myFunction();// hello    (let 形式创建的不可以访问  会返回window.myFunction is not a function)


function myFunction1() {
    console.log("hello world");
}

window.myFunction1();// hello world

var myFunction2 = () => {
    console.log("hahahahahahha");
}
window.myFunction2();//hahahahahahha


let myFunction3 = function () {
    console.log("adka");
}
console.log(window.myFunction3);//undefined

windows的属性

获取浏览器与屏幕的距离
离屏幕左侧的距离
  • screenLeft 不支持Firefox

  • screenX 不支持IE8以下

console.log(window.screenLeft);//不支持Firefox
console.log(window.screenX);//不支持IE8以下
离屏幕上端的距离
  • screenTop 不支持Firefox
  • screenY 不支持IE8以下
console.log(window.screenTop); //不支持Firefox
console.log(window.screenY);//不支持IE8以下
获取浏览器的尺寸(不带单位)
视口尺寸

不包含控制台、地址栏、标签页、菜单等、以及被放置在视口之外的元素

  • innerWidth 视口(viewport)的宽度
  • innerHeight 视口(viewport)的高度
console.log(window.innerWidth);//视口(viewport)的宽度
console.log(window.innerHeight);//视口(viewport)的高度
浏览器整体尺寸

包含控制台、地址栏、标签页、菜单等、以及被放置在视口之外的元素

  • outerWidth 浏览器的宽
  • outerHeight 浏览器的高
console.log(window.outerWidth);
console.log(window.outerHeight);
获取浏览器的滚动条尺寸
  • pageXOffset/srollX 滚动条水平方向上的尺寸
  • pageYOffset/srollY 滚动条方向上的尺寸
//获取浏览器的滚动条尺寸
console.log(`x轴:` + window.pageXOffset);
console.log(`y轴:` + window.pageYOffset);
console.log(`x轴:` + window.scrollX);
console.log(`y轴:` + window.scrollY);

windows方法

##### 提示、警示框

alert()

window.alert("message");弹出提示框,返回值是undefined

确认框

用户选择确认返回true,选择取消返回false

confirm()

let result = window.confirm("是否确认");//弹出对话框
console.log(result);//true或false
输入框

prompt()

用户输入信息,返回输入的信息

let input = window.prompt("请输入信息");//弹出对话框
console.log(input);//输入的信息
新建窗口
新建

open()

window.open("url","target","features");

参1:url:打开的页面的地址 参2:target:打开方式 _blank(新窗口)、 _self(当前页面) 参3:features:打开的页面的尺寸 参4:是否替换当前页面的历史记录(true,false)

resizeTo() 与resizeBy()

使用resizeTo()resizeBy()方法可以调整浏览器窗口的大小。这两个方法都接受两个参数,其中resizeTo()接受浏览器窗口新宽度和新高度,而resizeBy()接受新窗口与原窗口的宽度和高度只差。

关闭

close()

let temp = window.open("./index2.html","_blank","width=300px,height=300px");//打开新窗口
//关闭窗口
temp.close();
时间函数
  • setInterval(callback,delay);

功能:每隔参数2的时间调用一次参数1 参1:callback:要执行的函数 参2:delay:每隔多少毫秒执行一次 参数3即以后都是参1的实参,建议第三个参数直接传要处理的对象或对象数组

clearInterval(timer); 参:定时器的名字

 function getT(){
     let date = new Date();
     console.log(date.toTimeString());
 }
 setInterval(getT,1000);//每隔一秒执行一次函数

//练习:实现5,4,3,2,1
let k = 5;
let time = setInterval(() => {
    console.log(k--);
    if (k == 0) {
        clearInterval(time);
    }
}, 1000);

  • setTimeout(callback,delay);(超时函数)

功能:超过参数2的时间后,执行一次参数1的callback函数

clearTimeout(timer);

参:超时器的名字

let time1 = setTimeout(() => {
    console.log("hello world");
}, 2000);
clearTimeout(time1);

BOM--history

Window.history是一个只读属性,用来获取History 对象的引用,History 对象提供了操作浏览器会话历史(浏览器地址栏中访问的页面,以及当前页面中通过框架加载的页面)的接口。

  • history.forward(); 向前跳转

  • history.back(); 向回跳转

  • history.go(n) 通过参数的不同,返回不同的记录页面

    注:1、参数为正数,则去后面第n页 2、参数为负数,则去前面第n页 3、参数为0,则去当前页(刷新)

 <a href="./bom2.html">上一页</a>

 <input type="button" value="上一页" onclick="before()">
 <input type="button" value="下一页" onclick="next()">
  <script>
      function before() {
          history.back();
        }

      function next() {
            history.forward();
        }
 </script>

BOM--location

location 获取地址栏信息

  • location.href 获取地址栏的所有信息

    利用 location.href = "地址";跳转到指定的页面

  • location.search获取当前页面的查询字符串(?及以后的内容)

  • location.port 获取端口

  • location.replace("地址") 替换当前页面,无法回退

  • location.assign("地址") 跳转到指定页面

let info = location.href;//获取当前页面的地址
console.log(info);
let info1 = location.search;//获取当前页面的查询字符串(?及以后的内容)
console.log(info1);//?username=123&password=123123
let str = info1.split("?")[1];//获取查询字符串中的内容
let obj = formStrToObj(str);
console.log(obj) ;
console.log(formObjToStr(obj));
//获取端口
let port = location.port;//获取端口
console.log(port);//63342


//替换跳转页面
<input type="button" value="replace" onclick="F88()">
        <input type="button" value="assign" onclick="F89()">

function F88(){
    location.replace("/bom1.html");//替换当前页面
}
function F89(){
    location.assign("/bom2.html");//跳转到指定页面
}

BOM--screen

屏幕信息

  • screen.availWidth 获取屏幕可用宽度
  • screen.availHeight 获取屏幕可用高度
console.log(`屏幕宽度:${screen.availWidth}`);//可用屏幕宽度
console.log(`屏幕高度:${screen.availHeight}`);//可用屏幕宽度

BOM--navigator

浏览器信息

  • navigator.appName 浏览器名称
  • navigator.appVersion 浏览器版本
  • navigator.userAgent 浏览器类型
  • navigator.language 浏览器翻译 zh-CN
console.log(`浏览器名称:${navigator.appName}`);//浏览器名称    Netscape网景 开源(免费)
console.log(`浏览器版本:${navigator.appVersion}`);//浏览器版本
console.log(`浏览器类型:${navigator.userAgent}`);//浏览器类型
console.log(`浏览器翻译:${navigator.language}`);//浏览器翻译  zh-CN

BOM--document(DOM)

Document Object Model 文档对象模型

作用:获取和操作HTML节点

DOM 发展历史

DOM0

DOM1 1998年 W3C

DOM2 2000年

DOM3 2004年

DOM4 2015年

节点对象

nodeName(节点名)nodeValue(节点值)nodeType(节点类型)
元素节点(ElementNode)标签名null1
文本节点 (TextNode)#text文本内容3
属性节点 (AttributeNode )属性名属性值2

获取节点

快速获取节点
通过标签名获取元素

document.getElementsByTagName("标签名");

如果找到对应的节点则会返回一个伪数组,可通过下标去访问某一个元素

如果没有找到,则伪数组length=0

let divElement = document.getElementsByTagName('div');
console.log(divElement[0]);
let secElement = document.getElementsByTagName('section')[0];
console.log(secElement);
通过类名获取元素

document.getElementsByClassName("类名");

如果找到对应的节点则会返回一个伪数组,可通过下标去访问某一个元素

如果没有找到,则伪数组length=0

let elementByClassName = document.getElementsByClassName('box1');//如果没有找到,返回length=0的伪数组
console.log(elementByClassName);
通过ID值获取元素

document.getElementById("id值");

ID具有唯一性,如何没有找到,返回null

扩展

可以直接书写id值,即为对应的节点对象

let elementByID = document.getElementById('isSection');//ID具有唯一性,如何没有找到,返回null
console.log(elementByID);
console.log(isSection);
通过节点的name属性值,获取元素

document.getElementsByName("username");

会返回一个伪数组,可通过下标去访问某一个元素

如果没有找到,则伪数组length=0

let inpEle = document.getElementsByName("username"); console.log(inpEle[1]);
查询选择器

获取元素节点的方式,与第一类快速获取节点相比不是实时的

css选择器怎么选择,选择器参数就如何传

  • document.querySelector() 返回满足条件的第一个元素节点
  • querySelectorAll() 返回满足条件的所有元素节点
let elements = document.querySelector('[name="username"]');
console.log(elements);
//querySelectorAll()返回满足条件的所有元素节点
let elementsAll = document.querySelectorAll('[name="username"]');
console.log(elementsAll);
层次关系选取节点
子级
  • .childNodes 获取所有子节点

    返回的是一个伪数组

let artEle = document.querySelector('article');
//获取所有子节点
console.log(artEle.childNodes);
  • .children 获取所有子元素节点

    返回的是一个伪数组

//获取所有子元素节点
console.log(artEle.children);
console.log(artEle.children[1].children[0]);//span
  • .firstElementChild 获取第一个子元素节点
  • .lastElementChild 获取最后一个子元素节点
//获取第一个子元素节点
console.log(artEle.firstElementChild);
  • .firstChild 获取第一个子节点
  • .lastChild 获取最后一个子节点
//获取第一个子节点
console.log(artEle.firstChild);//文本节点
//获取最后一个子节点
console.log(artEle.lastChild);
父级

父级只有一个,所以父节点和父元素节点是同一个。

  • childNodes.parentNode 获取父节点
  • childNodes.parentElement 获取父元素节点

注: 获取html的parentNode返回#document 获取html的parentElement返回null

console.log(artEle.parentNode.parentNode.parentNode);//document
console.log(artEle.parentElement.parentElement.parentElement);//null
兄弟

前面

  • ElementNode.previousSibling 获取前一个兄弟节点

  • ElementNode.previousElementSibling 获取前一个兄弟元素节点

console.log(spanElement.previousSibling);//文本节点
console.log(spanElement.previousElementSibling);//span1

后面

  • ElementNode.nextSibling 获取后一个兄弟节点
  • ElementNode.nextElementSibling 获取后一个兄弟元素节点
console.log(spanElement.nextSibling);//文本节点
console.log(spanElement.nextElementSibling);//span3

parentNode.hasChildNodes(childNode)可以判断父节点里面是否包含子节点

简单获取节点

document.documentElement 获取HTML

document.head 获取head

document.body 获取body

document.images

document.forms 所有的form标签

document.links 所有的a标签

新增元素节点

  1. 创建新的元素节点 书写格式:document.createElement(nodeName)
  2. 创建新元素节点的元素内容(文本) 书写格式:document.createTextNode(text)
  3. 把新增的节点添加到页面中 书写格式:parentNode.appendChild(childNode)
//书写格式:document.createElement(nodeName)
let divElement2 = document.createElement('div');
console.log(divElement2);

//添加节点
//书写格式:parentNode.appendChild(childNode)
let bodyElement = document.querySelector('body');
bodyElement.appendChild(divElement2);

//添加文本节点
//书写格式:document.createTextNode(text)
let divText = document.createTextNode('这是新增的文本节点');
//书写格式:elementNode.appendChild(textNode)
divElement2.appendChild(divText);
console.log(divText);

插入节点

需要的节点
  1. 父节点
  2. 被插入的节点
  3. 插入的节点(新)
步骤
  1. 新增或获取插入节点
  2. 获取父节点
  3. 获取被插入的子节点
  4. 执行插入节点书写格式 书写格式:parentNode.insertBefore(insertNode,childNode)

注释节点

书写格式:document.createComment(text)

let comment = document.createComment('这是注释节点');
bodyElement.insertBefore(comment, divElement2);

剪切节点

方式1:如果插入的节点已经存在页面中,插入后,会在原位置删除

方式2:如果添加的节点已经存在页面中,添加后,会在原位置删除

//方式1
let pElement = document.querySelector('p');
bodyElement.insertBefore(pElement,divElement2 );
//方式2
let divElement3 = document.querySelector('.box');
bodyElement.appendChild(divElement3);

复制(克隆)节点

书写格式: 被克隆的节点.cloneNode(boolean)

  1. 实参给true,则表示深克隆,会克隆其子节点

  2. 实参给false,则表示浅克隆,不会克隆其子节点

let divElement3 = document.querySelector('.box');
let divClo = divElement3.cloneNode(false);
bodyElement.appendChild(divClo);

更改、替换

书写格式:parentNode.replaceChild(newChild,oldChild)

let asideElement = document.createElement('aside');
bodyElement.replaceChild(asideElement,divElement2);
快速替换或覆盖的方式

快速替换元素内容

  1. innerHTML可以识别字符串里面的标签
  2. innerText只能识别文本,不能识别标签
ple2.innerText = '<i>这是新的文本</i>';
ple2.innerHTML = '<i>这是新的文本</i>';

删除

书写格式:parentNode.removeChild(childNode)

bodyElement.removeChild(divElement3);

属性节点(AttributeNode)

生成属性节点

书写格式:ElementNode.setAttribute(name,value)

let headerElement = document.getElementsByTagName('header')[0];
headerElement.setAttribute('name', 'f82');
获取属性(原生和添加属性均可获取)

书写格式:ElementNode.getAttribute(name)

console.log(headerElement.getAttribute('name'));

注:ElementNode.属性名 仅可使用元素节点原生的属性

获取class属性值(多个)

可以通过ElementNode.classList获取,返回伪数组,即可通过下标获取

let asideElement11 = document.getElementsByTagName('aside')[0];
console.log(asideElement11.getAttribute('class'));//y1 y2(一个值)
console.log(asideElement11.className);//y1 y2(一个值)

console.log(asideElement11.classList);//[y1,y2]  伪数组
console.log(asideElement11.classList[1]);//y2
asideElement11.classList.add('y3');//添加class y3

asideElement11.className = 'y3';//将y1 y2替换成y3
asideElement11.className += ' y4';//将y4添加到y3后面,注意加空格
asideElement11.classList.remove('y3');//删除class y3
删除属性

书写格式:ElementNode.removeAttribute(name)

headerElement.removeAttribute('name');
快速生成属性

书写格式:ElementNode.属性名 = 属性值 注意:for写成htmlFor;class写成className

自定义属性

书写格式1:<开始 data-属性名=属性值></结束>

书写格式2:ElementNode.dataset.属性名 = XXX

获取自定义属性

书写格式1:ElementNode.dataset.属性名

书写格式2:ElementNode.getAttribute(name)

补充:

//创建文档碎片(实现添加多个标签时,只渲染一次),减少DOM渲染的次数,提高效率
let frag = document.createDocumentFragment();
frag.appendChild(spanEle);//将多个标签加入临时碎片
sectionEle.appendChild(frag);

利用js操作CSS

设置:ElementNode.style.key = value;

获取:ElementNode.style.key

注意:

  1. key是css样式的键名,如果是多个单词组成,则去横线,并且小驼峰;value是css样式的值
  2. 以点的方式只能获取节点的行内样式,非行内样式返回空
let labelElement = document.getElementsByTagName('label')[0];
labelElement.style.color = 'red';
labelElement.style.backgroundColor = 'blue';
labelElement.style.fontSize = 60+'px';//去掉连接符,使用小驼峰命名法

console.log(labelElement.style.color);//red
console.log(labelElement.style.fontSize);//60px
console.log(labelElement.style.border);//none
获取节点计算后的样式

书写格式 :getComputedStyle(ElementNode)

功能:实现获取非行内样式

注意:该样式为只读属性

let labelStyle = getComputedStyle(labelElement);
console.log(labelStyle.paddingLeft);//30px
获取元素节点的尺寸
  • content的宽高

ElementNode.style.width 带单位px 可用parseInt来提炼数值

ElementNode.style.height 带单位px 可用parseInt来提炼数值

  • content+padding

ElementNode.clientWidth

ElementNode.clientHeight

  • content+padding+border

ElementNode.offsetWidth

ElementNode.offsetHeight

获取节点的位置

position不等于static 获取节点到包含块的距离

position 等于static 获取节点到视口的距离

offsetLeft,offsetTop

let {offsetLeft,offsetTop} = iEle;//对象的解构
console.log(offsetLeft,offsetTop)

事件

事件:当用户在页面操作行为时则会触发事件

事件三要素:

  1. 事件源 (绑定事件的节点)
  2. 事件类型 (键盘、鼠标等) 例如:onclick
  3. 事件处理函数 (事件触发时执行的函数) 例如:F82()
  • DOM0
  1. DOM0级事件绑定 会存在覆盖的问题;下边的代码会把上边的代码覆盖.
  2. 分为两种:一种是 onclick = function(){} ,还有一种是标签内写onclick事件
  3. DOM0级事件具有极好的跨浏览器优势,会以最快的速度绑定。
  4. 删除DOM 0事件处理程序,只要将对应事件属性设为null即可。
box.onclick = null;
  • DOM1

DOM1一般只有设计规范没有具体实现,所以一般跳过。

  • DOM2
  1. 原生有两个方法用来添加和移除事件处理程序:addEventListener()removeEventListener()
  2. 给某一个元素的同一个行为绑定不同的方法在行内会分别执行;支持绑定多个函数;只有三个参数都相同时,才称为重复绑定,这时就不再往 事件池 添加 事件
  3. 第三个参数如果是true则表示在捕获阶段调用,为false表示在冒泡阶段调用。
  4. 只有2级DOM包含3个事件:事件捕获阶段、处于目标阶段和事件冒泡阶段;需要对同一个节点触发不同的事件时,事件不会被覆盖,会依次执行,dom1和dom2是可以共存的

ElementNode.addEventListener(事件类型,事件处理函数,事件流)

  1. addEventListener的第三个参数:事件流——事件传播机制

  2. 取值:Boolean

    1. 取值为false则从里到外依次触发,即冒泡(不写则默认false)
    2. 取值为true则从外到里依次触发,即捕获
  3. 具有嵌套关系 + 相同的事件类型就需要考虑事件流

事件类型
鼠标事件
  1. click 单击
  2. dblclick 双击
  3. mousedown 按下
  4. mouseup 抬起
  5. 【鼠标移入——移出】
    1. 这一组事件源与子元素都会触发
      1. mouseover 移入
      2. mouseout 移出
    2. 这一组只有事件源触发(true----捕获时 子元素也会触发效果)
      1. mouseenter 移入
      2. mouseleave 移出
  6. mousemove 鼠标移动

获取鼠标的左、中、右键

document.addEventListener('click',function(e){
    let event = e ||window.event;
    //左、中、右 ————>0、1、2
    console.log(event.button);
});

获取鼠标在盒子内的坐标

   1. 首先得到鼠标在页面中的坐标( e.pagex e.pageY )
   2. 其次得到盒子在页面中的距离( box.offsetLeft, box.offsetTop)
   3. 用鼠标距离页面的坐标减去盒子在页面中的距离,得到鼠标在盒子内的坐标
 console.log("鼠标到节点的X轴:", event.offsetX);
 console.log("鼠标到节点的Y轴:", event.offsetY);
 console.log("鼠标到视口的X轴:", event.clientX);
 console.log("鼠标到视口的Y轴:", event.clientY);
 console.log("鼠标到页面的X轴:", event.pageX);
 console.log("鼠标到页面的Y轴:", event.pageY);
页面事件

页面加载:

//已加载
window.addEventListener('load',f);
//AD
window.addEventListener('load', function () {
    asiEle.style.bottom = 0 + 'px'
    //关闭功能
    //倒计时功能
    let i = 5;
    let timer = setInterval(() => {
        timeSpan.innerText = `${i}`;
        if (i < 0) {
            asiEle.remove();
            clearInterval(timer);
        }
        i--;
    }, 1000);
    xSpan.addEventListener('click', () => {
        clearInterval(timer);
        asiEle.remove();

    });
});

检测滚动条

scroll 事件类型用于在浏览器窗口内移动文档的位置时触发,如通过键盘箭头键、翻页键或空格键移动稳定位置,或者通过滚动条滚动稳定位置。利用该事件可以跟踪文档位置变化,及时调整某些元素的的显示位置,确保它始终显示在屏幕可见区域内中。

window.addEventListener('scroll',()=>{
    let secEle = document.getElementsByTagName('section')[0];
    let scrollYs = window.scrollY;
    secEle.style.display = 'none';
    if (scrollYs < 800){
        secEle.style.display = 'none';
    }else {
        secEle.style.display = 'block';
    }
});

关闭或刷新

window.addEventListener('unload',function(){})

键盘事件

keydown:按下键盘时触发 注:按住不放一直触发该事件

event.key获取按的那个键
event.keyCode获取按键的ASC码

input.addEventListener('keydown',function(e){
	e=e||window.event;
	if(e.key == 'Enter'){
	
	}
})

keyup 抬起按键时触发

keypress 按下键盘的字符键时触发,功能键不触发

字符键:字母、数字、标点符号、shift+0-9

表单事件

focus 激活焦点框 移入输入框时触发

input 输入时触发

blur 失去焦点 移出输入框时触发

change 失去焦点时input的值与激活焦点时的值不一样的时候触发

即失去焦点前与失去焦点后的内容是否一致,如果不一致(发生改变)则触发该事件 适用场景 :select

补充:获取焦点 ElementNode.focus()

reset 重置按钮(reset 按钮触发) submit 提交事件 (提交按钮触发)

事件委托、事件代理

触发事件的节点

当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递给响应函数

在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标,键盘哪个按键被按下,滚轮的滚动方向

在IE8中,响应函数被触发时,浏览器不会传递事件对象,在IE8中及以下的浏览器中,是将事件对象作为window对象的属性保存的

事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

事件对象是触发事件时会自动传入到事件处理函数的一个对象,该对象里面记录了触发事件的详细信息。

适用场景:

  1. 相同事件类型

  2. 子节点是动态的

let ulEle = document.getElementsByTagName('ul')[0];
ulEle.addEventListener('click',function(e){
    //解决事件对象的兼容性问题
    let event = e || window.event;
    //event.target触发事件的节点
    if(event.target.nodeName == 'LI'){
        console.log('li');
    }
    if(event.target.localName == 'span'){
        console.log('span');
    }
})

事件处理函数(普通声明)中的this代表的就是事件源

cancelable 取消

事件阻止
  1. 阻止冒泡型事件流(DOM2) 书写格式:事件对象.stopPropagation() 事件对象是内层的

  2. 阻止捕获型事件流(DOM3) 书写格式:事件对象.stopImmediatePropagation() 事件对象是外层的

  3. 阻止默认事件:阻止原始的功能,执行需要的业务逻辑 书写格式:事件对象.preventDefault() (按钮和a标签可能用到)

//借助Mock批量生成数据
let result = Mock.mock({
    "stuArr|10":[{
        "stuId|+1":1,
        "stuName":"@cname",
        'stuAge|20-30':1,
        'stuGender|1':[true,false]
    }]
});
console.log(result);