前端笔记知识点整合之JavaScript(十)深入JavaScript节点&DOM&事件
一、dom
javascript语言核心。变量的定义、变量的类型、运算符、表达式、函数、if语句、for循环、算法等等。这些东西都属于语言核心,下次继续学习语言核心就是面向对象了。javascript能做非常多的事情:dom开发、ajax开发、canvas开发、nodejs开发、前端框架(react、vue、angular等等)、html5开发。这些都需要语言核心的知识。
dom开发说白了就是浏览器中的页面效果开发,在2011年之前,dom开发占据了前端开发工程师的90%的工作;但是现在,dom开发的工作比重已经降到了10%以下。换句话说,2011年之前,前端 = 做特效的;2011年之后,前端要负责得到后台的数据接口,用前端mvc逻辑分层开发前端组建、界面、功能,还要写html5,还要做canvas动画!
上层的框架屏蔽了下层的语言的一些麻烦、不方便的东西,并且提供更方便的api。
jquery就是干这个事情的,把js中的不方便封装起来,暴露的api都是非常简便的。
jquery的哲学就是dom编程领域的霸主,操作dom节点、绑定监听、运动、css样式、ajax等等都有封装。
工作上都是用jquery,如果不用jquery也是用类似的东西。没有人会不用*去开发页面效果。
javascript中library表示“库”,如果这个库的功能很强大,甚至颠覆了传统编程的语法、行文习惯,我们就可以叫做“框架”。
1.1 dom是什么
文档对象模型 (dom,document object model) 是 html 和 xml 文档的编程接口。它给文档(结构树)提供了一个结构化的表述并且定义了一种方式—程序可以对结构树进行访问,以改变文档的结构,样式和内容。 dom 提供了一种表述形式— 将文档作为一个结构化的节点组以及包含属性和方法的对象。从本质上说,它将 web 页面和脚本或编程语言连接起来了。
到底什么是dom?就是你可以像操作对象一样操作html页面,而不是操作字符串。
dom将 web 页面和脚本或编程语言连接起来了。
回看一下我们之前学习的dom操作,都在干嘛?我们在开发特效,但是微观的看,实际上在进行:
1) 得到html节点
2) 改变节点的属性
3) 改变节点的样式
4) 修改节点、删除节点、增加节点
5) 节点之间的关系
1.2原生javascript得到节点
document.getelementbyid('box'); document.getelementsbytagname('p'); |
以上两是全线浏览器都兼容的得到元素方法。
以下这些得到元素的方法都不兼容ie678。
document.getelementsbyname('aaa')[0] //通过name属性得到元素们 document.getelementsbyclassname('pp') //通过类名得到元素们 document.queryselector('#box'); document.queryselectorall('#box p'); //通过选择器得到元素们
jquery是dom开发的王者!帮我们解决了元素选择的兼容问题。
jquery底层很强大,比如$('.par1')机制不是getelementsbyclassname(),而是在遍历所有节点,选择类名有par1的项。
二、原生javascript节点关系
在jquery中学习parent()、children() 、siblings()、next()、prev()等等节点关系,js中也有对应的属性。
原生js提供的节点关系很少:
childnodes、firstchild、lastchild、parentnode、nextsibling、previoussibling
常见的nodetype值:
1-普通元素节点、比如div、p等等 2-属性节点 3-文本节点 8-注释节点 9-document节点 10-文档dtd |
想要查看某一个元素的节点类型,直接读取它的nodetype属性即可。
改变nodetype为3的文本节点的内容,要改变他的nodevalue属性
2.1 childnodes儿子节点
childnodes在ie6、7、8和高级浏览器不一致,高级浏览器认为所有的换行为空文本节点,而ie678无视这个空文本节点。
div中没有文本节点,此时应该是4个节点,但是ie9、chrome、火狐会认为有9个节点、ie8认为有4个节点。
高级浏览器会把空文本当做一个节点,标签前后的空文本也被算作一个。
注释的前后算不算空文本节点,各个浏览器有不同的解释。所以用节点的时候,一定要去过滤、判断节点的nodetype是不是1。
<div id="box"> <p></p> <p></p> <p></p> <p></p> </div>
obox.childnodes.length; //chrome数值9、ie678是4 |
为解决兼容性问题(到底空文本算不算儿子,所以要封装函数来解决):
可以利用nodetype是不是1来过滤文本节点、注释节点等,编写一个函数,得到一个标签真正的子节点。
jquery也有这层过滤:
//封装一个children函数,这个函数能返回obj对象的所有真正儿子节点 function chidlren(obj,num){ var arr = []; //存储所有儿子 //遍历所有的节点 for(var i = 0; i < obj.childnodes.length;i++){ //遍历的过程,寻找真正的html儿子节点、过滤文本、注释等节点 //判断节点类型是不是1 if(obj.childnodes[i].nodetype == 1){ arr.push(obj.childnodes[i]); //如果是儿子节点就插入数组中 } } //return arr; //返回的是:如果用户传入了num,返回某一个儿子,如果没有num,返回所有儿子 return num ? arr[num] : arr; } chidlren(obox)[2].style.backgroundcolor = 'red'; chidlren(obox,3).style.backgroundcolor = 'red';
2.2 parentnode父亲节点
parentnode属性表示父亲节点。任何节点的parentnode的nodetype一定是1,也就是说父亲节点一定是标签节点。文本节点、注释节点没有儿子。
var input = document.getelementsbytagname('input'); for(var i = 0;i < input.length;i++){ //当点击某个input时,如果自己被选中,此时改变父亲的颜色为绿色,否则为白色 input[i].onclick = function(){ if(this.checked){ this.parentnode.style.backgroundcolor = 'green'; }else{ this.parentnode.style.backgroundcolor = 'white'; } } }
2.3 previoussibling和nextsibling兄弟节点
上一个兄弟previoussibling、下一个兄弟nextsibling。同样的,文本节点也属于节点,注释也是节点,所以一个节点的上一个兄弟可能是文本、注释节点。原生js中没有提供类似nextall()、prevall()、siblings()方法,如果节点没有上一个兄弟或下一个兄弟、返回null。
console.log(pp.previoussibling.nodetype) console.log(pp.nextsibling.nodetype) |
var pp = document.getelementbyid("pp"); //返回obj的前面一个兄弟 function prevsibling(obj){ //开始遍历obj节点的前面,直到遇见一个nodetype为1的节点 var prev = obj; //循环遍历。注意while的条件是一个赋值语句!赋值语句也有表达式的 while(prev = prev.previoussibling){ if(prev.nodetype == 1){ return prev; } } return null; } //得到真正的后面兄弟 function nextsibling(obj){ //开始遍历obj节点的前面,直到遇见一个nodetype为1的节点 var next = obj; while(next = next.nextsibling){ if(next.nodetype == 1){ return next; } } return null; } //返回obj的前面所有兄弟 function prevall(obj){ //开始遍历obj节点的前面,直到遇见一个nodetype为1的节点 var prev = obj; var arr = []; while(prev = prev.previoussibling){ if(prev.nodetype == 1){ arr.push(prev); } } return arr; } prevsibling(pp).style.background = "red"; nextsibling(pp).style.background = "green"; prevall(pp)[1].style.background = "green";
三、原生javascript dom节点操作
html节点我们原来最多就是改改html属性,比如改改src属性;或者改改css样式,比如.style或者.css()。
现在的问题是,我们要增加节点、删除节点、移动节点、替换节点。
3.1 createelement()创建和appendchild()添加
创建节点的方法: create创建,element元素。接收一个参数,就是创建的标签是什么。
document.createelement() |
追加节点的方法:创建出来的节点不在dom树上,所以就应该用appendchild()来添加到dom树上:
父亲.appendchild(新儿子); |
var btn = document.getelementbyid('btn'); var txt = document.getelementbyid('txt'); var ul = document.getelementsbytagname('ul')[0]; btn.onclick = function(){ //创建一个li标签,用变量oli 来表示,创建除了的节点不是任何节点的儿子(没有在dom树上) var oli = document.createelement('li'); oli.innerhtml = txt.value; //改变这个节点的内容 //把新创建的节点,追加到dom树上 ul.appendchild(oli); }
appendchild()一般来说就是用来追加新创建的节点,如果试图把页面上已经有的节点,appendchild()到别的地方,那么这个节点将移动,也就是说,同一个节点不可能在页面上两个地方出现。
比如:
<div id="box1"> <p id="xiaoming">我是小明</p> </div> <div id="box2"> </div> <script type="text/javascript"> var box2 = document.getelementbyid('box2'); var xiaoming = document.getelementbyid('xiaoming'); box2.appendchild(xiaoming); </script>
以上将把xioaming移动到box2里面。
用innerhtml创建节点:
事实上,工作的时候很少用createelement。因为innerhtml足够好用,innerhtml也可以用来创建节点,甚至效率createelement还高。
var year = document.getelementbyid('year'); for(var i = 1950; i <= 2018;i++){ //创建节点 var op = document.createelement('option'); //改变创建出来的节点内容 op.innerhtml = i; //上dom树 year.appendchild(op); // 父亲.appendchild(新儿子); }
innerhtml创建:
for(var i = 1950; i <= 2018; i++) { year.innerhtml += '<option>'+i+'</option>'; }
javascript是动态变量:
var obox = document.getelementbyid('box'); //得到box里面所有的p,现在box没有p,所以ops是一个空数组 var ops = obox.getelementsbytagname('p'); var np = document.createelement('p'); //创建节点 obox.appendchild(np); //追加节点 var np = document.createelement('p'); //创建节点 obox.appendchild(np); //追加节点 var np = document.createelement('p'); //创建节点 obox.appendchild(np); //追加节点 var np = document.createelement('p'); //创建节点 obox.appendchild(np); //追加节点 var np = document.createelement('p'); //创建节点 obox.appendchild(np); //追加节点 //这里弹出多少?初学者认为弹出0,因为先得到数组p,然后创建节点,节点又没有往数组里面push,所以应该ops数不变才对。 //但是js中存储dom节点的变量是动态,不是一个瞬时照片,而是一个有生命的动态对象,当obox里面的p标签变化时,ps也变化 console.log(ops.length)
3.2 insertbefore()添加
appendchild是把新节点插入在父亲的所有子节点的后面,也就是说添加的节点就是父亲的最后一个儿子。
我们可以在任意一个位置添加子节点:会在原有标杆儿子之前插入
父亲.insertbefore(新儿子,原有标杆儿子) |
var btn = document.getelementbyid('btn'); var txt = document.getelementbyid('txt'); var ul = document.getelementsbytagname('ul')[0]; var lis = document.getelementsbytagname('li'); btn.onclick = function(){ //创建一个li标签,用变量oli 来表示,创建除了的节点不是任何节点的儿子(没有在dom树上) var oli = document.createelement('li'); oli.innerhtml = txt.value; //改变这个节点的内容 //把新创建的节点,追加到dom树上 //在lis[0]的前面插入 ul.insertbefore(oli,lis[0]); }
如果想每次都在开头添加,那么就是:
ul.insertbefore(oli,lis[0]); |
lis这个变量是动态的,这次添加的li,下回就是lis[0]。
3.3 removechild()删除
父亲.removechild(儿子); <ul> <li>吃饭 <a href="###">删除</a></li> <li>睡觉 <a href="###">删除</a></li> <li>打豆豆 <a href="###">删除</a></li> </ul> <script type="text/javascript"> var ul = document.getelementsbytagname('ul')[0]; var lis = document.getelementsbytagname('li'); var as = document.getelementsbytagname('a'); for(var i = 0;i< as.length;i++){ as[i].onclick = function(){ ul.removechild(this.parentnode); //如果要自杀,也要找到爸爸 //this.parentnode.removechild(this); } } </script>
如果要自杀,也要找到爸爸:
this.parentnode.removechild(this); |
3.4 replacechild()替换
替换节点:
父亲.replacechild(新儿子,旧儿子) |
<div> <p>赵丽颖</p> <p id="xh">小黑</p> <p>迪丽热巴</p> </div> <script type="text/javascript"> var obox = document.getelementsbytagname('div')[0] var xh = document.getelementbyid('xh'); //创建节点,孤儿节点 var op = document.createelement('p'); op.innerhtml = '朱老师'; //更改op的内容 obox.replacechild(op,xh); </script>
3.5 clone()克隆
克隆节点,参数true表示深度克隆,节点里面的所有内容和事件一同复制。
复制之后的节点是个孤儿节点,所以也要使用appendchild()等方法来添加上dom树。
克隆对象.clonenode(true) |
<div id="box1"> <ul> <li><span>赵丽颖</span></li> <li><span>迪丽热巴</span></li> <li><span>柳岩</span></li> <li><span>志玲姐姐</span></li> </ul> </div> <div id="box2"> </div> <script type="text/javascript"> var box1 = document.getelementbyid('box1'); var box2 = document.getelementbyid('box2'); var ul = document.getelementsbytagname('ul')[0]; var lis = document.getelementsbytagname('li'); //克隆li和li的所有后代(要加true),然后追加到ul中 //ul.appendchild(lis[0].clonenode()); //克隆第0个li box2.appendchild(ul.clonenode(true)); //克隆ul追加到box2中 </script>
四、事件监听
一堆理论知识正要来袭。
4.1事件流
我们考虑一个结构,三个div嵌套,点击最内层的div,我们点击了谁?仅仅点击了最内层div吗?不是就像手指放在到一个同心圆中,实际上手指触碰到了任何一个圆。
点击最内层的div,实际上浏览器会认为我们点击了所有的盒子,甚至于body、document、window。
为了描述事件的传播,人为规定了一个事件的传播方向,称为“事件流”。两个阶段:事件捕获阶段,事件冒泡阶段。
“事件流”描述的是页面上各个元素接收事件的顺序。
4.2 dom0级事件监听
dom分级别,dom0级、1级、2级、3级,是不同的标准,标准一直在升级。
之前学习的on开头的语法添加事件,称为“dom0级事件”。
事件的触发一定是按照事件流的顺序,由于dom0级只能监听冒泡阶段,所以顺序是:box3→box2→box1→body→document→window 如果改变监听顺序,弹出顺序不变。
box1.onclick = function(){ alert('我是box1');} box2.onclick = function(){ alert('我是box2');} box3.onclick = function(){ alert('我是box3');} document.body.onclick = function(){alert('我是body')} document.onclick = function(){alert('我是document')} window.onclick = function(){alert('我是window')}
这种监听写法,就是dom0级,就是把onclick当做属性添加给了div元素。
这种事件添加方法,只能监听冒泡过程,不能监听事件捕获阶段。
dom0级事件处理函数中,this指的是触发事件的dom元素,就是事件传播到的这个元素。
dom0级事件处理函数中,如果同一个对象,同一个事件名,绑定多个监听,后面写的覆盖前面写的。
box1.onclick = function(){ alert('我是box1');} box1.onclick = function(){ alert('我是box1,后面写的');} |
dom0级事件,ie6、7事件只能冒泡到document,ie8只能冒泡body,不能继续冒泡到window。也就是说不能给window对象添加事件。
4.3 dom2级事件监听
dom1级规范中,没有对事件进行改动,所以没有dom1级的事情
dom2级做了新的规范,不用on**来绑定监听了,而是用一个方法
w3c推出了addeventlistener()函数,add添加、event事件,listener监听
它接收三个参数:事件,函数,是否监听捕获阶段
元素.addeventlistener(事件,事件处理函数,是否添加到捕获阶段) |
第一个参数:事件名不用谢on。(click、mouseover)
第二个参数:函数可以是匿名函数,也可以是有名函数
第三个参数:布尔值,true表示监听捕获,false表示监听冒泡阶段
box1.addeventlistener('click',function(){ alert('我是box1的捕获阶段') },true);
第三个参数是true,表示监听box1的捕获阶段的单击事件。
要记住true表示捕获,false冒泡阶段:口诀:true上,false下。
box1.addeventlistener('click',function(){ alert('我是box1的捕获阶段') },true); box2.addeventlistener('click',function(){ alert('我是box2的捕获阶段') },true); box3.addeventlistener('click',function(){ alert('我是box3的捕获阶段') },true); box1.addeventlistener('click',function(){ alert('我是box1的冒泡阶段') },false); box2.addeventlistener('click',function(){ alert('我是box2的冒泡阶段') },false); box3.addeventlistener('click',function(){ alert('我是box3的冒泡阶段') },false);
box1的捕获→box2的捕获→box3的捕获→box3的冒泡→box2的冒泡→box1的冒泡
坑:最内层的box3,谁先写就谁先执行,也就是说对于最内层的box3,就不区分冒泡和捕获了,对于不少罪内层的元素来说,改变事件监听的顺序,不会影响执行结果,先捕获,后冒泡。
dom2级事件中,如果给同一个元素,同一个事件名,同一个阶段添加多个事件监听,彼此不会覆盖,先写的先执行。
box1.addeventlistener('click',function(){ alert('我是box1的冒泡阶段a') },false); box1.addeventlistener('click',function(){ alert('我是box1的冒泡阶段b') },false); box1.addeventlistener('click',function(){ alert('我是box1的冒泡阶段c') },false);
弹出顺序是:a→b→c
dom2级事件监听中,this指的是触发事件的这个元素,就是事件传播到的这个元素。
dom2级小测试-看看执行顺序:正确答案在下篇文章。
小题目:页面box1最大,嵌套box2、box3,点击box3弹出顺序
box2.onclick = function(){ alert('a'); } box2.onclick = function(){ alert('b'); } box2.addeventlistener('click',function(){ alert('c') },false); box2.addeventlistener('click',function(){ alert('d') },false); box2.addeventlistener('click',function(){ alert('e') },true); box2.addeventlistener('click',function(){ alert('f') },true); box3.addeventlistener('click',function(){ alert('g') },false); box3.onclick = function(){ alert('h') } box3.addeventlistener('click',function(){ alert('i') },true);
4.4低版本ie事件监听
ie6、7、8不支持addeventlistener()方法,支持attachevent()。
box1.attachevent('onclick', function(){ alert(1) });
第一个参数:必须写on,和addeventlistener不一样
第二个参数:事件处理函数
没有第三个参数,不能*选择添加到什么阶段,永远是冒泡阶段,也就是说ie678不能监听捕获阶段。
box1.attachevent('onclick', function(){ alert('我是1a'); }); box1.attachevent('onclick', function(){ alert('我是1c'); }); box1.attachevent('onclick', function(){ alert('我是1b'); }); box2.attachevent('onclick', function(){ alert('我是2'); }); box3.attachevent('onclick', function(){ alert('我是3'); });
比较搞笑,如果给同一个元素添加多个事件名相同的监听,不互相覆盖,但是倒着执行,先执行后写:
box1.attachevent('onclick', function(){ alert('我是a'); }); box1.attachevent('onclick', function(){ alert('我是b'); }); box1.attachevent('onclick', function(){ alert('我是c'); });
弹出c、b、a
最诡异是,this永远是window对象而不是事件传播到的元素。
box1.attachevent('onclick', function(){ alert(this === window); });
所以最正确的工作实践,就是用dom0级事件监听方法,除非基于特别充分的理由,否则不用dom2级。什么时候理由充分用dom2级呢?比如一些新兴事件,如手机事件:touchstart、touchmove、touchend事件等等。只能用dom2级。
上面学习的就是一些理论知识,总结一下:
事件流永远是先下(捕获)后(冒泡),但是不同监听方式,决定了监听那一部分。
面试意义大于实际意义!
jquery中用的就是dom2级,也有*,jquery事件同名不会被覆盖。
4.5事件监听移除
dom0级事件监听的移除很简单,直接把事件属性赋值给null即可。
var box1 = document.getelementbyid('box1'); box1.onclick = function(){ alert('你好,再次点击就没有效果了'); box1.onclick = null; //移除事件监听 }
dom2级事件监听移除,必须指名道姓移除,也就是说,如果是匿名函数添加的事件监听,是不可能去掉的。
添加的时候要有名字:
box1.addeventlistener('click',function fun(){ alert('你好'); box1.removeeventlistener('click',fun,true); },true);
点击按钮后,移除box1的事件监听:
btn.onclick = function(){ box1.removeeventlistener('click',fun,true); }
ie6、7、8用detachevent即可,同样,也必须起名。
box1.attachevent('onclick',fun) function fun(){ alert('你好'); } btn.onclick = function(){ box1.detachevent('onclick',fun); }
五、事件对象event
这里的知识就不是理论了 ,有实战价值。
5.1 event兼容性问题
在任何事件中,都有事件对象event。浏览器会往事件处理函数中,传入一个实参,就是事件对象,里面封装了你这次触发事件(点击、鼠标移入、移出、键盘按下)的细节。比如鼠标位置、是否按下某个键等等。
一般用变量event来接收,注意,不是必须的,名字可以改。
所有事件的细节,都被封装到event对象里面。
比如clinetx、clinety就是这次鼠标点击的位置。
先说兼容性问题,ie678中,event这事件对象不是实参,而是全局变量,系统会在每一个事件发生的时候,都去改变这个全局变量的值:
box.onclick = function(){ //圆括号不能写event,如果写了,就遮蔽了全局的event alert(event.clientx) }
兼容写法:
box.onclick = function(event){ //因为在chrome中event是实参,ie678events全局变量,所以用或的短路语法,它支持哪个用哪个 var event = event || window.event; alert(event.clientx) }
5.2事件对象属性
event.type 返回事件类型,没有on,比如“click” event.target 返回你点击的最小哪个元素,即使这个元素身上没有监听,也返回它 event.currenttarget 返回自己,this一定和它是同一个元素,都是自己 event.bubbles 返回布尔值,表示这个事件是否冒泡 |
●bubbles属性,表示事件是否冒泡
box1.onmouseover = function(event){ var event = event || window.event; console.log(event.bubbles); //表示是否冒泡 }
基本上所有事件这个属性都是true,表示这个事件冒泡,但是要记住:
onmouseover的event.bubbles是true,表示冒泡 onmouseout的event.bubbles是true,表示冒泡 onmouseenter的event.bubbles是false,表示不冒泡 |
有两个事件不冒泡:
onmouseenter和mouseleave的event.bubbles是false,不冒泡 |
onmouseenter和mouseleave这两个事件ie678910全面兼容!反而是chrome30之前不兼容,但是现在可以当做全面兼容。它们两个事件是著名天生不冒泡的,当一个内部元素鼠标进入了,会执行这个元素的事件处理函数,但是事件捕获继续往外层传播。它的外层盒子不会触发onmouseenter事件。
box1.onmouseenter = function(event){ alert('鼠标进入了box1') } box2.onmouseenter = function(event){ alert('鼠标进入了box2') } box1.onmouseout = function(event){ alert('鼠标离开了box1') } box2.onmouseout = function(event){ alert('鼠标离开了box2') }
onmouseenter和mouseleave比onmouseover和onmouseout好用
// $('#box').mouseenter(function(){ // $(this).children('.mask').slidedown(); // }); // $('#box').mouseleave(function(){ // $(this).children('.mask').slideup(); // }); $('#box').mouseover(function(){ $(this).children('.mask').slidedown(); }); $('#box').mouseout(function(){ $(this).children('.mask').slideup(); });
●target、srcelement属性,表示事件发生的最内层元素
chrome同时支持下面2个属性,ie只支持srcelement:
var target = event.target || event.srcelement; |
用这个属性可以优化代码效率,可以制作“事件委托”。把子元素的事件,委托给父亲,父亲通过event.target来判断是谁触发了事件。不使用事件委托,我们将会有很多事件监听;使用事件委托,事件监听只有1个。提升了页面的效率。
box1.onclick = function(event){ var event = event || window.event; var target = event.target || event.srcelement; alert(target.id) }
事件委托:
比如,小圆点添加监听,不要给所有li,直接给ol,让ol的event.target这个元素有cur
<body> <ol> <li class="cur">0</li> <li>1</li> <li>2</li> <li>3</li> <li>4</li> <li>5</li> </ol> </body> <script type="text/javascript" src="js/jquery-1.12.4.min.js"></script> <script type="text/javascript"> $('ol').mouseover(function(event){ var event = event || window.event; //得到触发事件的最小元素 var target = event.target || event.srcelement; //让触发事件的元素添加cur $(target).addclass('cur').siblings().removeclass('cur'); }); </script>
当页面上有大量的重复元素要添加监听的时候,比如100/200个,一定要注意事件委托。
ps:尽量让它越来越规范,前期的文章都是本人的学习时的笔记整理,希望看完后可以指点一二,提提意见多多交流;
笔记流程:html>css>javascript>jquery>html5/css3>移动端>ajax>面向对象>canvas>nodejs>es678>vue>react>小程序>面试问题
意见请留言,邮箱:scarf666@163.com
上一篇: 网站地址 静态化 不静态化分析
下一篇: vue 路由导航白话全解析
推荐阅读
-
前端笔记知识点整合之JavaScript(十)深入JavaScript节点&DOM&事件
-
前端笔记知识点整合之JavaScript(四)
-
前端笔记知识点整合之JavaScript(十二)缓冲公式&检测设备&Data日期
-
前端笔记知识点整合之JavaScript面向对象(一)Object&函数上下文&构造函数&原型链
-
前端笔记知识点整合之JavaScript(六)关于那个让人头疼的正则表达式
-
前端笔记知识点整合之jQuery(下)事件&节点操作&净位置&拖拽&页面卷动值&遍历JSON
-
前端笔记知识点整合之JavaScript(九)定时器&JSON&同步异步/回调函数&函数节流&call/apply
-
前端笔记知识点整合之JavaScript(八)关于元素&计算后的样式
-
前端笔记知识点整合之JavaScript(五)关于数组和字符串那点事
-
前端笔记知识点整合之JavaScript(十)深入JavaScript节点&DOM&事件