浏览器相关
一, 认识浏览器运行态下的JS
包含: BOM DOM ECMAScript
(function(context, undefined) {
const _class = ['js', 'browser', 'vue']
// 向全局作用域中存储
window.classArr = _claa.map(item => item)
// 获取当前页面的地址
const _url = location.href
// 设置页面标题
document.title = 'zhaowa class'
// 获取渲染节点
document.getELementById('app')
})(this)
// 简述
// ECMAScript - 基础逻辑, 数据处理
// DOM - 对于浏览器视图内HTML文本相关操作
// BOM - 对于浏览器本身功能区的相关操作
BOM
location
location.href => 'https://www.zhaowa.com/search?class=browser#comments'
.protocol => 'https:'
.host => 'www.zhaowa.com'
.origin => 'https://www.zhaowa.com'
.port => '8080'
.pathname => '/search/'
.search => '?class=browser'
.hash => '#comments' // 单页路由 | iframe 通信
// 修改
location.assign('...') // 跳转到指定的path, 替换pathname的值
.replace('...') // 效果同上,同时替换浏览器历史
.reload() // 刷新
.toString() // 产出当前地址字符串
- 面试方向
- location 本身的api操作
- 路由相关: 跳转, 参数, 操作 => 场景: history | hash
- url处理 - 正则or 手写处理
history
history.state => 存储当前页面的状态
history.pushState() // 流转到指定状态页面 .replaceState() // 替换当前状态
- 面试 - 路由方向 history & hash 模式
navigator
- 浏览器系统信息大集合
navigator.userAgent // 获取当前用户相关基础信息
- 面试方向
- UA读取信息 => 数据采集, 流量监控, 浏览器兼容性优化
- 剪切板, 键盘 => 如何做剪切板, 监听用户键盘输入
screen
表示显示区域 - 屏幕
-
面试方向 - 判断区域大小 window 视窗判断
// 全局入口 window.innerHeight window.innerWidth // 文本处获取 document.documentElement.clientHeight document.documentElement.clientWidth document.body.clientHeight 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 / .left / .bottom /.right // 兼容性, - IE 会多出2px
event事件模型
<div id="app">
<p id="dom">Click</p>
</div>
// 冒泡: p => div => body => html => document
// 捕获: document => html => body => div => p
el.addEventListener(event, function, useCapture) // useCapture 默认false
// 追问
// 1. 如何组织事件的传播
event.stopProgation()
// 注意: 无论向上还是向下都是可以阻止 =》 无法阻止默认事件的发生
// 2. 如何组织默认事件传播
event.prevenDefault()
// 3. 如何阻止相同节点绑定多个同类事件 => 兼容性 & 性能
event.stopImmediateProgation()
// 4. 手写, 实现一个多浏览器兼容的事件绑定
// attachEvent vs addEventListener
// 区别:
// a, 传参, attachEvent 对于事件名需要加上一个'on'
// b, 执行顺序, attachEvent --后绑定先执行, addEventListener - 先绑定先执行
// c, 解绑detachEvent vs removeEventListener
// d, 阻断e.cancelBubble = true vs e.stopPropagation()
// e, 阻断默认事件, returnValue vs e.preventDefault
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(this.element)
})
} else {
this.elemnet['on' + type] = handler
}
}
removeEventListener(type, handler) {
if (this.removeEventListener) {
this.element.removeEventListener(type, handle, false)
} else if (this.element.detachEvent) {
this.elment.detachEvent('on' + type, handler)
} else {
this.element['on'+ type] = null
}
}
static stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation()
} else if (e.cancelBubble) {
e.cancelBubble = true
}
}
static preventDefault(e) {
if (e.preventDefault) {
e.preventDefault()
} else {
e.returnValue = false
}
}
}
// 5, 性能 - 事件代理
<ul class='list'>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<div class='content'></div>
var list = document.querySelector('.list')
var li = list.getElementsByTagName('li')
var content = document.querySelector('.content')
//
for(var n = 0; n < li.length; n++){
li[n].addEventListener('click', function(){
// ...
})
}
// 代理 - 利用冒泡
function onClick(e){
var e = e || window.event
if (e.target.nodeName.toLowerCase() === 'li') {
const liList = this.querySelector('li')
const index = Array.prototype.indexOf.call(liList, target)
}
}
list.addEventListener('click', onClick, false)
网络层
// 实例化
const xhr = new XMLHttpRequest()
// 初始化链接
xhr.open(method, url, async)
// send发送消息
xhr.send(data) // data- encodeURICompenent
// 接收
xhr.readyStatus
// 0 - 尚未调用open方法
// 1 - 已经调用了open
// 2 - 已经send
// 3 - 已经收到请求的返回数据了
// 4, - 请求已完成
xhr.onreadystatechange = () => {
if (xhr.readyStatus === 4) {
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log('success', xhr.responseText)
}
}
}
// 超时时间
xhr.timeout = 1000
xhr.onTimeout = () => {
// 超时操作
}
- 面试
- RESTFUL - GET POST PUT DELETE
- 跨域 - CORS, JSONP(audio img,只能get),
- 状态码 - 浏览器缓存 3XX 强缓存, 协商缓存 cacach control lastmodify
浏览器执行
URL => 地址解析 => 获取到具体节点 => 文档load => JS CSS document => DOM | CSSOM | JS逻辑 => render tree = DOM + CSSOM | JS => LAYOUT tree => paint
- 面试: 重排(重新生成layout tree) 重绘(paint)
避免反复重排(几何尺寸), 减少重绘(颜色,文字,边框, 不影响边框)