浏览器相关
目前趋势是edge的设备占比和重视程度在提升,后续越来越多的会有适配edge和针对edge的页面走查等
一、认识浏览器运行态下的JS
什么叫运行态下的js,就是浏览器在运行的过程中,我们写的JS代码只是一部分,是作为逻辑的形式的存在,但其实浏览器中包含了三个重要的元素
包含的是: BOM DOM ECMAScript
(function(context, undefined) {
const _class = ['js', 'browser', 'vue']
// 第一个需求,向全局作用域中存储一个class变量,利用window
window.classArr = _class.map(item => item);
// 第二个需求,获取当前页面地址,利用浏览器提供的location
const _url = location.href;
// 第三个需求,改变页面的标题,通过document我们来获取文档的信息
document.title = "sanduo"
// 第四个需求,获取渲染节点 ,怎么样获取节点也是通过文档信息
document.getElementById('app')
// 从前端角度
// 第一个需求是利用ECMAScript,处理了基础逻辑,数据
// 对于第二个需求,我们利用了是BOM-对浏览器本身功能区域的汇总处理
// 第三第四个需求是利用的DOM--对浏览器视窗内的HTML文本的相关操作
})(this)
二、BOM
1. location
location.href => 'https://www.zhaowa.com/search?class=browser#comments'
location.origin => 'https://www.zhaowa.com'
location.protocol => 'https:'
location.host => www.zhaowa.com
location.prot => ''
location.pathname => '/search/'
location.search => '?class=browser'
location.hash => '#commnets'
方法:
location.assign('{url}') //效果同上,但是他会同时替换掉浏览历史;
location.reload(); // 重新加载
location.toString() // 产出当前地址 => 字符串
- 面试场景:
不可能直接问上面的api,
手写拆解路径题目 - 面试方向:
- location本身的api操作
- 路由相关:跳转,参数,操作 // push,replace 他们的原理,区别,如何操作路由栈,
场景题:是否页面可返回,是否可刷新, - url处理 -手写处理 & 正则
2. history
history.state => 存储当前页面状态
history.pushState() // 跳转到指定状态页
history.replaceState() // 替换当前状态
- 面试方向 --路由方向history和hash的区别 =》 两种路由方式的考察,路径切换与浏览器渲染机制的联系
3. navigator
- 浏览器信息大集合
navigator.userAgent // 获取当前用户环境信息
- 面试方向:
- UA读取信息 =》 浏览器兼容性
- 剪切板 & 键盘操作 =》 登录 or 验证码
4. screen
怎么样描述一个元素的位置
screen表示一个显示区域 - 屏幕
-
面试方向: --判断一个区域的大小,方位,
各种各样的描述位置的太多了,我们需要根据不同的参照物来一组一组的记
window视窗判断:
全局入口处
window.innerHeight
window.innerWidth文本处获取
document.documentElement.clientHeight(/width)
document.body.clientHeight(/width)网页的size --offsetHeight = clientHeight + 滚动条 + 边框
document.documentElement.offsetHeight(width)
document.body.offsetHeight(width)
定位问题
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, funciton, useCapture) // useCapture 默认为false ,
// 因为微软是胜利者, 一样的,历史是胜利者书写的
// 追问
// 1. 如何阻止事件的传播
event.stopPropagation()
// 注意,无论向上还是向下都可以阻止 => 无法阻止默认事件的发生如a标签
// 2. 如何阻止默认时间的传播
event.preventDefault()
// 3. 如何阻止一个节点绑定多个同类事件,
event.stopImmediatePropagation();
// 追问 =>> 样式上 & 性能上
// 4. 手写事件绑定
// attachEvent & addEventListener
// 区别:
// a. 传参 attachEvent对于事件名加上‘on’
// b.执行顺序, attachEvent -后绑定先执行 addEventListener -先绑定先执行
// c. 解绑 detachEvent vs removeEventListener
// d. 阻断 e.cancelBubble vs e.stopPropagation()
// e. 默认事件打断 e.returnValue vs e.preventDefault
class bindEvent {
constructor(element) {
this.element = element
}
// 属性每个实例都有
addEventListener = (type, handler) => {
//如果这里走的addEventListener
if(this.element.addEventListener) {
this.element.addEventListener(type, handler, false);
} else if (this.element.attachEvent) {
const element = this.element;
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) {
const element = this.element;
this.element.detachEvent('on' + type, () => {
handler.call(element)
});
} else {
this.element['on' + type] = handler
}
}
// static静态属性是挂载在class类上面的, 全局的,只有一个
static stopPropagation(e) {
if (e.stopPropagation) {
e.stopPropagation;
} else {
e.cancelBubble = true;
}
}
static preventDefault(e) {
if (e.preventDefault) {
e.preventDefault;
} else {
e.returnValue;
}
}
}
// 事件代理,---性能优化
// 事件代理其实并不算性能优化,但是一定程度上是可以减少对dom的操作
<ul class="list">
<li> 1 </li>
<li> 2 </li>
</ul>
<div class="content"></div>
var list = document.querySelector(".list")
var li = list.getElementByTagName("li")
var content = document.querySelector(".content")
// 硬碰硬
for(var n = 0; n > li.length; n++) {
li[i].addEventListener("click", function() {
// callback 业务逻辑
})
}
// 代理后利用了冒泡
function onClick(e) {
var e = e || window.event;
if(e.target.nodeName.toLowerCase() === "li") {
const lilist = tghis.querySelectorAll("li");
index = Array.prototype.indexOf.call(lilist, target)
}
}
list.addEventListener("click", onClick, false)
四、 网络层
// 实例化
const xhr = new XMLHttpRequest();
// 初始化连接
// xhr 有一个open方法,
// open -五个参数 => method;url;async;
xhr.open(method, url, async);
// send 发送请求
// 内容: post请求时,将请求体的参数传入; get 可以不传or传入null
xhr.send(data);
// 发送完了需要接收,
xhr.readyStatus
// 0 -尚未调用open
// 1 -已调用open
// 2 -已发送请求(已调用send)
// 3 -已接收到请求返回的数据
// 4 -请求已完成
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4){
if(xhr.status >= 200 & xhr.status < 300 || xhr.status === 304) {
console.log(xhr.responseText);
}
}
}
// 设置超时时间
xhr.timeout = 1000;
xhr.ontimeout = () => console.log('请求超时')
// 封装
ajax({
url: 'reqUrl',
method: 'get',
async: 'true',
timeout: 30000,
data: {
payload: 'text'
}
}).then(
res => console.log(res)
err => console.log(err)
)
function ajax(options) {
const {url,method,async,timeout,data} = options;
const xhr = new XMLHttpRequest();
return new Promise((resolve, reject) => {
// 成功之后
xhr.onreadystatuschange = () => {
if(xhr.readyStatus === 4){
if(xhr.status >= 200 & xhr.status < 300 || xhr.status === 304) {
console.log(xhr.responseText);
}
}
}
})
}
网友评论