web前端--浏览器相关

web前端–浏览器相关

1、什么是浏览器对象模型(BOM–brower object model)

BOM:提供独立于内容的、可以与浏览器窗口进行滑动的对象结构,就是浏览器提供的API

主要有:

1-1、window对象:对象–BOM的核心,是js访问浏览器的接口,也是es规定的global对象
在这里插入图片描述

​ 不常用:alert(单按钮)、confirm(双按钮)、prompt(用户输人相关)

​ 常用:open(打开新页面)、

​ onerror(前端监听全局报错–如资源加载报错、代码报错,监控关键业务节点的运 行是否正常–如下 单、支付等)、

​ setTimeout(指定一段时间间隔执行完函数,只执行一次):相关面试题如下

​ 如何使用setTimeout实现setInterval?(利用递归实现)

function mySetInterval(fn,millisec,count){
    function Interval(){
        if(typeof count ==='undefined' || count -->0){
            setTimeout(Interval,millisec);
            try{
                fn();
            }catch{
                count = 0;
                throw e.toString();
            }
        }
    }
    setTimeout(Interval,millisec);
}

​ setInterval(在固定时间间隔内不断执行函数)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYprtoZk-1641348255591)(C:\Users\xjj\Downloads\web07 03.浏览器相关\day03.浏览器相关\OpenCourse - 浏览器内置对象详解\OpenCourse - 浏览器内置对象详解\assets\window对象_窗口位置.png)]
在这里插入图片描述

1-2、location对象:提供当前窗口中的加载的文档有关的信息和一些导航功能。window和document的对象属性

在这里插入图片描述

1-3、navigation对象:获取浏览器的系统信息(websocket中用于网络监听比较多 onLine)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Or3KvB1W-1641348255594)(C:\Users\xjj\Downloads\web07 03.浏览器相关\day03.浏览器相关\OpenCourse - 浏览器内置对象详解\OpenCourse - 浏览器内置对象详解\assets\navigation对象.png)]

1-4、screen对象:用来表示浏览器窗口外部的显示器的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MIfj8mi3-1641348255595)(C:\Users\xjj\Downloads\web07 03.浏览器相关\day03.浏览器相关\OpenCourse - 浏览器内置对象详解\OpenCourse - 浏览器内置对象详解\assets\screen对象.png)]

1-5、history对象(应用最多):保存用户上网的历史信息

​ go(-1) = back() go(1) = forword()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZE5cv0xV-1641348255596)(C:\Users\xjj\Downloads\web07 03.浏览器相关\day03.浏览器相关\OpenCourse - 浏览器内置对象详解\OpenCourse - 浏览器内置对象详解\assets\history对象.png)]ho

pushState(当前栈中推入一个栈) onPopState(一个栈推出时调用当前栈的回调函数)

2、浏览器事件模型详解## 标题

2-1、事件捕获、事件冒泡相关

相关面试题:

i.事件委托/事件代理的过程和原理

​ 阶段:捕获阶段->目标阶段 ->冒泡阶段

​ 例子、点击input过程(window->body->input->body->window)

ii.如何监听一个捕获事件/冒泡事件(见下面的代码)

// 场景设计题
// 有一个页面,里面有许多元素,包括div p button等
// 每个元素上都有自己的click事件,都不相同
// 现在来了一个新的需求,一个用户进入这个页面的时候,会有一个状态banned,作用在全局作用域上window.banned存在
// banned:true 当前用户被封禁,用户点击当前页面上的任何元素,都不执行原来的click逻辑,而是alert弹窗,提示你被封禁了
// banned:false 不做任何操作
// 在最外层捕获事件上做拦截或写一个全屏的 最高层级的元素 遮罩住整个页面
//index.js
const parent = document.getElementById("parent");
const child = document.getElementById("child");
const son = document.getElementById("son");
// const baidu = document.getElementById("a-baidu");

