JavaScript中BOM
1.基本概念
1.1什么是BOM?
- DOM就是一套操作HTML标签的API(接口/方法/属性)
- BOM就是一套操作浏览器的API(接口/方法/属性)
1.2.BOM中常见的对象
- window: 代表整个浏览器窗口, 注意: window是BOM中的一个对象, 并且是一个顶级的对象(全局)
- Navigator: 代表当前浏览器的信息, 通过Navigator我们就能判断用户当前是什么浏览器
- Location: 代表浏览器地址栏的信息, 通过Location我们就能设置或者获取当前地址信息
- History: 代表浏览器的历史信息, 通过History来实现刷新/上一步/下一步, 注意点: 出于隐私考虑, 我们并不能拿到用户所有的历史记录, 只能拿到当前的历史记录
- Screen: 代表用户的屏幕信息
2. Navigato
// Navigator: 代表当前浏览器的信息, 通过Navigator我们就能判断用户当前是什么浏览器 // console.log(window.navigator); //useragent是其中的一个属性 var agent = window.navigator.userAgent; if(/chrome/i.test(agent)){ alert("当前是谷歌浏览器"); }else if(/firefox/i.test(agent)){ alert("当前是火狐浏览器"); }else if(/msie/i.test(agent)){ alert("当前是低级IE浏览器"); }else if("ActiveXObject" in window){ alert("当前是高级IE浏览器"); }
3.Location
// Location: 代表浏览器地址栏的信息, 通过Location我们就能设置或者获取当前地址信息 // 获取当前地址栏的地址 oBtn1.onclick = function(){ console.log(window.location.href); } // 设置当前地址栏的地址 oBtn2.onclick = function(){ window.location.href = "http://www.it666.com"; } // 重新加载界面 oBtn3.onclick = function(){ window.location.reload(); } oBtn4.onclick = function(){ window.location.reload(true); }
4. History
// History: 代表浏览器的历史信息, 通过History来实现刷新/前进/后退 // 注意点: 出于隐私考虑, 我们并不能拿到用户所有的历史记录, 只能拿到当前的历史记录 let oBtn1 = document.querySelector("#btn1"); let oBtn2 = document.querySelector("#btn2"); // 前进 /* 注意点: 只有当前访问过其它的界面, 才能通过forward/go方法前进 如果给go方法传递1, 就代表前进1个界面, 传递2就代表进行2个界面 */ oBtn1.onclick = function () { // window.history.forward(); window.history.go(1); } // 刷新 // 如果给go方法传递0, 就代表刷新 oBtn2.onclick = function () { window.history.go(0); } // 后退 /* 注意点: 只有当前访问过其它的界面, back/go方法后退 如果给go方法传递-1, 就代表后退1个界面, 传递-2就代表后退2个界面 */ oBtn1.onclick = function () { // window.history.back(); window.history.go(-1); }
5.获取元素宽高的方法以及偏移位等
5.1 获取偏移位
-
/* 1.offsetLeft和offsetTop作用 获取元素到最近祖先元素之间的偏移位 如果没有祖先元素是定位的, 那么就是获取到body的偏移位 */ let oSDiv = document.querySelector(".son"); oSDiv.onclick = function () { console.log(oSDiv.offsetLeft); console.log(oSDiv.offsetTop); }
5.2获取宽高
/* 1.通过getComputedStyle获取宽高 1.1获取的宽高不包括 边框和内边距 1.2即可以获取行内设置的宽高也可以获取CSS设置的宽高 1.3只支持获取, 不支持设置 1.4只支持IE9及以上浏览器 */ var oDiv = document.getElementById("box"); // oDiv.style.width = "166px"; // oDiv.style.height = "166px"; var style = getComputedStyle(oDiv); // style.width = "166px"; 设置 // style.height = "166px"; console.log(style.width);//获取 console.log(style.height); /* 2.通过currentStyle属性获取宽高 2.1获取的宽高不包括 边框和内边距 2.2即可以获取行内设置的宽高也可以获取CSS设置的宽高 2.3只支持获取, 不支持设置 2.4只支持IE9以下浏览器 */ var oDiv = document.getElementById("box"); // oDiv.style.width = "166px"; // oDiv.style.height = "166px"; var style = oDiv.currentStyle; style.width = "166px"; style.height = "166px"; // console.log(style); console.log(style.width); console.log(style.height); /* 3.通过style属性获取宽高 3.1获取的宽高不包括 边框和内边距 3.2只能获取内设置的宽高, 不能获取CSS设置的宽高 3.3可以获取也可以设置 3.4高级低级浏览器都支持 */ var oDiv = document.getElementById("box"); oDiv.style.width = "166px"; oDiv.style.height = "166px"; console.log(oDiv.style.width); console.log(oDiv.style.height); /* 4.offsetWidth和offsetHeight 4.1获取的宽高包含 边框 + 内边距 + 元素宽高 4.2即可以获取行内设置的宽高也可以获取CSS设置的宽高 4.3只支持获取, 不支持设置 4.4高级低级浏览器都支持 */ var oDiv = document.getElementById("box"); // oDiv.offsetWidth = "166px"; // oDiv.offsetHeight = "166px"; oDiv.style.width = "166px"; oDiv.style.height = "166px"; console.log(oDiv.offsetWidth); console.log(oDiv.offsetHeight); /* 1.getComputedStyle/currentStyle/style 获取的宽高不包括 边框和内边距 2.offsetWidth/offsetHeight 获取的宽高包括 边框和内边距 3.getComputedStyle/currentStyle/offsetXXX 只支持获取, 不支持设置 4.style 可以获取, 也可以设置 5.getComputedStyle/currentStyle/offsetXXX 即可以获取行内,也可以获取外链和内联样式 6.style 只能获取行内样式 */
5.3 获取定位父元素
/*1.offsetParent作用 获取元素的第一个定位祖先元素 如果没有祖先元素是定位的, 那么就是获取到的就是body */ let oSDiv = document.querySelector(".son"); oSDiv.onclick = function () { console.log(oSDiv.offsetParent); }
6.client属性
/* 1.offsetWidth = 宽度 + 内边距 + 边框 offsetHeight = 高度 + 内边距 + 边框 2.clientWidth = 宽度 + 内边距 clientHeight = 高度 + 内边距 */ let oDiv = document.querySelector("div"); // console.log(oDiv.clientWidth); // console.log(oDiv.clientHeight); /* 1.offsetLeft/offsetTop: 距离第一个定位祖先元素偏移位 || body 2.clientLeft/clientTop: 左边框 和 顶部边框 */ console.log(oDiv.clientLeft); console.log(oDiv.clientTop); oDiv.scrollWidth
7.scroll属性
/* 1.内容没有超出元素范围时 scrollWidth: = 元素宽度 + 内边距宽度 == clientWidth scrollHeight: = 元素高度 + 内边距的高度 == clientHeight */ let oDiv = document.querySelector("div"); // console.log(oDiv.scrollWidth); // console.log(oDiv.scrollHeight); /* 2.内容超出元素范围时 scrollWidth: = 元素宽度 + 内边距宽度 + 超出的宽度 scrollHeight: = 元素高度 + 内边距的高度 + 超出的高度 */ /* 3.scrollTop / scrollLeft scrollTop: 超出元素内边距顶部的距离,比如滚动网页滚出去的部分 scrollLeft: 超出元素内边距左边的距离 */ // console.log(oDiv.scrollTop); oDiv.onscroll = function () { console.log(oDiv.scrollTop); }
8. 获取网页宽高
/* 注意点: innerWidth/innerHeight只能在IE9以及IE9以上的浏览器中才能获取 console.log(window.innerWidth); console.log(window.innerHeight); */ <--------------------------------------------> /* 注意点: documentElement.clientWidth/documentElement.clientHeight 可以用于在IE9以下的浏览器的标准模式中获取 浏览器在渲染网页的时候有两种模式"标准模式"/"混杂模式/怪异模式" 默认情况下都是以标准模式来进行渲染的(CSS1Compat) 如果网页没有书写文档声明, 那么就会按照"混杂模式/怪异模式"来进行渲染的(BackCompat) 混杂模式就是没有写最上面那一行<!DOCTYPE html> documentElement --> HTML --> 整个网页 */ <--------------------------------------------> /* // console.log(document.documentElement); // console.log(document.documentElement.clientWidth); // console.log(document.documentElement.clientHeight); */ <-----------------------------------------------> // 注意点: 在混杂模式中利用如下的方式获取可视区域的宽高 // console.log(document.compatMode);// CSS1Compat // console.log(document.body.clientWidth); // console.log(document.body.clientHeight); */ //综上所述 我们来封装一个获取网页宽高的函数 let {width, height} = getScreen(); console.log(width); console.log(height); function getScreen() { let width, height; if(window.innerWidth){ width = window.innerWidth; height = window.innerHeight; }else if(document.compatMode === "BackCompat"){ width = document.body.clientWidth; height = document.body.clientHeight; }else{ width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; } return { width: width, height: height } }
9.获取网页滚动距离
window.onscroll = function () { // 1.IE9以及IE9以上的浏览器 // console.log(window.pageXOffset); // console.log(window.pageYOffset); // 2.标准模式下浏览器 // console.log(document.documentElement.scrollTop); // console.log(document.documentElement.scrollLeft); // 3.混杂(怪异)模式下浏览器 // console.log(document.body.scrollTop); // console.log(document.body.scrollLeft); let {x, y} = getPageScroll(); console.log(x, y); //封装一个获取网页滚动距离的函数 function getPageScroll() { let x, y; if(window.pageXOffset){ x = window.pageXOffset; y = window.pageYOffset; }else if(document.compatMode === "BackCompat"){ x = document.body.scrollLeft; y = document.body.scrollTop; }else{ x = document.documentElement.scrollLeft; y = document.documentElement.scrollTop; } return { x: x, y: y } } }
9.练习
星空背景 弹性导航 百度登录 大图展示 跟随广告 吸顶效果 返回顶部 楼层效果 橱窗效果
-
收获
window.scrollTo(x, y); // x表示让网页在水平方向滚动到什么位置 // y表示让网页在垂直方向滚动到什么位置 //注意点: 通过documentElement.scrollTop来实现网页滚动, 在设置值的时候不能添加单位
10.函数防抖
/* 1.什么是函数防抖[debounce]? 函数防抖是优化高频率执行js代码的一种手段 可以让被调用的函数在一次连续的高频操作过程中只被调用一次 2.函数防抖作用 减少代码执行次数, 提升网页性能 3.函数防抖应用场景 oninput / onmousemove / onscroll / onresize等事件 */ let oInput = document.querySelector("input"); let timerId = null; // abc oInput.oninput = function () { timerId && clearTimeout(timerId); timerId = setTimeout(function () { console.log("发送网络请求"); }, 1000); // console.log(this.value); // console.log("发送网络请求"); }
10.1 函数防抖的封装
function debounce(fn, delay) { // fn = test let timerId = null; return function () { let self = this;//使得我外面传进来的函数this和debounce的this相同 let args = arguments;// 外面的函数可以得到event事件 timerId && clearTimeout(timerId); timerId = setTimeout(function () { // console.log("发送网络请求"); // 以下操作将回调函数的this改为当前调用该函数的元素,同时也能够获取到如event事件等 fn.apply(self, args); }, delay || 1000); } } oInput.oninput = debounce(function (event) { console.log("发送网络请求"); console.log(this); console.log(event); }, 5000);
10.2 练习(令div的宽高为可视区域的一半)
let oDiv = document.querySelector("div"); function resetSize(){ let {width, height} = getScreen(); oDiv.style.width = width / 2 + "px"; oDiv.style.height = height / 2 + "px"; } resetSize(); // 监听可视区域尺寸的变化 onresize window.onresize = debounce(function () { resetSize(); console.log("尺寸的变化"); }, 1000);
这个练习存在着一定的问题,虽然性能提升但是用户体验不好,因为只有在可视区域尺寸变化完后div才会变,为此引出函数节流
11 函数节流
/* 1.什么是函数节流[throttle]? 函数节流也是优化高频率执行js代码的一种手段 可以减少高频调用函数的执行次数 2.函数节流作用 减少代码执行次数, 提升网页性能 3.函数节流应用场景 oninput / onmousemove / onscroll / onresize等事件 4.函数节流和函数防抖区别 函数节流是减少连续的高频操作函数执行次数 (例如连续调用10次, 可能只执行3-4次) 函数防抖是让连续的高频操作时函数只执行一次(例如连续调用10次, 但是只会执行1次) */ let oDiv = document.querySelector("div"); function resetSize(){ let {width, height} = getScreen(); oDiv.style.width = width / 2 + "px"; oDiv.style.height = height / 2 + "px"; } resetSize(); // 监听可视区域尺寸的变化 let timerId = null; let flag = true; window.onresize = function () { //设置flag后,当第一次进来的时候以下为false,会执行后边的代码,将flag修改为true,同时开启定时器, //而第二次进来的时候由于flag是false,会直接return,直到定时器时间到后执行定时器里边的内容同时修改flag //才会再次执行if后边的语句 if(!flag){ // if(false) if(true) if(false) return; } flag = false; timerId && clearTimeout(timerId); timerId = setTimeout(function () { flag = true; resetSize(); console.log("尺寸的变化"); }, 500); }
11.1 函数节流的封装(对比函数防抖)
function throttle(fn, delay) { // fn = test let timerId = null; let flag = true; return function () { if(!flag) return; flag = false; let self = this; let args = arguments; timerId && clearTimeout(timerId); timerId = setTimeout(function () { flag = true; fn.apply(self, args); }, delay || 1000); } }