浏览器

666 阅读4分钟

浏览器内置对象

浏览器js执行态

  1. ECMAScript - 基础逻辑,数据处理
  2. DOM - 浏览器视窗内文本的操作
  3. BOM - 浏览器本身区域能力的操作

浏览器对象模型(BOM:Browser Object Model)

主要对象有:

  1. window对象
  2. location
  3. navigation:获取浏览器的系统信息
  4. screen
  5. 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() 当前地址字符串

面试方向
  1. location本身api操作 —— 提取相关信息、api间对比 => assign vs replace

    • assign:相当于跳转到一个新的连接,点击返回可以返回到上一个页面(=location.href)

    • replace:相当于替换当前窗口页面,没有点击返回

  2. 路由相关:跳转、参数、操作 => 场景:可返回(history)、是否刷新(hash) => replace替换assign、携带参数

    • hash:根据#以及后面的字符对页面进行定位,使对应的id元素在可视区域显示,hash改变浏览器不会向服务器发送请求
    • history:可以在url里放传参,会使浏览器向服务器发送请求
  3. url处理 - 正则 or 手写js处理

  4. URI & URL:uniform resource identifier / locator

    • URI:资源标识符,当前页面的resource的id,相当于一个人的身份证,通过身份证号可以对应唯一一个资源
    • URL:资源定位符,当前页面存放的路径,当前定位的地址信息,相当于通过资源的地址来对应唯一一个资源

history

history.state => 存储当前页面的状态

history.pushState()
history.replaceState()

面试方向
  1. 路由——history和hash的模式利弊

    • hash优缺点
      优点
      a. 不需要后端配合,只需要前端配置路由表
      b. 兼容性好
      c. hash值改变不会发送请求
      缺点:hash需要加#,不符合url规范,不美观

    • history优缺点:
      优点:符合url规范,美观
      缺点
      a. 在输入地址或刷新页面时会重新请求,后端需要配置index.html页面用户匹配不到静态资源的情况,否则会出现404
      b. 兼容性差,利用了pushState和replaceState

navigator

浏览器系统信息的大集合
navigator.userAgent //获取当前用户的环境信息
面试方向
  1. userAgent 读取信息 => 浏览器兼容性、上报信息
    • 用户代理:能够识别用户使用的操作系统及版本,CPU类型,浏览器及版本,浏览器渲染引擎,浏览器语言,浏览器插件等
  2. 剪切板、键盘 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像素

浏览器事件模型

主要分为三个阶段:捕获阶段、目标阶段、冒泡阶段

  1. 冒泡:从里到外
  2. 捕获:从外到里

addEventListener第三个参数

el.addEventListener(event,function,useCapture) // 默认第三个参数是false 当设置为true时,就是在捕获阶段 false在冒泡阶段

阻止事件传播

  1. e.stopPropagation() => 既能阻止冒泡,也能阻止捕获
  2. 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 = () => {
    //超时后
}

面试方向:

  1. TCP => HTTP/HTTPS
  2. 状态码 => 2xx 4xx 5xx | 3xx => 浏览器缓存 => 强缓存(Expires + cache-control) / 协商缓存(last-modeified + Etag)

浏览器原理

面试题:从url输入到页面展示发生了什么 - 获取到资源 => 渲染出页面