一、事件
事件是电脑输入设备(鼠标、键盘)与页面进行交互的响应
事件对象
- 除IE8及以下版本的浏览器:当事件的响应函数被触发时,浏览器每次都会将一个事件对象作为实参传递进响应函数,在事件对象中封装了当前事件相关的一切信息,比如:鼠标的坐标、键盘哪个按键被按下,鼠标滚轮滚动的方向…
clientX可以获取鼠标指针的水平坐标 event(形参).clientX
clientY可以获取鼠标指针的垂直坐标 - 除了火狐浏览器:事件对象是作为window的一个属性,直接window.event(形参).clientX
解决兼容性问题:event=event||window.event - clientX和clientY用于获取鼠标在当前的可见窗口的坐标 而div的偏移量是相对于整个页面的
- pageX和pageY可以获取鼠标相对于当前页面的坐标(IE8及以下版本不可用)
事件的冒泡
- 所谓的冒泡指的就是事件的向上传导,当后代元素上的事件被触发时,其祖先元素的相同事件也会被触发(一定是相同事件onclick等)
- 在开发中大部分情况冒泡都是有用的,如果不希望发生事件冒泡,可以通过事件对象来取消冒泡:给函数设置一个事件对象形参,在代码末尾 event.cancelBubble=true;
事件的委派
- 给每一个元素依次添加事件,或者每新建一个元素都添加一个事件比较麻烦,并且性能低,直接给这些元素共同的父元素绑定事件,可参考博文:事件委派详解
- 使用event.target.className=="link"来判断触发对象是不是我们期望的元素,是则执行(target获取触发事件的对象)
事件的绑定/注册
告诉浏览器,当事件响应后要执行哪些操作代码
-
静态注册事件:
将事件写在标签中,一般都只写一句代码或者直接调用一个已经写好的函数 - 动态注册(绑定):
一般在window.onload页面加载完成时执行的函数里进行动态绑定事件代码)
先通过js代码得到标签的DOM对象,再通过DOM对象.事件名=function(){} - 使用 对象.事件=函数 的形式绑定响应函数,它只能同时为一个元素的一个事件绑定一个响应函数,不能绑定多个,会出现函数的覆盖
- (1) addEventListener() 通过这个方法为元素绑定响应函数(IE8及以下版本不支持)
(2) 对象.addEventListener(“事件的字符串去掉on”,function(){…},false) 最后一个参数:是否在捕获阶段触发事件,需要一个bool值,一般传false
(3) 使用addEventListener可以同时为一个元素的相同事件绑定多个响应函数,当事件被触发时,响应函数会按照函数绑定顺序依次执行(在IE8及以下版本中: 对象.attachEvent(“事件的字符串要on”,function(){…});
也可以为一个对象的相同事件绑定多个响应函数,只不过执行顺序是先绑定后执行) - 浏览器的兼容:
自己设置函数 参数:obj要绑定事件的对象 eventStr事件的字符串(不要on) callback回调函数
function(obj,eventStr,callback){
if(obj.addEventListener){
obj.addEventListener(eventStr,callback,false);(回调函数中的this是obj对象)
}
else{
obj.attachEvent(eventStr+“on”,callback);(回调函数中的this是window对象)
将window对象准换为obj对象:callback---->function(){ callback.call(obj);} 浏览器调用的函数我们不能改调用对象,但是自己调用的函数可以更改,第二种浏览器调用匿名函数function,我们再用自己想用的调用方式调用callback函数
}
}
常用事件
-
onload:加载完成事件 页面加载完成之后,常用于做页面js代码初始化操作
(1)静态:写在body标签中
(2)动态:window.onload = function(){}; -
onclick:单击事件 常用于按钮的点击响应操作
(1)静态:一般写在button标签中
(2)动态:var btn=document.getElementById("");
btn.onclick = function(){}; -
onblur:失去焦点事件 常用于输入框失去焦点后验证其输入内容是否合法
-
onchange:内容发生改变事件 常用于下拉列表和输入框内容发生改变后的操作
-
onsubmit:表单提交事件 常用于表单提交前,验证所有表单项是否合法
return false 可以阻止表单提交,在验证到不合法时就return false
< form action=“http://localhost:8080” method=“get” οnsubmit=“return fun()”> //一定要写一个return
< input type=“submit” value=“静态注册”>
< /form>
function fun(){
alert(“静态注册页面”);
return false;
} -
键盘事件
1.键盘事件一般都会绑定给一些可以获取到焦点的对象或者是document(输入框)
2.onkeydown:一直按着某个键事件会一直触发,连续触发时,第一次和第二次之间会间隔稍微长一些,其他的会非常快
3.onkeyup:按键被松开
4.event.keycode判断哪个按键被按下
event.altKey ctrlKey shiftKey判断对应是否被按下
5.return false 取消默认行为(向焦点框里自动添加输入按键)可以实现规定哪些按键能被按下
6.在使用时可以先输出按下键的编码来帮助 写代码
事件的传播
1.由内往外传播、冒泡传播
2.三个阶段:捕获阶段(由外向内捕获事件),目标阶段,冒泡阶段(由内向外执行事件)(在IE8及以下版本没有捕获阶段)
二、DOM对象
1.DOM查找
-
对网页进行增删改查:查找节点,读取节点,修改节点,创建节点,删除节点
节点:文档节点、元素节点、属性节点、文本节点 -
按id属性,精确查找一个元素对象
var elem=document.getElementById(“id”);效率非常高 只能用在document上 不是所有元素都有id(不加就不会执行) -
按标签名查找
varelems=parent.getElementsByTagName(‘tag’); 注意是单引号,返回一个数组,需要通过下标访问
查找指定parent节点下的所有标签为tag的子代节点
(1).可用在任意父元素上
(2).不仅查直接子节点,而且查所有子代节点
(3).返回一个动态集合,即使只找到一个元素,也返回集合必须用[0],取出唯一元素
var elems =ul.getElementsByTagName(‘li’); -
通过name属性查找
var elem = document.getElementsByName (‘name属性值’);
可以返回DOM树中具有指定name属性值的所有子元素集合 -
通过class查找
查找父元素下指定class属性的元素
var elems = parent.getElementsByClassName(‘class’); 有兼容性问题 IE8以下版本不支持 -
通过css选择器查找
元素、类、Id、后代、子代、群组选择器
var elems = parent.querySelector(“selector”); Selector支持一切css中选择器,如果选择器匹配的有多个,只返回第一个
var elsms = parent.querySelectorAll(“seletor”);查找多个选择器,返回的是非动态集合 -
innerHTML用于获取元素内部的HTML代码,对于自结束标签,这个属性没有意义,读取元素节点属性:元素.属性名(class标签用className)
innerText 获取元素内部的文本,纯文本,不含元素 -
根据属性查找父元素下的所有子节点:
父元素.childNodes 获取所有节点,根据DOM标准标签间写的空白也是节点(IE8及以下版本除外)
------换成用children属性,获取当前元素的所有子元素,不会包含空白文档
父元素.firstChild 获取父元素下第一个节点(包含空白文本)
------换成用firstElementChild获取第一个子元素(不支持IE8及以下版本)
父元素.lastChild 获取父元素下的最后一个节点 -
找父节点:子节点.parentNode;
找前兄弟节点:子节点.previousSibling; (会获取空白处) 子节点.previousElementSibling; (会获取前一个节点,不包含空白) 找兄弟节点: -
document.body------body标签
document.documentElement------html标签
document.all------页面中所有的元素,返回值为一个数组 相当于getElementByTagName("*") -
confirm()用于弹出一个有确认和取消的提示框---------有bool型的返回值
DOM修改
-
DOM标准:
核心DOM:可操作一切结构化文档的AOI,包括HTML和XML(万能、繁琐)
HTML DOM:专门操作HTML文档简化版DOM API仅对常用的复杂的API进行了简化(不是万能,简单的) -
修改属性四个操作:
读取属性值
(1)先获得属性节点对象,再获得节点对象的值: elem.attributes[下标/属性名] elem.getAttributeNode[属性名] attrNode.value-----属性值;;
(2) 直接获得属性值:elem.getAttribute(“属性名”)
修改属性值
(3)elem.setAttribute(“属性名”,value)
判断是否包含指定的属性:
element.hasAttribute(‘属性名’) 返回值为bool类型
移除属性
elem.removeAttribute(“属性名”) -
修改样式:(修改的是内联样式,具有较高的优先级,改后立即显示,但如果在样式中写了!important,则此时样式会有最高优先级,js修改代码会失效)
(1)内联样式:elem.style.属性名(也可以用来读取样式,读取的也是内联样式,如果内联样式没有就为空)
(2)属性名:去横线,变驼峰 (background-color-----backgroundColor ) -
获取元素的当前显示样式(都是只读的,修改只能用style)
元素.currentStyle.样式名-----可以获取当前元素正在显示的样式(如果没有设置样式就获取默认样式(宽度:auto),只有IE浏览器支持,其他的都不行)
(除IE8及以下版本的)浏览器通用:getComputedStyle() 这个方法是window的方法,可以直接使用
需要两个参数:
1.需要获取样式的元素
2.传递一个伪元素,一般为null
该方法会返回一个对象,对象中封装了当前元素对应的样式,访问:对象.样式名,如果没有设置样式,会获取真实的值,而不是默认值,比如宽度:auto(默认值)—>具体宽度;颜色—>rgb值兼容所有浏览器(自己创建一个判断方法):(兼容性问题都是一个思路,先判断有没有,有就用,没有就不用)
function getStyle(obj,name){
if(window.getComputedStyle) (在IE8中直接用getComputedStyle会报错,因为不存在这个变量,但是用Window.getComputedStyle属性会返回undefined,不会报错)
return getComputedStyle(obj,null)[name];(不写.name,写了表示访问name属性,写死了)
else
return obj.currentStyle[name];
或者 return window.getComputedStyle?getComputedStyle(obj,null)[name]:obj.currentStyle[name];
}
样式的相关属性
都是只读属性,修改只能修改style
- clientWidth clientHeight------这两个属性可以获取元素的可见宽度和高度,不带px,返回数字可直接进行计算
- offsetWidth offsetHeight—获取元素的整个宽度和高度,包括内容区、paddig、border
- offsetParent—用来获取当前元素的定位父元素,获取到离当前元素最近的开启了定位的祖先元素,如果都没开则返回body
- offsetLeft offsetTop—获取当前元素相对于其定位父元素的水平、垂直偏移量
- scrollWidth scrollHeight-----可以获取元素的滚动区域高度和宽度
- scrollLeft scrollTop—获取滚动条水平和垂直滚动的距离
当满足scorllHeight - scorllTop ==clientHeight 时说明垂直滚动条滚动到底了
当满足scorllWidth - scorllLeft = clientWidth时说明水平滚动条滚动到底了
DOM添加
-
创建空元素
var elem = document.createElement(“元素名”) var table = document.ceateElement(“table”); -
设置关键属性
elem.属性名=“属性值”
elem.innerHTML=“go to tmooc” a.href=“http…” -
设置关键样式
元素.style.样式名=样式值
elem.style.opacity=“1”;
elem.style.cssText=“width:100px;height:100px”;(可添加多个样式) -
将元素添加到DOM树 parentNode.appendChild(childNode); 添加在最后一个父元素
parentNode.insertBefore(newChild,existingChild) 在父元素中的指定子节点之前添加一个新的子节点,指定子字节通过查找得到
添加元素优化:尽量少的操作DOM树,每次修改DOM树,都导致重新layout,先构建好小树,再挂到DOM树上
(1)如果同时创建父元素和子元素时,建议在内存中先将子元素添加到父元素,再将父元素一次性挂到页面上
(2)如果只添加多个平级子元素时,就要将所有子元素,临时添加到文档片段中,再将文档片段整体添加到页面
文档片段: 内存中,临时保存多个平级元素的虚拟父元素,用法和普通父元素完全一样
步骤:
(1)创建片段: var frag =document.createDocumentFragment()
(2)将子元素临时追加到frag中 frag.appendChild(child);
(3)将frag追加到页面 parent.appendChild(frag);
append之后,frag自动释放,不会占用空间
注意:
DOM操作中如果涉及父元素,直接元素.parentNode就行,不用管是谁使用innerHTML也可以实现增删改查,直 接改html代码,但是要避免不直接操作DOM树
三、BOM对象
- 专门操作浏览器窗口的API,BOM可以使我们通过js来操作浏览器
- BOM常见对象:
(1)Window–代表整个浏览器的窗口,也是网页中的全局对象,网页中的变量–window的属性,网页中的函数–window的方法
(2)Navigator–代表的当前浏览器的信息,通过该对象可以来识别不同的浏览器
(3)Location–代表当前浏览器的地址栏信息,可以获取地址信息,或者操作浏览器跳转页面
(4)History–代表浏览器的历史记录,可通过其来操作浏览器的历史记录,由于隐私问题,该对象不能获取到具体的历史记录,只能操作浏览器向前向后翻页,而且该操作只能在当次访问时有效
(5)Screen–代表用户的屏幕信息,通过该对象可以获取用户的显示器的相关信息
(6)其他:document、event
Window
-
使用:直接使用或者作为window的属性使用
-
获取当前窗口大小:完整窗口大小:window.outerWidth/outerHeight
文档显示区大小:window.innerWidth/innerHeight -
定时器:让程序按指定时间间隔自动执行任务,实现网页动态效果、计时功能等
分类:
(1)周期性定时器:setinterval(ex p,time)
exp:执行语句
time:时间周期,单位为毫秒
注:在开启下一个定时器时要先关闭当前元素的上一个定时器,不然会出现定时器重复开启(加速)
停止定时器:(1)给定时器取名:var timer =setinterval(…)
(2)停止定时器:clearinterval(timer);
clearinterval()可以接受任何参数,包括null,undefined,如果参数有效则执行,无效则什么都不做
(2)一次性定时器 :让程序延迟一段时间执行 setTimeout(exp,time)
time:时间间隔,单位为毫秒
Navigator
(1)由于历史原因,Navigator对象中的大部分属性都不能帮助我们识别浏览器了,一般我们只会使用userAgent来判断浏览器的信息,userAgent是一个字符串,这个字符串中包含有用来描述浏览器的信息,不同浏览器有不同的userAgent,配合正则表达式(是否含有浏览器名字关键字)来判断是什么浏览器
(2)由于IE11没有MSIE关键字,所以IE浏览器不能这样操作,但是IE有很多自己特有的对象和属性,我们可以通过判断是否存在来看
if(“ActiveXObject” in winodw)一个特殊的对象(即window的属性)
History
(1)length属性,可以获取到当前访问的链接数量
(2)back()可以回退到上一个页面,与返回按钮一样
(3)forward()可以跳转到下一个页面,作用与前进按钮一样
(4)go()可以跳转到指定页面,它需要一个整数作为参数:
1–向前跳转一个页面
2–向前跳转两个页面
-1–向后跳转一个页面
-2–向后跳转两个页面
Location
-
直接打印,可以获取当前页面的完整路径
-
可以直接修改Location为相对路径或者绝对路径,并且会生成历史记录
-
Location.assign("…")------>跳转到其他页面
-
Location.reload()------->刷新页面
传一个参数true:强制清空缓存(与ctrl+f5是一个效果,完全清空文本框内容) -
Location.replace("…")用新的页面替换当前页面,但是不会生成历史记录,不能使用回退按钮回退
补充知识
原型对象
- 相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,可以将对象中公有的内容,统一设置到原型对象中
- 我们每创建一个函数,解析器都会向函数添加一个属性prototype,这个属性对应原型对象,这个属性对于普通函数没有任何作用
- 当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含的属性,指向该构造函数的原型对象,通过_proto_来访问
- 使用对象的hasOwnProperty来检查对象自身是否含有该属性
- 原型对象也是对象,也有原型,当使用一个对象的属性和方法时,会在自身中寻找,自身如果有就直接使用,没有就去原型对象中找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object中依然没有找到,则返回undefined
- 使用obj.hasOwnProperty(属性名)检查对象自身是否有这个属性
- 我们打印对象时打印的对象的tostring()方法,我们可以通过修改对象的prototype属性来设置原型对象
类的操作
- 在js中同时修改多个样式属性:
box.className = “b2”;
不采用一个一个样式地修改,直接修改元素的class属性(设置一个新的class),浏览器只需要重新渲染一次,性能高,可以将行为和表现分开 - 添加多的样式,或者修改部分样式:
box.className+=" b2" ;注意加一个空格 - 自己设置addClass 、hascClass(利用正则表达式判断是否有某个类和removeClass三个函数)