// baidu.addEventListener('click', function (e) {
//     e.preventDefault();
// })
const banned = true;
window.addEventListener("click", function (e) {
    if(banned){
        e.stopPropagation();
        alert('你被封禁了!')
        return;
    }
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
// 这里true是监听捕获阶段、false是监听冒泡阶段
parent.addEventListener("click", function (e) {
    // e.stopPropagation();
	//  阻止后续事件传播(捕获、冒泡)
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);

child.addEventListener("click", function (e) {
    console.log("child 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);

son.addEventListener("click", function (e) {
    console.log("son 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);

window.addEventListener("click", function (e) {
    // e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
    console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

parent.addEventListener("click", function (e) {
    console.log("parent 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

child.addEventListener("click", function (e) {
    console.log("child 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

son.addEventListener("click", function (e) {
    console.log("son 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);

//index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>事件代理</title>
</head>
<body>
    <div id="parent" class="flex-center">
        parent
        <p id="child" class="flex-center">
            child
            <span id="son" class="flex-center">
                son
                <a href="https://www.baidu.com" id="a-baidu">点我啊</a>
            </span>
        </p>
    </div>
    <script type="text/javascript" src="index.js"></script>
</body>
<style>
    #parent{
        background-color: bisque;
        width: 700px;
        height: 700px;
    }
    #child{
        background-color: chocolate;
        width: 500px;
        height: 500px;
    }
    #son{
        background-color: crimson;
        width: 300px;
        height: 300px;
    }
    .flex-center{
        display: flex;
        justify-content: center;
        align-items: center;
        font-size:20px ;
    }
</style>
</html>
// 写一个兼容性比较好的事件操作的类
class BomEvent{
    constructor(element){
        this.element = element;
    }
    addEvent(type,handler){
        if(this.element.addEventListener){
            this.element.addEventListener(type,handler,false);
        }else if(this.element.attachEvent){
            this.element.attachEvent(`on${type}`,function(){
                handler.call(element);
            });
        }else{
            this.element[`on${type}`] = handler;
        }
    }
    removeEvent(type,handler){
        if(this.element.removeEventListener){
            this.element.removeEventListener(type,handler,false);
        }else if(this.element.detachEvent){
            this.element.detachEvent(`on${type}`,handler);
        }else{
            this.element[`on${type}`] = null;
        }
    }
}
// 兼容的阻止事件传播
function stopPropagation(ev){
    if(ev.stopPropagation){
        ev.stopPropagation();
    }else{
        ev.cancelBubble = true;
    }
}
// 兼容的阻止默认事件
function preventDefault(event){
    if(event.preventDefault){
        event.preventDefault();
    }else{
        event.returnValue = false;
    }
}

事件代理应用的具体例子

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dfsfdfd</title>
</head>

<body>
<ul id="ul">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
    <li>6</li>
    <li>7</li>
    <li>8</li>
</ul>
    <script type="text/javascript">
        // const liList = document.getElementsByTagName('li');
        // 性能损耗过大,对原生DOM的操作次数太多
        // for(let i = 0;i<liList.length;i++){
        //     liList[i].addEventListener('click',function(e){
        //         alert(`内容为${e.target.innerHTML},索引为${i}`);
        //     })
        // }
        // 事件委托/代理实现
        const ul = document.querySelector('ul');
        ul.addEventListener('click',function(e){
            const target = e.target;
            console.log(e);
            if(target.tagName.toLowerCase()==="li"){
                const liList = this.querySelectorAll('li');
                // 这是一个伪数组
                // 转换成真实数组
                // const reaalLiList = Array.from(liList);
                // const index = reaalLiList.indexOf(target); 
                const index = Array.prototype.indexOf.call(liList,target);
                // 原型链改变this绑定提取伪数组的索引
                alert(`内容为${target.innerHTML},索引为${index}`);
            }
        })
    </script>
</body>
<style>
    #ul{
        background-color: gray;
        width: 700px;
        position: relative;
        display: flex;
        flex-direction: column;
        align-items: center;
    }
    li{
        margin-bottom: 20px;
        width: 80%;
        height: 100px;
        display: flex;
        justify-content: center;
        align-items: center;
        background-color: lightgoldenrodyellow;
        font-size: 20px;
        font-weight: bold;
    }
</style>
</html>

3、浏览器请求相关内容详解

3-1.原生ajax请求的完整过程


// 新建实例对象
const xhr = new XMLHttpRequest();
// 建立请求
xhr.open('GET','http://restapi.amap.com/v3/geocode/geo?key=2301ec0fe87784572dfb4401a28cc853&address=中国浙江省杭州市钱塘新区学林');
// 状态监听
xhr.onreadystatechange = function(){
    if(xhr.readyState !==4){
        return;
    }
    if(xhr.status === 200){
        console.log(xhr.responseText);
    }else{
        console.error(`HTTP ERROR,status=${xhr.status},errorText=${xhr.statusText}`);
    }
}
// 请求超时报错
xhr.timeout = 3000;
xhr.ontimeout = ()=>{
    console.log(`当前请求超时!`)
}
// 监听文件的上传
xhr.upload.onprogress= p=>{
    // 查看文件上传进度
    const percent = Math.round(((p.loaded / p.total)*100))+'%';
}
// 发送请求
xhr.send();

3-2、fetch请求

// 添加控制器到请求体中中断fetch请求
const controller = new AbortController();
fetch('http://restapi.amap.com/v3/geocode/geo?key=2301ec0fe87784572dfb4401a28cc853&address=中国浙江省杭州市钱塘新区学林',{
    method:'GET',
    credentials:'same-origin',
    signal:controller.signal
}).then(response=>{
    if(response.ok){
        return response.json();
    }
    throw new Error('http error');
}).then(json=>{
    console.log(json);
}).catch(error=>{
    console.error(error);
})
// 事件中断
controller.abort()
// 封装fetch的超时逻辑
function fetchTimeout(url,init,timeout=3000){
    return new Promise((resolve,reject)=>{
        fetch(url,init).then(resolve).catch(reject);
        //resolve情况下不会执行,reject下超时才会执行
        setTimeout(reject,timeout);
    })
}
fetchTimeout('http://restapi.amap.com/v3/geocode/geo?key=2301ec0fe87784572dfb4401a28cc853&address=中国浙江省杭州市钱塘新区学林',
{method:'GET',credentials:'same-origin'},30)

小练习(封装一个通用的异步函数的超时逻辑)

function AllTimeout(fn,timeout){
    return new Promise((resolve,reject)=>{
        fn.then(resolve).catch(reject);
        setTimeout(()=>{
            reject(new Error('请求超时!'))
        },timeout)
    })
}

相关面试题

i.为什么常见的cdn域名和业务域名不一样?(如www.baidu.com 业务域名 ;cdn.baidu-aa.com cdn域名)

first: 出于安全考虑(cookie中包含了很多用户的相关身份信息,公司是不乐意把自己产品下的用户信息抛给其他厂商–如第三方cdn厂商),如果两者域名相同,在浏览器策略的限制下,在发送cdn请求时也会携带上业务的cookie信息

second:请求头会携带cookie,若域名相同,每一个静态资源的请求无谓地消耗更多资源(带宽、流量的消耗)

third:并发请求数(http1.1限制同一域名同一时间最多发送的请求数),同域导致请求冲突,绕过并发请求数

http2.0涉及到多路复用,没有并发请求数的限制

3-3 请求头

method(get post等)

path(请求的接口路径)

cookie(浏览器本地存储的信息,如用户身份和密码)

referer(包含一个url,判断浏览器来自哪个页面)

user-agent(判断环境, 向访问网站提供你所使用的浏览器类型及版本、操作系统及版本、浏览器内核、等信息的标识,每个app中会有一个特殊的标识 )

access-control-allow-origin(用于限制哪些路径下的请求可以访问服务器的资源)

content-encoding:gzip(资源压缩,减少资源消耗)

set-cookie:login(用户登录完成后返回的标示信息如userId等cookie,注入到浏览器环境之中)

3-4 状态码

200(get请求成功)

201(post请求成功)

301(永久重定向)

302(临时重定向)

304(协商缓存,服务器文件未修改)

http缓存分为强缓存和协商缓存,前者通过max-age(依赖时间偏移)、expired(代表过期时间)来标识

协商双方是浏览器和服务器,last-modified(上一次的修改时间),判断缓存是否已经修改,etag(文件内容

进行哈希操作来判断文件内容是否已经修改,比较消耗资源)

面试题:vue/react等都会存在一个index.html文件,也就是所谓的单页,针对index.html文件,如果要做缓存,适合做什么缓存?

答:协商缓存,强缓存时如果加载的script代码存在错误,需要比较长时间后修正的代码才能作用到index.html,

​ 摒弃了h5的优点,更新无法实时下发到客户端。协商缓存每一次打包生成html文件时,文件中的script标签都

​ 会发生改变,浏览器会对比两个script文件的内容变化,改变就认为发生了更新,浏览器拉取更新后的代码

3-5 ts版本的ajax封装

缓存,服务器文件未修改)

http缓存分为强缓存和协商缓存,前者通过max-age(依赖时间偏移)、expired(代表过期时间)来标识

协商双方是浏览器和服务器,last-modified(上一次的修改时间),判断缓存是否已经修改,etag(文件内容

进行哈希操作来判断文件内容是否已经修改,比较消耗资源)

面试题:vue/react等都会存在一个index.html文件,也就是所谓的单页,针对index.html文件,如果要做缓存,适合做什么缓存?

答:协商缓存,强缓存时如果加载的script代码存在错误,需要比较长时间后修正的代码才能作用到index.html,

​ 摒弃了h5的优点,更新无法实时下发到客户端。协商缓存每一次打包生成html文件时,文件中的script标签都

​ 会发生改变,浏览器会对比两个script文件的内容变化,改变就认为发生了更新,浏览器拉取更新后的代码

3-5 ts版本的ajax封装

// 约束入参类型
// ?:的是可选参数
interface IOptions {
    url: String,
    type?: "GET" | "POST";
    data: any;
    timeout?: number
}
// 把对象中的data转换成queryString形式(a=xxx&b=xxxx),拼接到url上
function formatUrl(object){
    let dataArr = [];
    for(let key in object){
        dataArr.push(`${key}=${encodeURIComponent(object[key])}`);
    }
    return dataArr.join("&");
}
// ts版本的ajax的封装
export function ajax(options: IOptions = {
    type: 'GET',
    data: {},
    timeout: 3000,
    url: ""
}) {
    return new Promise((resolve, reject) => {
        if (!options.url) {
            return;
        }
        const queryString = formatUrl(options.data);
        // 状态监听
        const onStateChange = ()=>{
            xhr.onreadystatechange=()=>{
                if(xhr.readyState===4){
                    // 请求成功后清除超时定时器
                    clearTimeout(timer);
                    if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
                        resolve(xhr.responseText);
                    }else{
                        reject(xhr.status);
                    }
                }
            }
        }
        let timer;
        let xhr;
        // 创建请求实例
        // 考虑兼容性
        if((window as any).XMLHttpRequest){
            xhr = new XMLHttpRequest();
        }else{
            xhr = new ActiveXObject("Microsoft.XMLHTTP");
        }
        // 建立请求
        if(options.type.toUpperCase()==="GET"){
            xhr.open('GET',`${options.url}?${queryString}`);
            onStateChange();
            xhr.send();
        }else if(options.type.toUpperCase()==="POST"){
            xhr.open('POST',`${options.url}`);
            xhr.setRequestHeader('ContentType','application/x-www-form-urlencoded');
            onStateChange();
            xhr.send(options.data);
        }
        // 请求超时的处理
        if(options.timeout){
            timer = setTimeout(()=>{
                // 中断请求
                xhr.abort();
                reject('timeout');
            },options.timeout)
        }
    })
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值