因为篇幅过于长,知识体系过于庞杂,请谨慎学习, 转述的我都有放置连接(难理解的也放了demo测试或者图)javascript
技术规范(基础了解,大佬尽可跳过)php
ES5/ES6等历程了解 jscss
tips: browser object model(即浏览器对象模型,核心是window)html
BOM是一系列在浏览器环境中使用对象的统称,这些对象提供了访问浏览器的功能。前端
通俗讲就是JavaScript访问浏览器的一个接口 ECMAScript规定的Global对象(全局对象)java
介绍:咱们定义的全局变量和全局函数都是window对象的属性和方法node
MDN全window文档,能够查阅jquery
查阅资料git
查阅资料 思否 JavaScript BOM对象-Navigator浏览器对象程序员
参考JS高级程序设计-第3版,挺好的书(有须要找我要电子书)
深刻学习History对象管理浏览器会话历史 BOM之history对象 history对象 前端离开页面事件总结
navigator对象:包含大量有关Web浏览器的信息,在检测浏览器及操做系统上很是有用(window.navigator或者navigator) 每一个浏览器中的 navigator 对象也都有一套本身的属性
基本大概有须要的
//如下也能够经过window.navigator获取到
navigator.appCodeName //浏览器代码名的字符串表示
navigator.appName //官方浏览器名的字符串表示
navigator.appVersion //浏览器版本信息的字符串表示
navigator.cookieEnabled //若是启用cookie返回true,不然返回false
navigator.javaEnabled //若是启用java返回true,不然返回false
navigator.platform //浏览器所在计算机平台的字符串表示
navigator.plugins //安装在浏览器中的插件数组
navigator.taintEnabled //若是启用了数据污点返回true,不然返回false
navigator.userAgent //用户代理头的字符串表示
Navigator.onLine //返回一个布尔值,表示用户当前在线仍是离线(浏览器断线)
复制代码
var UserAgent =window.navigator.userAgent.toLowerCase();
function getBrowserType(UserAgent){
var result={
isIE6: /msie 6.0/.test(UserAgent), // IE6
isIE7: /msie 7.0/.test(UserAgent), // IE7
isIE8: /msie 8.0/.test(UserAgent), // IE8
isIE9: /msie 9.0/.test(UserAgent), // IE9
isIE10: /msie 10.0/.test(UserAgent), // IE10
isIE11: /msie 11.0/.test(UserAgent), // IE11
isLB: /lbbrowser/.test(UserAgent), // 猎豹浏览器
isUc: /ucweb/.test(UserAgent), // UC浏览器
is360: /360se/.test(UserAgent), // 360浏览器
isBaidu: /bidubrowser/.test(UserAgent), // 百度浏览
isSougou: /metasr/.test(UserAgent), // 搜狗浏览器
isChrome: /chrome/.test(UserAgent),
//Chrome浏览器
isFirefox: /firefox/.test(UserAgent), // 火狐浏览器
isOpera: /opera/.test(UserAgent), // Opera浏览器
isSafiri: /safari/.test(UserAgent) && !/chrome/.test
(UserAgent), // safire浏览器
isQQ: /qqbrowser/.test(UserAgent)//qq浏览器
};
return result;
}
console.log(getBrowserType(UserAgent));
复制代码
只用来代表客户端的能力,包括浏览器窗口外部的显示器的信息,如像素高度和宽度等。每一个浏览器中的screen对象都包含着各不相同的属性
各大浏览器实现的属性
ps:说起兼容性高的
属性 | 说明 | IE | FireFox | Safari/Chrome | Opera |
---|---|---|---|---|---|
availHeight | 返回显示屏幕的高度 (除 Windows 任务栏以外) | ✔ | ✔ | ✔ | ✔ |
availWidth | 返回显示屏幕的宽度 (除 Windows 任务栏以外) | ✔ | ✔ | ✔ | ✔ |
width | 返回显示器屏幕的宽度 | ✔ | ✔ | ✔ | ✔ |
height | 返回显示屏幕的高度 | ✔ | ✔ | ✔ | ✔ |
colorDepth | 返回目标设备或缓冲器上调色板的比特深度(多数系统32位) | ✔ | ✔ | ✔ | ✔ |
pixelDepth | 返回显示屏幕的颜色分辨率(比特每像素) | × | ✔ | ✔ | ✔ |
availLeft | 返回未被系统部件占用的最左侧的像素 | × | ✔ | ✔ | × |
availTop | 返回未被系统部件占用的最上方的像素 | × | ✔ | ✔ | × |
History对象容许咱们操做浏览器会话历史,即加载当前页面的标签页窗口或frame窗口的访问历史
属性(window.history获取)
history.length:包括当前页面在内的会话历史中的记录数量
history.state:属性用来保存记录对象(返回当前页面的state对象,上述的state对象)【区别不一样会话历史纪录】
导航方法(window.history获取)
history.back():返回会话历史记录中的上一个页面
history.forward():进入会话历史记录中的下一个页面
history.go():加载会话历史记录中的某一个页面,该页面与当前页面在会话历史中的相对位置定位,-1表明当前页面的上一个记录,1表明当前页面的下一个页面
增改记录
方法
history.pushState():在浏览历史中添加【向浏览器历史添加了一个状态】
state —— 状态对象是一个由pushState()方法建立的、与历史纪录相关的javascript对象,当用户定向到一个新的状态时,会触发popstate事件
title —— 新页面的标题,可是全部浏览器目前都忽略这个值,所以这里能够填null
url —— 必须与当前页面URL同源
语法: history.pushState(state, title, url);
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 2", "bar.html");
复制代码
history.replaceState():在浏览历史中修改记录(更新当前会话历史记录,如更新当前会话记录的状态对象或URL。)
事件
popstate:监听history对象的变化【每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件】
仅仅调用pushState方法或replaceState方法,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用javascript调用back()、forward()、go()方法时才会触发
往返缓存概念(浏览器有一个特性)
能够在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度
这个缓存中不只保存着页面数据,还保存了DOM和javascript的状态
若是页面位于bfcache中,那么再次打开该页面时就不会触发load事件
进入页面与离开页面事件 pageshow与 pagehide=》(没法执行alert操做,window 对象 和 dom 对象都已经被销毁了)
pageshow:页面加载时触发,包括第一次加载和从缓存加载两种状况 ps:第一次加载时,它的触发顺序排在load事件后面
window.onpageshow = function(e){
e = e || event;
console.log(e.persisted,进入加载事件);
}
复制代码
pagehide:该事件会在浏览器卸载页面的时候触发,并且是在unload事件以前触发
window.onpagehide = function(e){
e = e || event;
console.log(e.persisted);
}
复制代码
前端离开页面事件总结(出现提示框有点会有点问题,由于alert是阻塞)
Onblur :监控(窗口 页面 组件)失去焦点事件
Onfocus :监控(窗口 页面 组件)获得焦点事件
onbeforeunload:在即将离开当前页面(刷新或关闭)时执行 JavaScript
window.onbeforeunload=function(e){
  var e = window.event||e;
  e.returnValue=("肯定离开当前页面吗?");
}
复制代码
以http://www.baidu.com:8080/index.php?name=kang&when=2011#first为例
属性 | 描述 | 值 |
---|---|---|
protocol | 设置或返回当前 URL 的协议。 | http: |
hostname | 设置或返回当前 URL 的主机名。 | www.baidu.com |
host | 设置或返回主机名和当前 URL 的端口号 | www.baidu.com:8080 |
port | 返回当前 URL 的端口号 | 8080 |
pathname | 设置或返回当前 URL 的路径部分 | /index.php |
search | 设置或返回从问号 (?) 开始的 URL(查询部分) | ?name=kang&when=2011 |
hash | 设置或返回从井号 (#) 开始的 URL(锚) | #first |
href | 设置或返回完整的 URL | 全连接 |
window.location和document.location互相等价。 location 的8个属性都是可读写,可是只有href与hash的写才有意义
方法
assign() :加载新的文档
导航到一个新页面的方法
window.location.assign("http://www.mozilla.org"); // or
window.location = "http://www.mozilla.org";
复制代码
reload() :从新加载当前文档
若是文档已改变,reload() 会再次下载该文档。若是文档未改变,则该方法将从缓存中装载文档。这与用户单击浏览器的刷新按钮的效果是彻底同样的。若是把该方法的参数设置为 true,那么不管文档的最后修改日期是什么,它都会绕过缓存,从服务器上从新下载该文档
window.location.reload(true);
复制代码
不会在 History 对象中生成一个新的记录。当使用该方法时,新的 URL 将覆盖 History 对象中的当前记录。
window.location.replace('http://example.com/');
复制代码
兼容问题
document.documentElement.body || document.body 区别 document.body 和 document.documentElement 的区别
获取 scrollTop 方面的差别
兼容性解决方案:var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
DTD概念普及 W3C HTML中 !DOCTYPE 的解释与做用
Document Type Definition,中文翻译为:文档类型定义【整体上应该分为三类: HTML5,HTML4.0,XHTML。】
早期的版本基于SGML,因此须要套用SGML的解析规则。DTD的做用在于定义SGML文档的文档类型以便于浏览器解析。
随着技术的进步,如今HTML5 不基于 SGML,因此也就不须要引用 DTD了
牵扯处一个问题什么是!DOCTYPE,以及做用(面试题)
DOCTYPE是document type(文档类型)的简写,在Web设计中用来讲明你用的XHTML或者HTML是什么版本
没有<!DOCTYPE>声明,那么不一样的浏览器将会以本身不一样的怪异的模式去解析渲染页面,这样页面在不一样的浏览器上呈现出来的效果也就不同,人们把这称之为“怪异模式”
若是声明了,将会开启“严格模式”,又有人称之为“标准模式”,浏览器将已w3c标准来解析渲染页面
document获取到当前页面不少数据信息【属性】
全部图片images/表单forms/连接links/锚点anchors的集合
document.images/document.forms/document.links/document.anchors
复制代码
当前页的cookie/域名domain/获取载入当前文档的文档的url/标题title/当前url
document.cookie/document.domain/document.referrer/document.title/document.URL
复制代码
方法
不要和 window.open() 方法混淆。document.open 可用于重写当前的文档内容或者追加内容, 而 window.open 是提供了打开一个新的窗口的方法,当前的网页文档内容会被保留
window.scrollBy(x,y)/window.scrollTo(x,y)挺有用的,移动文档
MoveTo和MoveBy的区别(可引伸为To和By的区别)
By 和 To 的区别(move/resize/scroll)--窗口移动变化(浏览器禁止)/窗口大小变化(浏览器可能会禁止掉)/内容滚动
By 算的是相对于节点对象的当前位置
To 算的是绝对位置,不考虑当前节点对象在哪
moveBy()/moveTo()----->在chrome,IE浏览器上运行,都不显示效果
缘由:为了保护计算机的安全性
----语法很少赘述
javascript都是以单线程的方式运行于浏览器的javascript引擎中的 settimeout和setinterval的做用只是把你要执行的代码在你设定的一个时间点插入js引擎维护的一个代码队列中 插入代码队列并不意味着你的代码就会立马执行的,理解这一点很重要 settimeout和setinterval还有点不同
扯出最最重要的知识点:Event Loop(面试题) 通杀 Event Loop 面试题 / Js 的事件循环(Event Loop)机制以及实例讲解
js是单线程的脚本语言,在同一时间,只能作同一件事,为了协调事件、用户交互、脚本、UI渲染和网络处理等行为,防止主线程阻塞,Event Loop方案应运而生
知识点的普及
执行栈
当执行某个函数、用户点击一次鼠标,Ajax完成,一个图片加载完成等事件发生时,只要指定过回调函数,这些事件发生时就会进入任务队列中,等待主线程读取,遵循先进先出原则
主线程
任务队列(Task Queue)
顺序讲解: 当主线程将执行栈中全部的代码执行完以后,主线程将会去查看任务队列是否有任务。若是有,那么主线程会依次执行那些任务队列中的回调函数。
宏任务与微任务(很重要)
异步任务分为 宏任务(macrotask) 与 微任务 (microtask),不一样的API注册的任务会依次进入自身对应的队列中,而后等待 Event Loop 将它们依次压入执行栈中执行。
宏任务(如下都是) script(总体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)、UI rendering (浏览器独有)
微任务(如下都是) Promise.then()、 MutaionObserver、process.nextTick(Node.js环境)、Object.observe
Event Loop(事件循环) 【全部任务当作两个队列:执行队列与事件队列】
--->先执行script --->遇到宏任务(放入事件列表),遇到微任务(先依次压入执行栈),等script里的同步任务完成 --->再执行执行栈里面的微任务 --->最后执行事件列表里的宏任务
注意:new Promise() 构造函数里面是同步代码,而非微任务
promise.then 虽然和 process.nextTick 同样,都将回调函数注册到微任务,但优先级不同。process.nextTick 的微任务队列 老是优先于 promise 的 微任务队列 执行
在 I/O Callbacks 中注册的 setTimeout 和 setImmediate,永远都是 setImmediate 先执行。
setTimeout(function () {
console.log(1);
});
new Promise(function(resolve,reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
})
console.log(4);
1. 遇到setTimeout(宏任务)压到事件列表
2. 进入Promise,遇到console.log(2),打印2
3. 遇到resolve(3),回调函数【Promise.then是微任务】压入执行栈
3. 遇到console.log(4),执行4-------》执行完script
4. 执行微任务resolve(3),转到then,打印3
4. 最后执行事件列表,执行宏任务setTimeout,打印1
复制代码
--》 2 4 3 1
巩固提升
console.time("start")
setTimeout(function () {
console.log(2);
}, 10);
setImmediate(function () {
console.log(1);
});
new Promise(function (resolve) {
console.log(3);
resolve();
console.log(4);
}).then(function () {
console.log(5);
console.timeEnd("start")
});
console.log(6);
process.nextTick(function () {
console.log(7);
});
console.log(8);
// requestAnimationFrame(() => console.log(9))。
复制代码
讲完了这个执行顺序(贼重要)问题,回到计时器
关于setTimeout()你所不知道的地方,详解setTimeout()
将指定的代码移出本次执行,等到下一轮Event Loop时,再检查是否到了指定时间。若是到了,就执行对应的代码;若是不到,就等到再下一轮Event Loop时从新判断。这意味着, setTimeout和setInterval指定的代码,必须等到本次执行的全部代码都执行完,才会执行
因为前面的任务到底须要多少时间执行完,是不肯定的,因此没有办法保证,setTimeout和setInterval指定的任务,可能会不必定按照预约时间执行
setTimeout来代替setInterval
timer=setTimeout(fn,1000)
function fn(){
console.log("循环")
//argement.callee表明表明上下文正在执行的函数--》这些都会在后面一一细说
setTimeout(arguments.callee,1000)
}
复制代码
setTimeout(fn,0)来置换顺序
setTimeout(fn,time),在执行过程当中time是能改变的(调整快慢)
setTimeout循序回调(传参)
setTimeout(function(a,b){
console.log(a+b);
},1000,1,1);
复制代码
注意点:setTimeout()中回调函数中的this(会指向全局,利用apply/call解决) 你所不知道的setTimeout
为何不使用 setInterval-->跳帧---》解决方案,好比容易内存泄漏 深度解密setTimeout和setInterval——为setInterval正名 / 从setTimeout-setInterval看JS线程(setInterval缺点) / 阮一峰的线程与进程
alert :显示警告框的信息; 无返回值
confirm:参数就只有一个.显示提示框的信息. 按肯定,返回true; 按取消返回false.
var truthBeTold = window.confirm("单击“肯定”继续。单击“取消”中止。");
if (truthBeTold) {
window.alert("欢迎访问咱们的 Web 页!");
} else {
window.alert("再见啦!");
}
复制代码
prompt:参数,有两个, 第一个参数,显示提示输入框的信息. 第二个参数,用于显示输入框的默认值. 返回,用户输入的值.
var data = window.prompt("输入验证码", "")
if( data == 'ss' )
{
alert("ok");
}
else
{
alert("false");
}
复制代码
JavaScript中的各类宽高属性 / JS 相关宽高理解,有图表能够查阅
了解跨浏览器肯定窗口大小是很不容易的:
window.innerHeight/innerWidth:第一种方式获取的是可视区的宽高,包括了滚动条的宽度
ps:IE 8 及更早 IE版本不支持这两个属性。
document.body.clientHeight/clientWidth: 第二种方式获取的是可视区的宽高,不包括滚动条的宽度以及边框border【 获取body宽度】
兼容性写法:document.documentElement.clientHeight/clientWidth(获取整个页面)
document.documentElement对象的clientWidth..... / 如何使用 JavaScript 获取页面、窗口的高度?
// 页面可视区的宽度
var oClientWidth = document.documentElement.clientWidth || document.body.clientWidth || 0;
// 页面可视区的高度
var oClientHeight = document.documentElement.clientHeight || document.body.clientHeight || 0;
复制代码
document.body.offsetWidth/offsetHeight :是可视区的宽高(即元素占据的空间,包括填充和边框,不包括滚动条)【 获取body宽高度】
兼容性写法:document.documentElement.offsetWidth/offsetHeight(获取整个页面)
// scrollWidth 表示整个网页正文的宽度
var scrollWidth = document.documentElement.offsetWidth || document.body.offsetHeight;
// scrollHeight 表示整个网页正文的高度
var scrollHeight = document.documentElement.offsetWidth || document.body.offsetHeight;
复制代码
document.body.scrollWidth/scrollHeight: 网页正文全文宽高【 获取body正文全文宽高】
兼容性写法:document.documentElement.scrollWidth/scrollHeight(获取整个页面正文全文宽高)
// scrollWidth 表示整个网页正文的宽度
var scrollWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
// scrollHeight 表示整个网页正文的高度
var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
复制代码
页面正文卷起长度
解决兼容:scrollTop/scrollLeft
// scrollTop 网页被卷起的高度
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
// scrollLeft 网页左边被卷起的宽度
var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
复制代码
window 相关宽高
Event对象的5种坐标
clientX和clientY,相对于浏览器(但是区左上角0,0)的坐标
screenX和screenY,相对于设备屏幕左上角(0,0)的坐标
offsetX和offsetY,相对于事件源左上角(0,0)的坐标
pageX和pageY,相对于整个网页左上角(0,0)的坐标
X和Y,原本是IE属性,相对于用CSS动态定位的最内层包容元素
关于DOM级别的一些问题 DOM事件全整理之从DOM事件级别,DOM事件流到事件委托
文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义了一种方式可使从程序中对该结构进行访问,从而改变文档的结构,样式和内容。
DOM描绘了一个层次化的节点树,容许开发人员添加、移除和修改页面的某一部分。
简单来说,DOM就是一组API(接口)。它将一份结构化文档看作一棵树,这棵树由各类各样的节点构成,也即节点树
精辟:DOM标准的目标是让“任何一种程序设计语言”能操控使用“任何一种标记语言”编写出的“任何一份文档”。“操控”具体含义为能经过DOM提供的API对文档的内容、结构、样式进行访问和修改
方法
getElementById():根据元素的id来获取该元素对象,经过该方法获取的元素对象是惟一的,能够直接对其进行操做
getElementsByClassName():根据元素的class类名来获取该元素对象,经过该方法获取的元素对象是一个伪数组,须要经过伪数组的方式对其进行访问
getElementsByTagName():根据元素的标签名来获取该元素对象,经过该方法获取的元素对象是一个伪数组,须要经过伪数组的方式对其进行访问
是 HTML5 新增长的一个 js 函数,对于一些老浏览器例如 IE9 如下的浏览器是不支持这个函数的,因此在那些须要处理兼容性问题的
getElementsByClassName()方法不兼容ie低版本解决方案
if(!document.getElementsByClassName)//判断浏览器是否支持这个方法
{
document.getElementsByClassName=function(cname){
var selected=new Array();
var alltag=document.getElementsByTagName("*");//获取全部标签
for(var i=0;i<alltag.length;i++)
{
var t=alltag[i];
alert(t.className);
if(t.className==cname) //比较标签的class与所要查找的class是否相同
{
selected.push(t); //将相同的存入数组
}
}
return selected;
}
}
复制代码
querySelector与getElement...差别以及区别 querySelector和getElementById性能分析与使用选择 / 为什么getElementsByTagName()比querySelectorAll()快100倍
document.querySelector():返回文档中匹配指定的CSS选择器的第一元素
document.querySelector("#demo");
document.querySelectorAll():是 HTML5中引入的新方法,返回文档中匹配的CSS选择器的全部元素节点列表
var x = document.querySelectorAll(".example");
认识DOM文档的遍历指针以及如何获取根节点和body节点 / 《JavaScript高级程序设计》学习笔记(四)
知识点普及:Node类型
DOM1级定义了一个Node接口,该接口由DOM中的全部节点类型实现。这个Node接口在JavaScript中是做为Node类型实现。除了IE以外,在其余浏览器中均可以访问到这个类型。JavaScript中全部节点类型都继承自Node类型,所以全部节点类型都共享着相同的基本属性和方法
在DOM结构树中,每个独立的DOM节点都定义了一系列的指针(节点属性),经过这些指针,咱们能够遍历DOM结构中咱们想找到的任何对象。若是指针指向的元素不存在,则对应指针的属性值为null
nodeName和nodeValue属性-------》【扩展到js原生事件委托机制(事件的捕获冒泡)】
用nodeName和nodeValue属性能够了解节点的具体信息,其值彻底取决于节点的类型 nodeName中保存的始终都是元素的标签名,而nodeValue的值则始终为null
Javascript性能优化 - 事件委托 / JavaScript 事件委托详解 / 事件冒泡机制与委托机制 / JavaScript事件委托原理 / JavaScript事件代理和委托(Delegation)
事件委托机制
场景:
ps:假设有一个多行多列的表格,咱们想让用户单击每一个单元格都能看到与其中内容相关的更多信息(好比,经过提示条)。为此,能够为每一个单元格都绑定click事件.问题是,若是表格中要绑定单击事件的有10列500行,那么查找和遍历5000个单元格会致使脚本执行速度明显变慢,而保存5000个td元素和相应的事件处理程序也会占用大量内存
ps:假设一个动态翻页的表格,每一次翻页都是从新插入的表格。经过给第一页添加事件,对后续经过js异步加载的页面没有做用
提示:使用事件委托时,若是注册到目标元素上的其余事件处理程序使用.stopPropagation()阻止了事件传播,那么事件委托就会失效。
事件触发过程:现代浏览器(指 IE6-IE8 除外的浏览器,包括 IE9+、FireFox、Safari、Chrome 和 Opera 等)事件流包含三个过程,分别是捕获阶段、目标阶段和冒泡阶段 JavaScript 浏览器事件解读
当咱们对 DOM 元素进行操做时,好比鼠标点击、悬浮等,就会有一个事件传输到这个 DOM 元素,这个事件从 Window 开始,依次通过 docuemnt、html、body,再不断通过子节点直到到达目标元素,从 Window 到达目标元素父节点的过程称为捕获阶段,注意此时还未到达目标节点。
捕获阶段结束时,事件到达了目标节点的父节点,最终到达目标节点,并在目标节点上触发了这个事件,这就是目标阶段。
当事件到达目标节点以后,就会沿着原路返回,这个过程有点相似水泡从水底浮出水面的过程,因此称这个过程为冒泡阶段。
addEventListener(eventName, handler, useCapture) 函数。第三个参数是 useCapture,表明是否在捕获阶段进行事件处理, 若是是 false, 则在冒泡阶段进行事件处理,若是是 true,在捕获阶段进行事件处理,默认是 false。这么设计的主要缘由是当年微软和 netscape 之间的浏览器战争打得火热,netscape 主张捕获方式,微软主张冒泡方式,W3C 采用了折中的方式,即先捕获再冒泡。(true 时表捕获阶段,false时为冒泡阶段)
main.addEventListener("mousedown",function(e){ //e.target是鼠标通过的那个元素
var nodename = e.target.nodeName.toLocaleLowerCase(); //标签转小写
var classname=e.target.className; //获取class
if(e.target && nodename == "div" || nodename=="span") {
if(classname=="head"||classname=="msg"||classname=="foot"||classname=="tip"|| nodename=="span"){
if(classname=="tip"){
...........
}else if(nodename=="span"){
........
}else{
............
}
}
}
},true);
复制代码
事件委托是事件冒泡的一个应用,但有时候咱们并不但愿事件冒泡
event.stopPropagation():阻止冒泡事件,不让事件向documen上蔓延,可是默认事件任然会执行,当你掉这个方法的时候,若是点击一个连接,这个连接仍然会被打开;
ps:但IE不支持,IE中提供的是,cancelBubble属性,默认为false,当它设置为true时,就是阻止事件冒泡
event.preventDefault():阻止默认事件,调用此方法是,连接不会被打开,可是会发生冒泡,冒泡会传递到上一层的父元素;
return false:这个方法比较暴力,他会同时阻止事件冒泡也会阻止默认事件;写上此代码,连接不会被打开,事件也不会传递到上一层的父元素,能够理解为 return false 就等于同时调用了event.stopPropagation()和event.preventDefault()。
讲到冒泡=>其实能够扯到onmouseover/onmouseout 以及onmouseenter/onmouseleave
事件冒泡以及onmouseenter 和 onmouseover 的不一样
冒泡 onmouseover/onmouseout是有冒泡的
onmouseenter/onmouseleave是没有冒泡的
mouseover
mouseout
Node(节点)对应的5个指针
parentNode:返回指定节点的父节点
previousSibling:返回指定节点的上一个相邻节点
nextSibling:返回指定节点的下一个相邻节点
firstChild:返回指定元素的第一个子节点
lastChild:返回指定元素的最后一个子节点
childNodes
test.firstChild=test.childNodes[0] 始终相等
test.lastChild=test.[test.childNodes.length-1] 始终相等
在只有一个子节点的状况下,firstChild和lastChild指向同一个节点,若是没有子节点,firstChild和lastChild的值均为null。
JavaScript常见原生DOM操做API总结 JavaScript操做DOM经常使用的API
建立节点
createElement:传入指定的一个标签名来建立一个元素
let elem = document.createElement("div");
elem.id = 'test';
elem.style = 'color: red';
elem.innerHTML = '我是新建立的节点';
document.body.appendChild(elem);
复制代码
createTextNode:建立一个文本节点
var node = document.createTextNode("我是文本节点");
document.body.appendChild(node);
复制代码
cloneNode:返回调用该方法的节点的一个副本
是否采用深度克隆,若是为true,则该节点的全部后代节点也都会被克隆,若是为false,则只克隆该节点自己
要调用appendChild方法才能添加到文档树中
若是复制的元素有id,则其副本一样会包含该id,因为id具备惟一性,因此在复制节点后必需要修改其id
调用接收的是否深度克隆参数最好传入,若是不传入该参数,不一样浏览器对其默认值的处理可能不一样
须要克隆的元素,事件都启用,最好使用事件委托机制
var parent = document.getElementById("parent");
document.getElementById("btnCopy").onclick = function(){
var parent2 = parent.cloneNode(true);
parent2.id = "parent2";
document.body.appendChild(parent2);
}
复制代码
createDocumentFragment:建立一个 DocumentFragment ,也就是文档碎片,它表示一种轻量级的文档,主要是用来存储临时节点,大量操做DOM时用它能够大大提高性能。
(function()
{
var start = Date.now();
var str = '', li;
var ul = document.getElementById('ul');
var fragment = document.createDocumentFragment();
for(var i=0; i<1000; i++)
{
li = document.createElement('li');
li.textContent = '第'+(i+1)+'个子节点';
fragment.appendChild(li);
}
ul.appendChild(fragment);
})();
复制代码
插入节点
appendChild:前面已经用到屡次,就是将指定的节点添加到调用该方法的节点的子元素的末尾。
insertBefore(newElement, referenceElement):用来添加一个节点到一个参照节点(referenceElement)以前
<div id="parent">
父节点
<div id="child">
子元素
</div>
</div>
<input type="button" id="insertNode" value="插入节点" />
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.getElementById("insertNode").onclick = function(){
var newNode = document.createElement("div");
newNode.textContent = "新节点"
parent.insertBefore(newNode,child);
}
复制代码
替换节点 :
parent.replaceChild(newChild,oldChild)用于使用一个节点替换另外一个节点【oldChild是被替换的节点】
<body>
<div id="parent">
父节点
<div id="child">
子元素
</div>
</div>
<input type="button" id="insertNode" value="替换节点" />
</body>
<script>
var parent = document.getElementById("parent");
var child = document.getElementById("child");
document.getElementById("insertNode").onclick = function(){
var newNode = document.createElement("div");
newNode.textContent = "新节点"
parent.replaceChild(newNode,child)
}
复制代码
移除节点
回忆jquery的节点操做 jQuery DOM 操做(基本操做、内部插入、外部插入、包裹操做) / jQuery DOM节点的建立、插入、删除
element.setAttribute(name, value)
let div1 = document.getElementById("div1");
div1.setAttribute("align", "center");
复制代码
element.getAttribute(attributeName)
let div1 = document.getElementById("div1");
let align = div1.getAttribute("align");
复制代码
element.removeAttribute(attrName)
let div = document.getElementById("div1")
div.removeAttribute("style");
复制代码
暂了解,基本不使用除了前四种
---》获取CSS衍生出一个问题getComputedStyle()与currentStyle()、style()方法
obj.style:这个方法只能JS只能获取写在html标签中的写在style属性中的值(style=”…”),而没法获取定义在<style type="text/css" 里面的属性
IE中使用的是obj.currentStyle方法,而FF是用的是getComputedStyle 方法
解决兼容问题
function getStyle(element, attr) {
if(element.currentStyle) {
return element.currentStyle[attr];
} else {
return getComputedStyle(element, false)[attr];
}
}
复制代码
JavaScript 操做 DOM 的那些坑 /// 建议看看在新窗口中打开页面?当心有坑! /// 前端性能优化之 DOM 篇 /// 前端性能优化之图片篇 /// 关于反爬虫(爬虫与反爬虫),看这一篇就够了 /// 浏览器特性与安全策略 /// 【干货】浅析浏览器安全 /// 如何应对网站反爬虫策略?如何高效地爬大量数据? /// 浅析最烦人的反爬虫手段 /// 反AdBlock屏蔽广告
IE8不兼容addEvntListener,只能使用attachEvent()和detachEventListener()方法。IE从IE9开始支持addEventListener和removeEventListener. addEventListener/attachEvent兼容IE浏览器与标准浏览器
鼠标滚轮事件:mousewheel:》当用户使用鼠标滚轮与页面进行交互、在垂直方向上滚动页面时(不管上下),就会触发mousewheels事件,这个事件能够在任何元素上触发,最终会冒泡到document或者window上。
对应的event对象还有wheelDelta属性,值是120/-120的倍数
document.addEventListener('mousewheel',function(event){
console.log(event.wheelDelta)
})
复制代码
键盘事件
键盘事件用来描述键盘行为,主要有keydown、keypress、keyup三个事件
按下enter键
function enterOperate(evt){
if(evt.keyCode == 13){
alert("按下enter键");
}
}
document.body.addEventListener("keydown", enterOperate)
复制代码
组合按键
function combinationKey(evt){
if( evt.shiftKey && evt.keyCode == 73){
alert(“触发了shift + i组合键”);
}
}
复制代码
程序员发展到必定的水平后,瓶颈并不在技术水平上,而是在表达能力上
涉及到点击穿透的问题【web开发经典问题】(面试题)点击穿透
用户点击事件以后,浏览器会等待300ms后,若是没有(再次的点击行为)【双击】行为,再去执行click事件
浏览器等待约 300ms 的缘由是,判断用户是不是双击(double tap)行为,双击过程当中就不适合触发 click 事件了 为了减小这300ms的延迟,tap事件被不少框架(如zepto)封装,来减小这延迟问题, tap事件不是原生的,因此是封装的
fastclick库。github
上面说到点击问题,其实能够再扯到节流与防抖 面试准备 - JS 防抖与节流
讲到节流防抖---拉扯到回流重绘的问题
最后说到整个浏览器从输入url过程:DNS解析>tcp三次握手>tcp四次挥手>浏览器的渲染页面
解决说明问题【倒序解决】
输入url以后发生了什么 参考浏览器输入 URL 后发生了什么?
DNS解析 :( Domain Name System)是“域名系统”的英文缩写,它用于TCP/IP网络,它所提供的服务是用来将主机名和域名转换为IP地址的工做。
tcp三次握手:
专业名词
过程
第一次握手:状态【两端都处于CLOSED关闭状态】,客户端(Client)将SYN的数据包【SYN=1,随机产生一个值seq=x】发送给服务端(Server),客户端(Client)处于SYN-SENT,等到服务端确认
第二次握手:服务端(Server)接收到数据包后,得知客户端请求创建链接,服务端将SYN与ACK【SYN=1,ACK=1,ack = x + 1,随机产生一个值 seq = y】)的数据包发回给客户端(Client),服务端进入SYN-RCVD状态,操做系统为该 TCP 链接分配 TCP 缓存和变量
第三次握手:客户端(Client)收到确认后,检查原先本身的seq是否等于x+1,ACK是否为1,若是没问题,将ACK数据包【ack = y + 1】丢回服务端(server),Server 检查 ack 是否为 y + 1,ACK 是否为 1,若是正确则链接创建成功。状态【两端都处于established 状态】,完成握手,随后 Client 和 Server 就能够开始传输数据。
TCP四次挥手
第一次挥手:客户端发送FIN【FIN=1,seq=u】数据包,中止再发送数据,主动关闭 TCP 链接,进入 FIN-WAIT-1(终止等待1)状态
第二次挥手:服务端接收到FIN数据包报文后,就会发出确认报文段ACK数据包【ACK = 1,确认号 ack = u + 1,序号 seq = v】,Server 进入 CLOSE-WAIT(关闭等待)状态,此时的 TCP 处于半关闭状态,Client 到 Server 的链接释放。 ----------------------------------------------------------》数据发送完毕
第三次挥手:Server 已经没有要向 Client 发出的数据了,Server 发出链接释放报文段(数据包)FIN与ACK(FIN = 1,ACK = 1,序号 seq = w,确认号 ack = u + 1),Server 进入 LAST-ACK(最后确认)状态,等待 Client 的确认。
第四次挥手:Client 收到 Server 的链接释放报文段后,对此发出确认报文段(ACK = 1,seq = u + 1,ack = w + 1),Client 进入 TIME-WAIT(时间等待)状态。此时 TCP 未释放掉,须要通过时间等待计时器设置的时间 2MSL 后,Client 才进入 CLOSED 状态。
四次挥手的详述 Client端发起中断链接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",可是若是你还有数据没有发送完成,则没必要急着关闭Socket,能够继续发送数据。因此你先发送ACK,"告诉Client端,你的请求我收到了,可是我还没准备好,请继续你等个人消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端肯定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭链接了"。Client端收到FIN报文后,"就知道能够关闭链接了,可是他仍是不相信网络,怕Server端不知道要关闭,因此发送ACK后进入TIME_WAIT状态,若是Server端没有收到ACK则能够重传。“,Server端收到ACK后,"就知道能够断开链接了"。Client端等待了2MSL后依然没有收到回复,则证实Server端已正常关闭,那好,我Client端也能够关闭链接了。Ok,TCP链接就这样关闭了
浏览器的渲染:【干货】十分钟读懂浏览器渲染流程 /// 浏览器渲染页面过程与页面优化
回流与重绘:重点:浏览器的回流与重绘 (Reflow & Repaint) /// 你真的了解回流和重绘吗
回到最初的问题:节流与防抖(这是俩种解决方案:解决的问题是:频繁的点击事件)
节流:指定一段时间内只执行一次操做
节流函数体
function throttle(fn) {
// 四、经过闭包保存一个标记canRun
let canRun = true;
return function() {
// 五、在函数开头判断标志是否为 true,不为 true 则中断函数
//做用执行函数canRun为false,而后一段时间后才变成true
if(!canRun) {
return;
}
// 六、将 canRun 设置为 false,防止执行以前再被执行
canRun = false;
// 七、定时器
setTimeout( () => {
fn.call(this, arguments); //将不肯定变量替换到函数中了
// 八、执行完事件(好比调用完接口)以后,从新将这个标志设置为 true
canRun = true;
}, 1000);
};
// 三、须要节流的事件
function sayThrottle() {
console.log("节流成功!");
}
复制代码
懒加载要监听计算滚动条的位置,使用节流按必定时间的频率获取。 用户点击提交按钮,假设咱们知道接口大体的返回时间的状况下,咱们使用节流,只容许必定时间内点击一次。
防抖函数:俩次触发间隔超过指定时间间隔
window.onload = function() {
// 一、获取这个按钮,并绑定事件
var myDebounce = document.getElementById("debounce");
myDebounce.addEventListener("click", debounce(sayDebounce));
}
// 二、防抖功能函数,接受传参
function debounce(fn) {
// 四、建立一个标记用来存放定时器的返回值
let timeout = null;
return function() {
// 五、每次当用户点击/输入的时候,把前一个定时器清除
clearTimeout(timeout);
// 六、而后建立一个新的 setTimeout,
// 这样就能保证点击按钮后的 interval 间隔内
// 若是用户还点击了的话,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 1000);
};
}
// 三、须要进行防抖的事件处理
function sayDebounce() {
// ... 有些须要防抖的工做,在这里执行
console.log("防抖成功!");
}
复制代码
输入URL发生了什么=参考文章
DNS解析:DNS解析的过程是什么,求详细的? /// DNS解析过程详解
TCP三次握手以及TCP四次挥手 TCP三次握手与四次挥手 /// 注意!是TCP不是HTTP的3次握手与4次挥手(#...#)
浏览器的渲染:【干货】十分钟读懂浏览器渲染流程