一、认识浏览器运行态下的JS
包含:BOM、DOM、ECMAScript
简述:
ECMAScript:基础逻辑、数据处理
DOM:对于浏览器视窗内html文件的相关处理和操作
BOM:对浏览器本身功能区域做处理
(function(context, undefined) {
const _class = ['js','vue','react'];
// 向全局作用域中进行存储
window.classArr = _class;
// 获取当前页面地址
const url = location.herf;
// 获取渲染节点
document.getElementById('app');
// 获取页面标题
document.title = 'hello world';
})(this,undefined)
二、BOM
1、location
location.href = 'http://www.baidu.com'; // 获取当前页面完整url
location.protocol = 'http'; // 获取当前协议
location.host = 'www.baidu.com'; // 获取当前主机名+ 端口
loaction.hostname = 'www.baidu.com'; // 获取当前主机名
location.port = '80'; // 获取当前端口号
location.pathname = '/index.html'; // 获取当前路径
location.search = '?name=zhangsan'; // 获取查询参数部分(以问号开头)
location.hash = '#/home'; // 获取hash值--锚点部分
location.assign(url); // 跳转到指定页面,替换pathname的值
location.reqlace(url); // 跳转到指定页面,同时会替换浏览历史
location.reload(); // 重新加载
location.toString(); // 当前完整地址字符串输出
- 面试方向: 1、location本身api的操作 2、路由相关:跳转、参数、操作 => 场景: 返回(history)、刷新(hash) 3、url处理 - 正则 | js解析
2、history
history.pushState() // 跳转到指定状态页面 history.replaceState() // 替换当前状态
- history与hash模式利弊 1、hash模式:浏览器兼容性更好,当#号后面路径发生变化时,浏览器不会重新发起请求,但会触发hashchange事件;书写不美观,同时服务端无法准确捕获路由信息 2、history模式:可读性和语义化更强,服务端可以准确捕获路由信息,但浏览器兼容性差,需要服务端配合,同时浏览器会重新发起请求,但会触发popstate事件
3、navigator
- 浏览器系统信息大集合
navigator.userAgent // 获取当前用户
- 面试 1、userAgent 读取信息 => 浏览器兼容性(如何解析和检测不同浏览器及设备) 2、剪切板、键盘;
4、screen
表示显示区域的参数 - 屏幕
- 面试 - 对于区域的判断window视窗判断:
全局入口处:window.innerWidth / innerHeight
文本处进行获取:document.documentElement.clientHeight / clientWidth | document.body.clientHeight / clientWidth
网页的size => offsetHeight = clientHeight + 滚动条 + 边框
document.documentElement.offsetHeight / offsetWidth | document.body.offsetHeight / offsetWidth
定位:scrollLeft / scrollTop -- 距离常规左 / 上; 滚动距离 offsetLeft / offsetTop -- 距离常规左 / 上 局对距离
el.getBoundingClientRect() // 获取元素在视窗内的位置信息
top: 元素上边到视窗上边的距离; left: 元素左边到视窗左边的距离; bottom: 元素下边到视窗下边的距离; right: 元素右边到视窗右边的距离;
- 兼容性:IE会多出两个像素
三、事件模型
<div id="app">
<p id="dom">click</p>
</div>
// 冒泡:p => div => body => html => document -- 逐级向上触发
// 捕获:html => document => body => div => p -- 逐级向下触发
el.addEventListener(event, function, useCapture);
// 1、如何阻止事件传播
event.stopPropagation(); // 注:无论向上还是向下都可以阻止 => 无法阻止默认事件的发生,如 a 标签的跳转
// 2、如何阻止默认事件的传播
event.preventDefault();
// 3、相同节点绑定多个同类事件,如何阻止
event.stopImmediatePropagation();
// 4、兼容性
// addEventListtener vs IE - attachEvent
// 区别:
a.传参 attachEvent 对于所有的事件名都要加上 on
b.执行顺序,attachEvent - 后绑定先执行:addEventListener - 先绑定先执行
c.解绑:detachEvent 对比 removeEventListener
d. e.cancelBubble = true; vs e.stopPropagation(); // 阻止事件传播
e.阻止默认事件 e.returnValue vs e.preventDefault(); // 阻止默认事件
// 手写统一事件绑定 兼容IE
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) {
const element = this.element;
this.element.attachEvent('on' + type, () => {
handler.call(element)
})
}
}
// 移除事件
removeEventListener(type, handler) {
if(this.element.removeEventListener) {
this.element.removeEventListener(type,handler,false)
}else if(this.element.detachEvent) {
const element = this.element;
this.element.detachEvent('on'+type, () => {
handler.call(element);
})
}
}
// 阻止事件传播(冒泡)
stopPropagation(e) {
if(e.stopPropagation) {
e.stopPropagation();
}else {
e.cancelBubble = true;
}
}
// 阻止默认事件
preventDefault(e) {
if(e.preventDefault) {
e.preventDefault();
}else {
e.returnValue = false;
}
}
}
性能优化 -- 事件代理
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<div class="context"></div>
const ul = document.querySelector('ul');
const list = ul.getElementsByTagName('li');
const context = document.querySelector('.context');
// 循环代理
for(let i = 0; i < list.length; i++) {
list[i].addEventListener('click', function() {
console.log(this.innerHTML);
}
}
// 代理后--利用冒泡
function proxy(e) {
let e = e || window.event;
if(e.target.nodeName.toLowerCase === 'li') {
const liList = this.querySelectorAll('li');
let index = Array.prototype.indexOf.call(liList, e.target);
console.log(e.target.innerHTML);
}
}
list.addEventListener('clisk', onClick, false)
四、网络层
// 实例化
const xhr = new XMLHttpRequest();
// 初始化连接
xhr.open(method, url, async);
// 发送请求
xhr.send(data);
// 接收统计
xhr.readyStatus; // 0 > 尚未调用open ,1 > 已经调用open,2 > 已经调用send, 3 > 已接收到请求,4 > 请求完成
// 接收回调
xhr.onrenadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.responseText);
}
}
}
// 设置超时
xhr.timeout = 1000;
xhr.ontimeout = () => {
console.log('超时');
}
- 面试 1、RESTFUL(接口规范):GET | POST | PUT | DELETE 2、跨域:代理(proxy)、JSONP、CORS、iframe 3、状态码:2xx、400、500、3xx => 浏览器缓存: 强缓存(expire + cache-control) | 协商缓存(last-modified + E-tag)
#### 浏览器原理
1、DOM
2、CSSOM 浏览器将css解析成树形的数据结构
3、render Tree 合并后生成具有样式 + 元素 + 层级解析树
4、Layout 计算出每个节点要渲染的位置
5、Painting 渲染
// 重排 | 重绘
reflow 元素几何尺寸发生了变化,需要重新计算layout tree
repaint 某个元素的背景、颜色、边框颜色
display: none => reflow
visibility: hidden => repaint