一、浏览器主要术语解释
w3c是web规范,浏览器要遵循的网页标准(包括超文本标记语言,html5规范,事件规范等。),ecmascript6、7、8是js运行的标准。
dom是网页文档对象模型,定义了网页文档的操作的api,bom是浏览器对象模型,定义了浏览器操作的apif,它的主要对象是windows,document是windows下的属性。
chrome是v8引擎,safiri是jscore,firefox是spidermonkey
1、encodeURI
会将元字符和语义字符之外的全转码,比如:
http://www.example.com/q=春节
http://www.example.com/q=%e6%98%78%y3
2、encodeURIComponent
http://www.example.com/q=春节
http%3a%2f%2fwww.example.com%2fq=%e6%98%78%y3
在链接跳转的时候用转义比较好。
3、dpi ----设备像素比==物理像素/逻辑像素
分辨率越大,像素点越多,即物理像素比较大,dpi越大。1px所占用的像素越少,dpi越小。
二、浏览器事件
1、浏览器事件模型分为三步,分别是捕获阶段、目标阶段,冒泡阶段,它们之间的关系是:捕获–>目标–>冒泡。
Window.addEventListener(‘click’,function(){},true)//这是捕获阶段进行触发
Window.addEventListener(‘click’,function(){},false)//这是冒泡阶段进行触发
例如:一个结构html–>body–>div–>span;这时点击了div区域,事件触发阶段为html的捕获阶段点击事件–>body的捕获阶段点击事件–>div的捕获阶段的点击事件–>div的冒泡阶段的点击事件–>body的冒泡阶段的点击事件–>window的冒泡阶段的点击事件。
2、阻止事件传播–>e.stopPropagation()。
不仅能阻止冒泡也能阻止捕获传播,如果在某个监听事件中方法中使用了e.stoppropagation,那么当前这个方法的后续还是会执行下去,只是事件的传播停止了。
3、阻止默认事件–>e.preventDefault();
比如a标签的点击事件会带默认的跳转事件,那么在a标签的点击事件中加上e.preventDefault()就不会跳转了。
4、监听同一事件,阻止其他的同一事件执行–>e.stopImmediatePropagation
5、事件委托
事件委托是基于事件冒泡这个过程触发的,例如一个ul列表,里面有很多li,我们需要把每个li点击事件都要获取。那么最简单直接的方式在每个li上进行绑定监听click事件,当有很多的li那么监听器也会越来越多,性能上会有影响。由于有事件冒泡的这个特性,可以将监听器统一绑定在父元素ul上,这样就只有一个监听器了,例如:
<ul id='qqq'>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
let ul = document.getElementById('qqq');
ul.addEventListener('click',function(e){
//e.target是当前点击的元素对象
//e.currentTarget是当前绑定监听的元素对象
if(e.target.tagName.toLowerCase()=='li'){
let liList = document.querySelectorAll('li');//伪数组
let realList = Array.from(liList);
let index = realList.indexOf(e.target)//当前点击元素的索引,对象都有了,就可以根据它处理对应的事了
//另一种伪数组调用indexof的方法
let index = Array.prototype.indexOf.call(liList,e.target)
}
})
6、事件监听不同浏览器不同的监听方法,ie浏览器使用的是attachEvent且默认是绑定在冒泡阶段,以下是实现一个类来兼容不同浏览器的监听方法
class addEventClass {
constructor(element) {
this.element = element;
}
addEvent(event,handler) {
if(this.element.addEventListener) {
this.element.addEventListener(event, handler, false);
} else if(this.element.attachEvent) {
this.element.attachEvent('on'+event,handler);
} else {
this.element['on'+event] = handler;
}
}
removeEvent(event,handler) {
if(this.element.removeEventListener) {
this.element.removeEventListener(event, handler, false);
} else if(this.element.detachEvent) {
this.element.detachEvent('on'+event,handler);
} else {
this.element['on'+event] = null;
}
}
}
function stopPropagation(ev) {
if(ev.stopPropagation){
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
}
function preventDefault(ev) {
if(ev.preventDefault){
ev.preventDefault();
} else {
ev.returnValue = false;
}
}
浏览器常用属性及事件:
一个网络联网的功能:
window.addEventListener('load',function(){
var status = document.getElementById('status');
var log = document.getElementById('log');
function updateOnlineStatus(event) {
status.innerHTML = navigator.onLine?'online':'offline';
log.insertAdjacentHTML('beforeend',`event${event.type}`)
}
window.addEventListener('online',updateOnlineStatus);
window.addEventListener('offline',updateOnlineStatus);
})
var {connection} = navigator;
var type = connection.effectiveType;
function updateConnectionStatus(){
console.log(`网络从${type}切换至${connection.effectiveType}`);
type = connection.effectiveType;
}
connection.addEventListener('change',updateConnectionStatus)
三、浏览器请求
1、响应码:
200:get请求成功
201:post请求成功
301:永久重定向
302:暂时重定向
304:协商缓存,服务器文件未修改
400:请求参数错误,不被服务端识别
401:身份未认证
403:服务器收到请求,但拒绝提供服务,可能跨域
404:资源未找到
405:请求方式有误
500:服务器内部错误
503:服务器当前无法处理,临时状态
504:网关错误
2、为什么常见的cdn域名和业务域名不一致?
- 安全性,浏览器有一个同源策略,不同域名不会携带cookies
- 提高带宽利用率,上cdn的资源比如图片等就为了快速拉取,携带cookie浪费带宽资源
- 避免产生最大并发请求数,因为浏览器规定同源同域名请求数同一时间请求有限制。
3、针对单页面index.html要求用缓存是协商缓存好还是强缓存?
html里的script和css后面都有hash值,只要重新发布,hash就会变换。
如果index.html使用强缓存,那么在强缓存期间想要重新发布就无法更新有很大的问题。当使用协商缓存,当重新打包时,script和css的hash值变化,index.html检查到自己内容的改变就发起重新请求。
一般请求index.html不做缓存,no-cache,no-store,因为html文件比较小。
4、浏览器ajax和fetch简单实现
ajax:
let xml = new XMLHttpRequest();
xml.open('GET','http://xxx.com');
xml.onreadystatechange = function() {
if(xml.readyState == 4) {
//readyState有5种状态
//0:请求初始化
//1:服务器已经建立链接
//2:请求已经接收----发送数据阶段
//3:请求处理中----接收数据状态
//4:请求完成
if(xml.status == 200) {
console.log(xml.responseText);
}
}
}
xml.send();
xml.timeout = 1000;
xml.ontimeout = function() {
}
xml.upload.onprogress = p => {
console.log(p.loaded/p.total);
}
fetch:
特点:
1、不携带cookie
2、500的错误不会reject
3、不支持超时设置
4、
//不携带cookie
fetch('http://xxx.com',{
method:'GET',
}).then(response => response.json()
).then(json => console.log(json)
).catch(error => console.log(error))
//同域携带cookie
fetch('http://xxx.com',{
method:'GET',
credentials:'same-origin',
}).then(response => response.json()
).then(json => console.log(json)
).catch(error => console.error(error))
//fetch返回的错误不会直接进入catch,需要通过response.ok来判断手动触发catch
fetch('http://xx.com',{
method:'GET'
}).then(response => {
if(response.ok) {
return response.json();
}
throw new Error('fetch return is not ok')
}).then(json => console.log(json)
).catch(error => console.error(error));
//不支持直接设置超时,可以如此做
function timeOut(url, init, time) {
return new Promise((resolve,reject) => {
fetch(url, init).then(resolve).catch(reject);
setTimeout(() => reject, time);
})
}
//用AbortController来中止fetch
let controller = new AbortController();
fetch('http://xxx.com',{
method:'GET',
siganl:controller.siganl,
})
controller.abort();
四、ajax兼容使用ts实现
interface Option {
url:string,
method?:'GET'|'POST',
data:any,
timeout:number,
}
function transferData(data: any) {
let returnList = [];
for(let key in data) {
//这里去encode是因为怕data里有url的字符会影响真的url
returnList.push(`${key}=${encodeURIComponent(data[key])}`);
}
return returnList.join('&');
}
export function ajaxTs(options: Option) {
return new Promise((resolve, reject) => {
if(!options.url) {
return;
}
let xhr;
if((window as any).XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject('Microsoft.XMLHTTP')
}
let queryData = transferData(options.data);
let timer = null;
const handleStatus = () => {
xhr.onreadystatechange = function() {
if(xhr.readyState == 4) {
clearTimeout(timer);
if(xhr.status >=200 && xhr.status < 300 || xhr.status == 304) {
resolve(xhr.responseText);
} else {
reject(xhr.status);
}
}
}
}
if(options.method.toUpperCase()=='GET') {
xhr.open('GET',options.url+'?'+queryData);
handleStatus();
xhr.send();
} else if(options.method.toUpperCase() == 'POST') {
xhr.open('POST',options.url);
xhr.setRequestHeader('contentType','application/x-www-form-urlencoded')
handleStatus();
xhr.send(options.data);
}
if(options.timeout){
timer = setTimeout(() => xhr.abort(), options.timeout);
}
})
}
五、webcomponents
webcomponents是浏览器原生的创建可重用的自定义元素,实现自定义标签,对于夸框架复用有帮助。
它主要实现方式有
- customElements
- template----可重用的一套模版,包括html.style等
- shadow dom 用于隔离自定义元素和样式。
前两个实现方式都可以用于slot显示。三种方式哦都必须继承HTMLElement。
常见的webcomponents库有polymer、x-tag、stonel等等。
例如:
class TextIcon extends HTMLElement {
constructor() {
super()
this._text = null;
}
static observedAttributes = ['text'];
attributeChangedCallback(name, oldValue, newValue) {
this._text = newValue;
this.updateRender();
}
connectedCallback() {
this.updateRender();
}
get text () {
return this._text;
}
set text(v) {
console.log(v, 'ss')
this.setAttribute('text', v)
}
updateRender () {
this.innerText=this._text
}
}
customElements.define('text-icon', TextIcon)
使用
<text-icon text="test1"></text-icon>
const textIcon = document.createElement('text-icon')
textIcon.setAttribute('text', 'sddd')
document.body.appendChild(textIcon)
const textIcon1 = new TextIcon()
textIcon1.text = 12
document.body.appendChild(textIcon1)