浏览器内置对象
浏览器js执行态
- ECMAScript - 基础逻辑,数据处理
- DOM - 浏览器视窗内文本的操作
- BOM - 浏览器本身区域能力的操作
浏览器对象模型(BOM:Browser Object Model)
主要对象有:
- window对象
- location
- navigation:获取浏览器的系统信息
- screen
- history: 保存用户上网的历史信息
location
location.href = www.zhaowa.com/search?clas…
各个部分含义
location.origin => www.zhaowa.com
location.protocol => https:
location.port => 8080
location.pathname => '/search'
location.search => '?class=browser&id=2'
location.hash => '#comments'
location.assign() 跳转到指定的path => 替换pathname
location.replace() 跳转到指定的path => 替换pathname 同时替换浏览历史
location.reload()
location.orString() 当前地址字符串
面试方向
-
location本身api操作 —— 提取相关信息、api间对比 => assign vs replace
-
assign:相当于跳转到一个新的连接,点击返回可以返回到上一个页面(=location.href)
-
replace:相当于替换当前窗口页面,没有点击返回
-
-
路由相关:跳转、参数、操作 => 场景:可返回(history)、是否刷新(hash) => replace替换assign、携带参数
- hash:根据#以及后面的字符对页面进行定位,使对应的id元素在可视区域显示,hash改变浏览器不会向服务器发送请求
- history:可以在url里放传参,会使浏览器向服务器发送请求
-
url处理 - 正则 or 手写js处理
-
URI & URL:uniform resource identifier / locator
- URI:资源标识符,当前页面的resource的id,相当于一个人的身份证,通过身份证号可以对应唯一一个资源
- URL:资源定位符,当前页面存放的路径,当前定位的地址信息,相当于通过资源的地址来对应唯一一个资源
history
history.state => 存储当前页面的状态
history.pushState()
history.replaceState()
面试方向
-
路由——history和hash的模式利弊
-
hash优缺点
优点:
a. 不需要后端配合,只需要前端配置路由表
b. 兼容性好
c. hash值改变不会发送请求
缺点:hash需要加#,不符合url规范,不美观 -
history优缺点:
优点:符合url规范,美观
缺点:
a. 在输入地址或刷新页面时会重新请求,后端需要配置index.html页面用户匹配不到静态资源的情况,否则会出现404
b. 兼容性差,利用了pushState和replaceState
-
navigator
浏览器系统信息的大集合
navigator.userAgent //获取当前用户的环境信息
面试方向
- userAgent 读取信息 => 浏览器兼容性、上报信息
- 用户代理:能够识别用户使用的操作系统及版本,CPU类型,浏览器及版本,浏览器渲染引擎,浏览器语言,浏览器插件等
- 剪切板、键盘
Navigator.clipboard仅支持通过 HTTPS 提供的页面
- 方法:writeText():异步,返回promise
navigator.clipboard.writeText('复制的内容')
.then(() => {
console.log('复制成功');
})
.catch(err => {
// 如果用户没有授权,则抛出异常
console.error('复制失败:', err);
});
- readText():读取
navigator.clipboard.readText()
.then(value => {
console.log('复制的内容', value);
})
.catch(err => {
console.error('粘贴失败: ', err);
});
- paste:粘贴
document.addEventListener('paste', async event => {
let text;
if (navigator.clipboard) {
text = await navigator.clipboard.readText()
}else {
text = event.clipboardData.getData('text/plain');
}
});
screen
表征显示区域 - 荧幕
- 面试方向 - 判断区域大小
window视窗判断:
全局入口处:
window.innerHeight
window.innerWidth
文本入口处:
document.documentElement.clientHight
document.documentElement.clientWidth
document.body.clientHight
document.body.clientWidth
网页视图size -> offsetHeight = clientHeight + 边框 + 滚动条
document.documentElement.offsetHeight
document.documentElement.offsetWidth
document.body.offsetHeight
document.body.offsetWidth
动态定位
scrollLeft / scrollTop - 距离常规左/上滚动距离
offsetLeft / offsetTop - 距离常规左/上距离
el.getBoundingClientRect().top
el.getBoundingClientRect().left
el.getBoundingClientRect().bottom
el.getBoundingClientRect().right
兼容性:ie9之前会多出2像素
浏览器事件模型
主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段
- 冒泡:从里到外
- 捕获:从外到里
addEventListener第三个参数
el.addEventListener(event,function,useCapture) // 默认第三个参数是false 当设置为true时,就是在捕获阶段 false在冒泡阶段
阻止事件传播
- e.stopPropagation() => 既能阻止冒泡,也能阻止捕获
- e.stopImmediatePropagation() => 如果有多个相同类型事件的事件监听函数绑定到同一个元素,当该类型的事件出发时,它们会按照被添加的顺序执行。如果其中某个监听函数执行了event.stopImmediatePropagation()方法,则当前元素剩下的监听函数将不会被执行
兼容性
attachEvent——兼容:IE7、IE8; 不支持第三个参数来控制在哪个阶段发生,默认是绑定在冒泡阶段 addEventListener——兼容:firefox、chrome、IE、safari、opera;
区别:
a. 传参:attachEvent 对于事件名需要加上'on'
b. 执行顺序:attachEvent - 后绑定先执行; addEventListener - 先绑定先执行
c. 解绑:detachEvent vs removeEventListener
d. 阻断:event.cancelBubble = true vs event.stopPropgation()
e. 默认事件拦截:event.returnValue = false vs event.
面试题: 手写兼容性事件绑定
class bindEvent {
constructor(element) {
this.element = element;
}
// 绑定
addEventListener = (type, handler) => {
if (this.element.addEventListener) {
this.element.addEventListener(type, handler, false)
} else if (this.element.attachEvent) {
this.element.attachEvent('on' + type, () => {
handler.call(element)
})
} else {
this.element['on' + type] = handler;
}
}
// 解绑
removeEventListener = (type, handler) => {
if (this.element.removeEventListener) {
this.element.removeEventListener(type, handler, false)
} else if (this.element.detachEvent) {
this.element.detachEvent('on' + type, () => {
handler.call(element)
})
}
}
// 阻断
static stopPropgation(e) {
if (e.stopPropgation) {
e.stopPropgation();
} else {
e.cancelBubble = true;
}
}
// 默认拦截
static preventDefault(e) {
if (e.preventDefault) {
e.preventDefault
} else {
e.returnValue = false;
}
}
}
性能优化 - 事件代理
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<div class="content"></div>
var list = document.querySelector("list");
var li = list.getElementByTagName("li");
代理前
for(var i = 0; i < li.length; i++){
li[i].addEventListener('click',function(){...})
}
代理后
function onClick(e){
var e = e || window.event;
if(e.target.nodeName.toLowerCase() === 'li'){
var liList = this.querySelectorAll('li');
...
}
}
list.addEventListener('click',onclick,false)
网络层
const xhr = new XMLHttpRequest();
xhr.open(method, url, async)
xhr.send(data) //get - 可以不传或者传入null post - encodeURIComponent编码拼接
//接收
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304)
}
}
//超时时间
xhr.timeout = 30000
xhr.ontimeout = () => {
//超时后
}
面试方向:
- TCP => HTTP/HTTPS
- 状态码 => 2xx 4xx 5xx | 3xx => 浏览器缓存 => 强缓存(Expires + cache-control) / 协商缓存(last-modeified + Etag)
浏览器原理
面试题:从url输入到页面展示发生了什么 - 获取到资源 => 渲染出页面