浏览器内置JS对象, 事件模型

150 阅读3分钟

浏览器相关

一, 认识浏览器运行态下的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() // 产出当前地址字符串
          
  
  • 面试方向
  1. location 本身的api操作
  2. 路由相关: 跳转, 参数, 操作 => 场景: history | hash
  3. url处理 - 正则or 手写处理

history

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

history.pushState() // 流转到指定状态页面 .replaceState() // 替换当前状态

  • 面试 - 路由方向 history & hash 模式

navigator

  • 浏览器系统信息大集合
    navigator.userAgent // 获取当前用户相关基础信息
  • 面试方向
    1. UA读取信息 => 数据采集, 流量监控, 浏览器兼容性优化
    2. 剪切板, 键盘 => 如何做剪切板, 监听用户键盘输入

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 = () => {
        // 超时操作
        
    }
    
  • 面试
  1. RESTFUL - GET POST PUT DELETE
  2. 跨域 - CORS, JSONP(audio img,只能get),
  3. 状态码 - 浏览器缓存 3XX 强缓存, 协商缓存 cacach control lastmodify

浏览器执行

URL => 地址解析 => 获取到具体节点 => 文档load => JS CSS document => DOM | CSSOM | JS逻辑 => render tree = DOM + CSSOM | JS => LAYOUT tree => paint

  • 面试: 重排(重新生成layout tree) 重绘(paint)

避免反复重排(几何尺寸), 减少重绘(颜色,文字,边框, 不影响边框)