# BOM与DOM
# BOM浏览器对象模型
# 一、window对象
# 1、window.navigator
返回浏览器及其功能信息
# 2、window.location
location
属性是一个用于存储当前载入页面URL信息的对象。
hash : ""
host : "180.100.209.103:3000"
hostname : "180.100.209.103"
href : "http://180.100.209.103:3000/"
origin : "http://180.100.209.103:3000"
pathname : "/home"
port : "3000"
protocol : "http:"
search : "?ad=123"
assign : ƒ assign()
reload : ƒ reload()
replace : ƒ replace()
toString : ƒ toString()
// 跳转地址
window.location.href = 'http://www.baidu.com';
// assign()
window.location.assign('http://www.baidu.com');
// replace() 不会在历史记录中留下记录,没有再次返回
window.location.replace('http://www.baidu.com');
// reload() 重新载入
window.location.reload('http://www.baidu.com');
# 3、window.history
浏览器中的地址访问历史记录
window.history.length; // 长度
window.history.forward(); // 前进
window.history.back(); // 后退
window.history.go(1/-1); // 前进后退
window.history.pushState(); // 更改记录中的URL,路由会跟着变,但页面不刷新
history.pushState({a: 1}, "", "hellow");
history.state; // {a: 1}
history.pushState({b: 2}, "", "helddslo");
history.state; // {b: 2}
# 4、window.frames
window.frames
返回当前页面中所有框架的集合。当前页面嵌有iframe时就能通过该属性获取iframe的window对象。
window.frames === window; // true
// 嵌套iframe
<iframe name="myframe" src="hello.html" />
window.frames.length; // 1
window.frames[0]; // iframe
window.frames[0].window;
window.frames[0].window.location.reload();
// top 属性获取最顶层页面
window.frames[0].window.top === window; // true
# 5、window.screen
window.screen
浏览器的环境信息。
height : 1080 // 总分辨率
width : 1920
availWidth : 1920 // 除去任务栏的区域
availHeight : 1040
availLeft : 0
availTop : 0
colorDepth : 24
pixelDepth : 24
# 5、window.devicePixelRatio
获取设备物理像素与设备独立像素的比例(dpr),一般用于移动端适配。
# 6、window.open()
打开新标签页,弹出窗
- url 地址
- resizable 新标签页尺寸可调整
- width height 弹窗长款
window.open('http://www.baidu.com', '', 'width=300, height=400, resizable=yes'); // 打开大小为300/400的新弹窗
# 7、window.close()
关闭标签页
# 8、window.moveTo()、window.moveBy()、window.resizeTo()、window.resizeBy()
window.moveTo(100, 100) // 让窗口移动到屏幕x, y的位置
window.moveBy(10, -10) // 移动x, y 距离
window.resizeTo(100, 100) // 改变窗口大小为x, y
window.resizeBy(10, -10) // 改变窗口大小x, y
# 9、window.alert()/window.prompt()/window.confirm()
window.alert('xxx')
弹出框window.prompt('请输入')
弹出输入框window.prompt('请输入')
弹出输入框
# 10、window.setTimeout()/window.setInterval()
window.setTimeout()/window.setInterval()
定时器window.setTimeout()
倒计时执行window.setInterval()
循环执行
这两个方法虽然可以传入毫秒级时间,但并不能保证准确执行,原因之一就是浏览器并没有精确到毫秒的去触发事件,最小在十几毫秒左右才会执行。 setTimeout/setInterval都属于宏任务,每次都是塞到异步任务队列排队执行。所以这也是导致定时器不能准确执行的另一个原因,如果我们设置了一个100毫秒的定时器,但他前面还有多个异步任务等待执行,等到他们执行完再执行估计都120毫秒后了。 所以我们在使用定时器时要慎重使用,不要什么情况下都使用,还要考虑有没有其他异步任务来影响。
如果要实现CSS动画效果,最好也不要用定时器来实现。一般情况下,动画在达到60帧时动画效果就会看起来很流畅,也就是说定时器要设置1000/60秒效果才会很流畅,但这个数字很危险,浏览器可能无法准确的执行。要实现动画效果,我们可以考虑使用requestAnimationFrame方法来实现,它不会受异步任务影响,会告诉浏览器直接要执行的动画。requestAnimationFrame方法和setTimeout倒计时类似。
const timer1 = setTimeout(function() {
console.log(111);
}, 1000);
clearTimeout(timer1);
const timer2 = setTimeout(function() {
console.log(111);
}, 1000);
clearInterval(timer2);
// requestAnimationFrame方法
function animationWidth() {
var div = document.getElementById('box');
div.style.width = parseInt(div.style.width) + 1 + 'px';
if(parseInt(div.style.width) < 200) {
requestAnimationFrame(animationWidth);
}
}
requestAnimationFrame(animationWidth);
# DOM文档对象模型
# 一、document对象
document.documentElement
获取HTML根节点document.body
获取body节点document.cookie
cookie信息document.title
网站标题document.images
获取所有图片document.links
获取含有herf的a标签document.anchors
获取含有name的a标签document.write()
页面载入时插入一下html元素document.referrer
返回访问过的页面URLdocument.domain
返回页面域名
# 二、获取节点快捷方法
document.getElementById()
通过id获取document.getElementByTagName()
通过标签名获取document.getElementByClassName()
通过标类名获取document.querySelector()
通过CSS选择器获取,可以是标签、类名、id等document.querySelectorAll()
通过CSS选择器获取所以的
这些方法获取元素后,可以直接获取其上的属性,不用再使用getAttribute了
var app = document.getElementById('app');
app.id; // app
app.className; // app
document.querySelector('body');
document.querySelector('.app');
document.querySelector('#app');
document.querySelector('input[type=text]');
# 三、访问节点属性
# 1、hasAttributes
documentElement.hasAttributes()
判断节点是否存在属性
var dom = document.getElementsByTagName('body');
dom[0].hasAttributes(); // true
# 2、attributes
documentElement.attributes
获取元素的属性列表,返回的是一个属性的映射对象
var app = document.getElementById('app');
// 获取属性长度
app.attributes.length; // 1
// 获取属性
app.attributes[0]; // id="app"
app.attributes[0].nodeName; // 'id'
app.attributes[0].nodeValue; // 'app'
app.attributes['id'].nodeValue; // 'app'
# 3、getAttribute
documentElement.getAttribute
获取元素的某个属性的值
var app = document.getElementById('app');
app.getAttribute('id'); // app
# 四、访问节点
# 1、判断是否存在子节点
documentElement.hasChildNodes()
判断节点是否存在子节点,包含文本节点
var dom = document.getElementsByTagName('body');
dom[0].hasChildNodes(); // true
# 2、获取节点文本内容
documentElement.textContent
documentElement.innerText
documentElement.innerHTML
# 3、获取节点标签名
documentElement.nodeName
var dom = document.getElementsByTagName('body');
dom[0].nodeName; // BODY
# 4、获取父节点
documentElement.parentNode()
获取父节点
# 5、获取子节点
documentElement.childNodes
获取所有子节点,包含文本节点documentElement.children
获取子元素,不包含文本节点
documentElement.childNodes[0]; // 第一个节点
documentElement.childNodes[documentElement.childNodes.length - 1]; // 最后一个节点
dom.children; // 所有子元素
dom.children[0];
# 6、前后相邻节点
documentElement.nextSibling
下一个节点,包含文本节点documentElement.previousSibling
前一个节点,包含文本节点documentElement.nextElementSibling
下一个元素,不包含文本节点documentElement.previousElementSibling
前一个元素,不包含文本节点
var dom = document.getElementById('app');
dom.nextSibling; // <p></p>
dom.previousSibling; // <p></p>
dom.nextElementSibling; // <p></p>
dom.previousElementSibling; // <p></p>
# 7、首尾节点
documentElement.firstChild
第一个节点,包含文本节点documentElement.lastChild
最后一个节点,包含文本节点documentElement.firstElementChild
第一个元素,不包含文本节点documentElement.lastElementChild
最后一个元素,不包含文本节点
var dom = document.getElementById('app');
dom.firstChild; // <p></p>
dom.lastChild; // <p></p>
dom.firstElementChild; // <p></p>
dom.lastElementChild; // <p></p>
# 五、节点操作
# 1、修改内容和样式
var dom = document.getElementById('app');
dom.innerHtml = 'hello world';
dom.style.fontSize = '12px';
dom.style.color = '#fff';
dom.style.cssText = 'border: 1px solid #ccc;';
# 2、创建节点元素
document.createElement()
创建元素document.createTextNode()
创建文本节点
var box = document.createElement('div');
# 3、添加节点
父元素.appendChild() 添加到最好一个子节点后面,并且在document.body上也可以调用
var dom = document.getElementById('app');
var box = document.createElement('div');
dom.appendChild(box);
// document.body.appendChild(box);
# 4、指定位置插入
父元素.insertBefore(新元素, 在谁前面插入) ,如果后面元素没有会自动调用appendChild()
var dom = document.getElementById('app');
var box = document.createElement('div');
dom.insertBefore(box);
# 5、替换元素
父元素.replaceChild(新的元素, 被替换的元素)
var dom = document.getElementById('app');
var child = dom.children[0];
var box = document.createElement('div');
dom.replaceChild(box, child);
# 6、删除元素
父元素.removeChild(元素)
var dom = document.getElementById('app');
var child = dom.children[0];
dom.removeChild(child);
# 7、克隆元素
元素.cloneNode(bool) bool为传布尔值,true克隆所有子节点,false值克隆当前节点
var dom = document.getElementById('app');
document.body.appendChild(dom.cloneNode(dom));
# 六、事件
# 1、事件绑定
# 1.1、内联绑定
<div id="app" onclick="alertMsg('hello')"></div>
# 1.2、元素属性法
var dom = document.getElementById('app');
dom.onclick = function() {
alert(123);
}
# 1.3、事件监听器
第一个参数为监听元素事件类型,第二个参数是一个函数指针,可以是一个匿名函数,也可以传一个函数名,第三个参数表示是否在捕获时就执行,默认为false。
var dom = document.getElementById('app');
dom.addEventListener('click', function() {
alert(1111);
}, false);
dom.addEventListener('click', alertHandler, false);
function alertHandler() {
alert(1111);
}
// 取消绑定
dom.removeEventListener('click', alertHandler, false)
// IE中使用
dom.attachEvent('on' + 'click', alertHandler)
dom.detachhEvent('on' + 'click', alertHandler)
# 2、事件周期-捕获与冒泡
# 2.1、一个事件从触发到结束的过程
- 捕获阶段 - 从window开始,有外向内直到目标元素结束,记录每层元素的事件
- 触发阶段 - 事件源的事件函数触发
- 冒泡阶段 - 从事件源开始由内向外一层一层触发
事件从最外层一层一层捕获,然后再从最内层一层一层触发。 当祖先元素和后代元素都绑定了同一个事件时,触发子元素的事件,父元素的事件也会被触发。 祖先元素绑定事件,点击所有的子元素也会触发祖先元素的事件,即使子元素没有绑定事件。
# 2.2、事件委托
利用冒泡子元素会触发父元素的事件原理,将子元素应该执行的事件,加到父元素上,点击子元素也可以触发,实现事件委托,节省内存。
# 2.3、取消冒泡
使用事件对象event的stopPropagation
方法阻止冒泡
// 兼容IE
function alertMsg(e) {
e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true;
}
# 2.4、阻止默认事件
浏览器中,有些事件自身会存在一下默认行为,比如a链接会跳转,我们可以使用事件对象的preventDefault方法进行取消。
// 兼容IE
function jumpLink(e) {
e.preventDefault();
}
# 页面上的各种尺寸
# 1、屏幕尺寸
window.screen.width
屏幕的宽window.screen.height
屏幕的高window.screen.availWidth
屏幕可用尺寸宽window.screen.availHeight
屏幕可用尺寸高,等于屏幕的高减去 mac 顶部栏或 windows 底部栏。
# 2、浏览器尺寸
window.outerWidth
整个浏览器的宽window.outerHeight
整个浏览器的高window.innerWidth
浏览器内部宽(包含滚动条的宽度)/ 可见宽高window.innerHeight
浏览器内部高,去除浏览器边框、标签栏、工具栏和开发者工具栏的高度document.documentElement.clientWidth
网页可见区域宽度(和innerWidth类似,不包含滚动条的宽度)document.documentElement.clientHeight
网页可见区域高度
# 3、body的尺寸
document.body.clientWidth
body的宽(不包含滚动条),并不等于网页可见区域的宽高document.body.clientHeight
body的高document.body.offsetWidth
body真实的宽(包括边框和边距,不包含滚动条)document.body.offsetHeight
body真实的高document.body.scrollWidth
body内滚动内容宽度(如果body宽高固定,就是内容高度,不固定就和body一样)document.body.scrollHeight
body内滚动内容高度
# 4、页面卷去高度
获取页面默认滚动卷去高度通过scrollTop获取,但需要使用兼容性写法。
不论body设不设置宽高,只要子元素没有设置overflow
属性,都是以浏览器默认,也就是body获取页面卷去高度,如果子元素设置了就只能以子元素来获取,并且不需要兼容性写法。
// 默认卷去高度
var scrollT = document.documentElement.scrollTop || document.body.scrollTop;
var scrollL = document.documentElement.scrollLeft || document.body.scrollLeft;
# 6、元素的各种宽高
上面都是获取整个页面的宽高等尺寸,当然其中也有适合页面里元素的各种尺寸方法。
var index = document.getElementsByClassName('index')[0];
index.clientWidth; // 元素的宽
index.clientHeight; // 元素的宽
index.offsetWidth; // 元素真实的宽
index.offsetHeight; // 元素真实的高
index.scrollWidth; // 元素内的滚动宽度
index.scrollHeight; // 元素内的滚动高度
index.offsetTop; // 元素到顶部的距离
index.offsetLeft; // 元素到左边的距离
index.scrollTop; // 元素内卷去高,(加给父元素)
index.scrollLeft; // 元素内卷去左
# 5、滚动到指定位置
页面滚动到指定位置,页面默认body滚动到顶部不论使用哪种方法都是带平滑滚动效果的,但如果是元素就没有效果了,需要使用其他属性进行添加。
# 1、使用scrollTop滚动到指定位置
// 页面滚动位置
document.documentElement.scrollTop = document.body.scrollTop = 0;
// 元素滚动位置
var index = document.getElementsByClassName('index')[0];
index.scrollTop = 0;
# 2、使用scrollTo滚动到指定位置
window.scrollTo(x, y, behavior)
behavior为滚动行为,值为smooth(平滑滚动),instant(瞬间滚动),默认值 auto(瞬间滚动),不过这个API不支持IE。
window.scrollTo(0, 0);
var index = document.getElementsByClassName('index')[0];
index.scrollTo({
top: 0,
behavior: "smooth"
});
# 3、使用scrollBy滚动到指定位置
window.scrollBy(x, y, behavior)
scrollBy与scrollTo类似,表示相对当前的位置滚动多少距离。
var index = document.getElementsByClassName('index')[0];
index.scrollBy({
top: -500,
behavior: 'smooth'
})
# 4、scrollIntoView让元素滚动到页面可以见范围内
此方法针对滚动容器内的子元素,让子元素滚动到可见范围内,而不是滚动容器。
Element.scrollIntoView(Boolean)
一个布尔值参数时表示滚动顶部对齐还是底部对齐,true表示顶部对齐,false表示底部对齐,默认为true。
Element.scrollIntoView({behavior: 'auto', block: 'start', inline: 'nearest'})
为一个对象时有三个值,behavior动画效果,auto/smooth,默认为 auto。block垂直对齐,start/center/end/nearest。默认为start。inline水平对齐,start/center/end/nearest。默认为 nearest。
var box1 = document.getElementsByClassName('box1')[0];
box1.scrollIntoView()
box1.scrollIntoView({
behavior: "smooth"
})
# 5、自定义实现
使用requestAnimationFrame
API进行模拟实现。
var scrollSmoothTo = function (position) {
// 当前滚动高度
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
// 滚动step方法
var step = function () {
// 距离目标滚动距离
var distance = position - scrollTop;
// 目标滚动位置
scrollTop = scrollTop + distance / 5;
if (Math.abs(distance) < 1) {
window.scrollTo(0, position);
} else {
window.scrollTo(0, scrollTop);
requestAnimationFrame(step);
}
};
step();
};
# 滚动到顶部案例:
当被卷曲高度超过可视区高度时,回到顶部按钮显示,小于则消失。
通过监听scroll事件来判断是否显示回到顶部按钮,并根据卷去页面的高度计算滚动速度。
var timer = null;
var isTop = true;
var btn = document.getElementById('btn');
var iH = document.documentElement.clientHeight; // 网页可见区域高度
// 在滚动条事件中实时的获取被卷去高度,和iH进行比较
window.onscroll = function() {
var oS = document.documentElement.scrollTop || document.body.scrollTop;
if (oS>iH) {
btn.style.display = 'block';
} else {
btn.style.display = 'none';
}
if (!isTop) clearInterval(timer);
isTop = false;
}
btn.onclick = function() {
// 通过定时器设置30毫秒滚动距离
timer = setInterval( function() {
// 实时的获取被卷去高度,根据高度计算滚动速率
var oS = document.documentElement.scrollTop || document.body.scrollTop;
var speed = -Math.ceil(oS/4);
// 滚动到具体位置
document.documentElement.scrollTop = document.body.scrollTop = oS + speed;
if (oS <= 0) clearInterval(timer);
isTop = true;
}, 30);
}