浏览器体系
一、浏览器运行态下的JS
BOM、DOM、ECMAScript
(function(context,undefined){
const _class = ['js','browser','vue'];
//向全局中挂载
window.classArr = _class.map(item => item)
//获取当前页面地址
const _url = location.href
// 设置tab标签
document.title = 'hhhhhh';
//获取渲染节点
document.getElementById('#app');
})(this)
浏览器JS的执行态
ECMAScripr - 基础逻辑、数据处理
DOM - 对于浏览器视窗内,文本的相应操作
BOM - 对于浏览器本身区域能力的处理
二、 BOM
1. location
- location.href => 'juejin.cn/editor/draf…' => 路径栏所有东西
- location.orgin => 'juejin.cn'
- location.protocol => 'https:'
- location.host => 'juejin.cn'
- location.port => ''
- location.pathname => '/editor/drafts/7232225892214259749'
- location.search => '?a=1'
- location.hash => '#hahah'
- location.assign('') =>跳转到指定path => 替换pathname
- location.replace('') => 同上,同时替换浏览历史
- location.reload()
- location.toString() =>产出当前地址字符串
2. history
- history.state => 存储当前页面的状态
- history.pushState()
- history.replaceState()
3. navigator
- 浏览器系统信息大集合
navigator.userAgent //获取用户当前环境信息
4. screen
表征显示区域 - 电脑荧幕
window 视窗判断:
全局入口处:
window.innerWidth
window.innerHeight
文本处获取:
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()
el.getBoundingClientRect().top
el.getBoundingClientRect().left
el.getBoundingClientRect().bottom
el.getBoundingClientRect().right
- el.getBoundingClientRect()在老版本的IE里会多出两个像素
三、Event事件模型
<div id='app'>
<p id='dom'></p>
</div>
//冒泡 - ms: p => div => body => HTML =>document
//捕获 - ns:document => HTML => body => div => p
el.addEventListener(event,function,useCapture) //默认是捕获false
//阻止事件的传播
event.stopPropgation() //阻止任何传递行为,但无法阻止默认事件
event.preventDefault() //阻止默认事件 - 例如a标签点击会跳出来
event.stopImmediatePropgation()//相同节点绑定多个同类事件
兼容性 & 性能(IE - attachEvent VS addEventListener)
区别:
- 传参:attachEvent 对于事件名需要加一个‘on’
- 执行顺序:attachEvent 后绑定先执行;addEventListener 先绑定先执行
- 解绑detachEvent VS removeEventListener
- 阻断:e.cancelBubble VS event.stopPropgation()
- 默认事件拦截:event.returnValue VS event.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(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);
})
}else{
this.element['on' + type] = null;
}
}
//阻断
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>
<li>6</li>
<li>7</li>
</ul>
<div class="content"></div>
var list = document.querySelector('list');
var li = list.getElementsByTagName('li');
//暴力
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.toLowCase() === 'li'){
var liList = this.querySelectorAll('li');
……
}
}
list.addEventListener('click',onClick,false)
四、网络层
//实例化
const xhr = new XMLHttpRequest();
//初始化建立
xhr.open(method,url,async) //get/post;请求地址;是否为异步请求
//方法的发送请求 - send
xhr.send(data) //get -可以不传或传入null,post - encodeURIComponent编码拼接
//接收
//xhr.readyStatus - 0:尚未建立open;1: 已调用open;2:已经调用send;3:已经收到请求返回;4:请求已经完成
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4){
//判断http状态码
if(xhr.status >= 200 && xhr.status <300 || xhr.status ==304){
}
}
}
xhr.timeout = 3000
xhr.ontimeout = () => {
//超时……
}
//封装
ajax({
url:'reqUrl',
method:'get',
async:true,
timeout:3000,
data:{
payload :'text'
}
}).then(
res =>{}
err =>{}
)
//实现
function ajax(options){
const {
url,
method,
async,
data,
timeout
} = options;
const chr = new XMLHttpRequest()
//配置超时时间
if(timeout){
xhr.timeout = timeout;
}
return new Promise((resolve,reject) => {
//成功
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4){
//判断http状态码
if(xhr.status >= 200 && xhr.status <300 || xhr.status ==304){
resolve(xhr.responseText)
}else{
reject()
}
}
}
//失败
xhr.onerror = err => reject(err);
xhr.ontimeout = () => reject('timeout');
//传参处理
let _params=[];
let encodeData='';
if(data instanceof Object){
for(let key in data){
//参数编码
_params.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]))
}
encodeData = _params.join('&')
}
//根据method判断连接
if(method === 'get'){
const index = url.indexOf('?')
if(index === -1){
url += '?'
}else if(index !== url.length -1){
url += '&'
}
url += encodeData
}
//建立连接
xhr.open(method,url,async)
//发送请求
if(method === 'get'){
xhr.send(null)
}else{
xhr.setRequestHeader(
'content-type':'application/x-www-form-urlencoded'
)
xhr.send(encodeData)
}
})
}
五、浏览器原理
从url输入到页面展示发生了什么(本篇只聊获取到资源到渲染出页面)
DOM
CSSOM:css解析成树形数据结构
Render Tree:DOM + CSSOM生成树
Layout module:计算Render Tree 每个节点具体的状态和位置
Painting: 呈现到屏幕上
流程
url => HTML解析( JS + DOM +CSSOM )=> render tree / JS + css执行 => layout => painting
纵向切分
bytes(62 48 65 2C ……) => characters(<html ></html>) => Tokens(tag tree) =>Nodes(html|head|body) => DOM | CSSOM