网站首页 > 技术文章 正文
本内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
事件有很多类型,不同的事件类型具有不同的信息;
DOM2级事件规定了下列5种事件:
- UIEvent(user Interface,用户界面)事件,在用户与页面上的元素交互时触发;
- MouseEvent鼠标事件,当用户通过鼠标在页面上执行操作时触发;
- KeyboardEvent键盘事件:通过键盘在页面上执行操作时触发;
- HTML事件:当浏览器窗口发生变化或发生特定的客户端/服务器交互时触发;
- MutationEvent变动事件:当底层DOM结构发生变化时触发;
DOM3级在DOM2的基础上重新定义了这些事件,并增加了一些事件:
- FocusEvent焦点事件:当元素获得或失去焦点时触发;
- WheelEvent滚轮事件:当使用鼠标滚轮(或类似设备)时触发;
- 文本事件:当在文本中输入文本时触发;
- 合成事件:当为IME(Input Method Editor,输入法编辑器)输入字符时触发;
HTML5规范也定义了大量的事件:历史管理、拖放、跨文本通信,以及多媒体等事件;
除了这些事件,有些浏览器会在DOM和BOM中也实现其他专有事件;
从另外一个角度来分,事件大致可以分成几大类:
依赖于设备的输入型事件:这些事件依赖于特定的输入设备,比如鼠标和键盘,也包括触摸事件;例如,mousedown、mousemove之类的,只能通过鼠标设备,而keydown或keypress只能通过键盘设备,touchmove或gesturechange也只能通过触摸设备实现;
独立于设备的输入型事件:不依赖于特定的输入设备,比如click事件,既可以通过鼠标单击实现,也可以通过键盘或触摸设备实现;再如textinput事件,即可以通过键盘按键实现,也可以在剪切和粘贴实现,甚至通过手写设备来实现;
用户界面事件:通常指的是一些注册在表单控件上的事件,例如文本框获取焦点的focus事件,控件改变值的change事件或提交表单的submit事件;
状态变化事件:表示某些生命周期或相关状态的变化的事件,比如,文档加载的load事件或DOMContentLoaded事件或文档状态readystatechange事件;再如HTML5的历史管理的popstate事件,online或offline事件;
特定API事件:HTML5及相关的规范中定义的事件,例如:拖放事件,多媒体的相关事件;
UIEvent事件:
UIEvent事件表示简单的用户界面事件,但包含一些不一定与用户操作有关的事件,主要与元素的焦点有关;
该事件类继承自Event类;由其也派生出其他子类,如MouseEvent、TouchEvent、FocusEvent、KeyboradEvent、WheelEvent、InputEvent和CompositionEvent;
其自身定义了一些属性,如:detail、layerX、layerY、pageX、pageY、sourceCapabilities、view和which;
UIEvent相关的事件:
- DOMActive:表示元素已经被用户操作(通过鼠标或键盘)激活时发生;
- load:当页面完全加载后在window上触发,当所有框架都加载完毕时在框架集上触发,当图像加载完毕时在<img>元素上触发,或者当嵌入的内容加载完成时在<object>元素上触发;
- unload:当页面完全卸载后在window上触发,当所有框架都卸载后在框架集上触发,或者当嵌入的内容卸载完毕后在<object>元素上面触发;
- abort:当用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上触发;
- error:当发生Javascript错误时在window上触发,当无法加载图像时在<img>元素上面触发,当无法加载嵌入内容时在<object>元素上触发,或者当一或多个框架无法加载时在框架集上触发;
- select:当用户选择文本框(<input>或<textarea>)中的一或多个字符时触发;
- resize:当窗口或框架的大小变化时在window或框架上触发;
- scroll:当用户滚动带滚动条的元素中的内容时,在该元素上触发;
以上这些事件,在DOM2级事件中,除了DOMActive之外,其他事件都属于HTML事件,所以,在确定浏览器是否支持DOM2级事件,最后检测一下,如:
var isSupported = document.implementation.hasFeature("HTMLEvents","2.0");
确定浏览器是否支持DOM3级事件,如:
var isSupported = document.implementation.hasFeature("UIEvent","3.0");
另外,这些事件,多数与window对象或表单控件相关,所以有些地方把这些事件也称为window事件,就是因为这些事件的发生多数与浏览器窗口有关;
load加载事件:当页面完全加载后(包括所有图像、Javascript文件和CSS文件等外部资源),就会触发window对象的load事件,这也是Javascript中最常使用的事件;
有两种定义onload事件处理程序的方式:
window.addEventListener("load", function(event){
console.log("Loaded");
console.log(event); // Event
},false);
// 或在IE10以下
window.attachEvent("onload", function(event){
console.log("Loaded");
console.log(window.event);
});
为<body>元素添加onload特性;
<body onload="console.log(event);">
一般来说,在window上发生的任何事件都可以在<body>元素中通过相应的特性来指定,因为在HTML中无法访问window元素;
图像也可以触发load事件,无论是在DOM中的图像还是在HTML中的图像元素;
<img src="images/1.jpg" onload="alert('图片已加载')" />
或:
var img = document.querySelector("img");
img.addEventListener("load", function(event){
console.log(event.target.src);
});
// 或
EventUtil.addHandler(img, "load", function(event){
event = EventUtil.getEvent(event);
console.log(EventUtil.getTarget(event).src);
});
在创建新的<img>元素时,可以为其指定一个事件处理程序,只需要指定src属性就可以下载,并不需要添加到DOM树中,如:
window.addEventListener("load", function(event){
var img = document.createElement("img");
img.addEventListener("load", function(e){
console.log(e.target.src);
});
img.src = "images/1.jpg";
document.body.appendChild(img);
});
// 或者
EventUtil.addHandler(window, "load", function(){
var img = document.createElement("img");
EventUtil.addHandler(img, "load", function(event){
event = EventUtil.getEvent(event);
console.log(EventUtil.getTarget(event).src);
});
img.src = "images/1.jpg";
document.body.appendChild(img);
});
还可以使用DOM0级的Image对象实现,如:
// 把
var img = document.createElement("img");
// 换成
var img = new Image();
还有一些元素也以非标准的方式支持load事件;在标准浏览器中,<script>元素也会触发load事件,以确定动态加载的js文件是否加载完毕,在设置了<script>的scr属性并且添加到文档中,才会开始下载;
window.addEventListener("load", function(){
var script = document.createElement("script");
script.addEventListener("load", function(event){
console.log(event.target.src);
});
script.src = "scripts/main.js";
document.getElementsByTagName("head")[0].appendChild(script);
});
// 或
EventUtil.addHandler(window, "load", function(){
var script = document.createElement("script");
EventUtil.addHandler(script, "load", function(event){
console.log(event);
var target = EventUtil.getTarget(event);
console.log(target.src);
});
script.src = "scripts/main.js";
document.getElementsByTagName("head")[0].appendChild(script);
});
此时,event对象的target及currentTarget或srcElement引用都是<script>节点;
IE8及以下浏览器不支持<script>元素上的load事件,但以上代码不会抛出异常;
浏览器还支持<link>元素上的load事件,如:
window.addEventListener("load", function(){
var link = document.createElement("link");
link.rel = "stylesheet";
link.addEventListener("load", function(event){
console.log(event.target.href);
});
link.href = "styles/css.css";
document.getElementsByTagName("head")[0].appendChild(link);
});
与<script>类似,指定其href属性并且添加到文档中才会下载;
unload事件:在页面被完全卸载后触发;或者从一个页面切换到另一个页面,或者刷新操作也会触发unload事件,如:
<body onunload="alert('unload');">
抛出异常:blocked alert during unload,也就是页面被阻塞了,而在unload事件处理中,是不允许阻塞的,诸如弹窗之类的,都会引起阻塞;正确的做法:
<body onunload="console.log('unload');">
或:
EventUtil.addHandler(window, "unload", function(event){
console.log("unload");
});
- unload事件特点:
- unload事件的event对象只包含target(或srcElement)属性,且值为document;
- unload事件发生时的状态应该是:
- 所有资源仍存在 (图片, iframe 等.)
- 对于终端用户所有资源均不可见;
- 界面交互无效 (window.open, alert, confirm 等,会引起阻塞);
- 错误不会停止卸载文档的过程;
unload事件执行时间很短,并且是在一切都被卸载之后才触发,所以不适合处理常规代码,一般是取消(或清除)该页面上的对象引用,以避免内存泄漏;
var obj = {name:"wangwei",age:18};
window.addEventListener("unload", function(event){
var oDiv = document.getElementById("mydiv");
console.log(oDiv);
var img = document.getElementsByTagName("img")[0];
console.log(img);
console.log(obj);
obj = null;
console.log(obj);
debugger;
});
var obj = {name:"wangwei",age:18};
window.addEventListener("unload", function(event){
localStorage.setItem("unload","页面被unload了");
localStorage.setItem("person", obj);
});
示例:统计一个页面停留的时长,如:
window.addEventListener("load", function(){
var start = new Date();
console.log(start);
window.addEventListener("unload", function(){
var end = new Date();
var duration = (end.getTime() - start.getTime()) / 1000;
var pageView = {
pageStayTime: duration,
pageUrl: location.href
};
console.log("保存到数据库中");
});
});
另外,unload事件是不冒泡的,也是不可取消的;
同样,DOM2级事件规定应该在<body>元素而非window对象上触发unload事件,但所有浏览器都在window上实现了unload事件;
error事件:window.onerror属性看起来像事件处理程序,并且当Javascript出错时就会触发它,但是,它并不是真正的事件处理程序,因为它的参数不是event对象,而是5个参数,由这5个参数可以获取详细的错误信息;
- message:错误信息,描述错误的一条消息;
- URL:引发错误的Javascript所在的文档的URL;
- line:文档中发生错误的行数;
- column:发生错误的列数;
- error:错误对象,这个error也称为全局错误对象;
window.onerror = function(sMessage, sUrl, sLine, sColumn, error){
console.log("Error:" + sMessage + " URL:" + sUrl + " Line:" + sLine + " Column:" + sColumn);
console.log(error);
return true;
}
但如果使用DOM2级事件处理程序,其中的参数就是event对象;
window.onload = function(){
num1 + num2;
}
window.addEventListener("error", function(event){
console.log(event); // ErrorEvent
return true;
});
ErrorEvent类继承自Event类,其定义了如下属性:
- message:只读,返回包含了所发生错误的描述信息;
- filename:只读,包含了发生错误的脚本文本的URL;
- lineno:只读,错误发生的行号;
- colon:只读,错误发生的列号;
- error:只读,发生错误时所抛出的Error对象;
这5个属性也对应着window.onerror属性的5个参数;
如果是图片的onerror事件,就是一个真正的事件,其中只有一个参数,就是一个event对象;
var img = document.getElementsByTagName("img")[0];
img.onerror = function(event){
console.log(event); // Event type为error
}
abort事件:当一个资源的加载已中止时,将触发该事件;
var video = document.querySelector("video");
videoSrc = "https://www.zeronetwork.cn/video.webm";
video.addEventListener("abort", function(event){
console.log(event);
console.log("下载中止:" + videoSrc);
});
var source = document.createElement("source");
source.setAttribute("src", videoSrc);
source.setAttribute("type", "video/webm");
video.appendChild(source);
source.addEventListener("error", function(event){
console.log(event);
return true;
});
resize事件:当浏览器窗口的大小被调整,就触发resize事件,该事件在window上触发;
EventUtil.addHandler(window, "resize", function(event){
console.log(event);
});
在标准浏览器中,event对象有target属性,且值为window对象,但IE未提供任何属性;
浏览器的大小改变1像素就会触发resize事件,然后再随着变化不断重复触发;
最大化或最小化窗口时,也会触发resize事件;但是部分浏览器会在最大化或最小化时触发两次或以上的该事件,此时可以使用setTimeout()解决,也就是延迟执行某些代码,如:
function callBack(){
console.log("callBack");
}
window.addEventListener("resize", function(event){
var target = this;
if(target.resizeFlag)
clearTimeout(target.resizeFlag);
target.resizeFlag = setTimeout(function(){
callBack();
console.log("resize");
target.resizeFlag = null;
},200);
});
示例:随窗口大小的变化而变化,如:
var mydiv = document.getElementById("mydiv");
var w = mydiv.clientWidth,
h = mydiv.clientHeight,
dx = w / h,
dw = document.documentElement.clientWidth,
scale = w / dw;
window.addEventListener("resize", function(event){
var dw = document.documentElement.clientWidth;
mydiv.style.width = dw * scale + "px";
var w = mydiv.clientWidth;
mydiv.style.height = w * dx * scale + "px";
console.log(mydiv.style.width);
console.log(mydiv.style.height);
});
示例:
<style>
*{margin:0;padding:0;}
.leftDiv,.rightDiv{
width: 40%; overflow-y: scroll; float: left; margin-right: 10px; background-color: purple;
}
</style>
<div class="leftDiv">leftDiv ...</div>
<div class="rightDiv">rightDiv ...</div>
<script>
var leftDiv, rightDiv, dHeight;
window.addEventListener("load", function(){
leftDiv = document.querySelector(".leftDiv");
rightDiv = document.querySelector(".rightDiv");
dHeight = document.documentElement.clientHeight;
leftDiv.style.height = dHeight + "px";
rightDiv.style.height = dHeight + "px";
});
window.addEventListener("resize", function(event){
dHeight = document.documentElement.clientHeight;
leftDiv.style.height = dHeight + "px";
rightDiv.style.height = dHeight + "px";
});
</script>
resize事件目前只能注册在window对象上,它不支持注册在DOM元素上,如果要监听DOM元素的resize事件,最好的方案就是使用自定义事件;
scroll事件:虽然是在window对象上发生,但它实际表示的是页面中相应元素的变化;即可以在滚动窗口或其他元素时,跟踪变化来确保某些内容一直在屏幕上可见;
window.addEventListener("scroll", function(event){
console.log(event); // Event
});
该事件对象并没有提供滚动相关的信息,只是一个普通的Event的对象;
在混杂模式下,可以通过<body>元素的scrollLeft和scrollTop来监控到这一变化;在标准模式下,会通过<html>元素来反映这一变化;
window.onscroll = function(){
console.log("x:" + document.documentElement.scrollLeft + ", y:" + document.documentElement.scrollTop);
}
// 或
window.addEventListener("scroll", function(event){
if(document.compatMode == "CSS1Compat")
console.log(document.documentElement.scrollTop);
else
console.log(document.body.scrollTop);
});
与resize事件类似,scroll事件会在文档被滚动活动期间会被重复触发,因此在scroll事件处理程序中尽量保持简单的代码;
scroll事件示例:
<div id="mydiv" style="width:200px;height:200px;background-color: purple; position: absolute;top:50px;right:50px;"></div>
<div style="height: 2000px; background-color:lightgreen;"></div>
<script>
window.onscroll = function(){
var oDiv = document.getElementById("mydiv");
oDiv.style.top = document.documentElement.scrollTop + "px";
}
</script>
scroll事件也可以注册到Element元素上;如:
var oDiv = document.getElementById("mydiv");
console.log(oDiv.scrollHeight);
oDiv.addEventListener("scroll", function(event){
// console.log(event); // Event
console.log(event.target.scrollTop);
});
事件防抖(debounce)和节流(throttle):
防止事件被频繁触发;相关的事件有:mousemove、keydown、keypress、keyup、resize、scroll等;
防抖:触发高频事件后n秒内函数只执行一次,如果n秒内高频事件再次触发,则重新计算时间;如:
var timer = null; // 创建一个标记用来存放定时器的返回值
window.addEventListener("resize", function(){
if(timer){
clearTimeout(timer); // 每当resize时把之前的一个setTimeout清除
timer = null;
}
if(!timer){
timer = setTimeout(function(){ // 再创建一个新的定时器
console.log("防抖");
},500);
}
});
在事件防抖中,清除定时器的时机很关键,必须在新定时器生成之前,如果在之后,会将所有定时器都清除,目标函数一次都不执行;或:
function debounce(callback, delay){
var timeout = 0;
return function(){
var arg = arguments;
// 一直触发,就一直清除
clearTimeout(timeout);
// 直到事件不再触发,最后一个定时器没有清除,delay后就会执行定时器,
// 如此,就确保只执行一次
timeout = setTimeout(function(){
callback.apply(this, arg);
}, delay);
};
}
function fn(e){
console.log("fn" + e);
}
window.addEventListener("resize", debounce(fn, 500));
示例:输入框验证
function checkEmail(callback,delay){
var t = null;
return function(){
var arg = arguments;
clearTimeout(t);
t = setTimeout(function(){
callback.apply(this, arg);
}, delay);
}
}
function emailHander(e){
var reg = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if(!reg.test(e.target.value)){
e.target.style.backgroundColor = "red";
setTimeout(function(){
e.target.style.backgroundColor = "";
},800);
console.log("格式不正确");
}else{
e.target.style.backgroundColor = "green";
console.log("正确");
}
}
var email = document.getElementById("email");
email.addEventListener("keyup", checkEmail(emailHander,800), false);
节流:防抖是多次触发事件,目标函数只执行一次,不管触发这些事件用了多少时间;而节流是在一定时间内只会执行一次,稀释函数的执行频率,进而达到缓慢执行目标函数的目的;如:
使用setTimeout():
var timeoutId;
window.addEventListener("resize", function(event){
if(!timeoutId){
timeoutId = setTimeout(function(){
console.log("延迟执行"); // 只执行一次
clearTimeout(timeoutId);
// timeoutId = null; // 换成这一句,500ms执行一次
},500);
}
});
// 或
function resizeHandler(event){
// 先解除绑定
window.removeEventListener("resize", resizeHandler);
console.log(document.documentElement.clientWidth);
// 重新绑定
setTimeout(function(){
window.addEventListener("resize", resizeHandler);
},500);
}
window.addEventListener("resize", resizeHandler);
使用setInterval():
将事件处理程序放在setInterval()函数中,每隔一段时间,去监测一次是否发生了scroll事件,然后执行,而scroll事件只是改变scrolled的值,不会影响性能,如:
var scrolled = false;
window.addEventListener("scroll", function(){
scrolled = true;
});
setInterval(function(){
if(scrolled){
// 代码处理
console.log("scroll");
scrolled = false;
}
},500);
使用时间戳:
var startTime = new Date();
var flag = false;
var delay = 200;
window.addEventListener("resize", function(){
startTime = new Date();
if(flag === false){
flag = true;
setTimeout(resizeEnd, delay);
}
});
function resizeEnd(){
if(new Date() - startTime <= delay)
setTimeout(resizeEnd, delay);
else{
flag = false;
console.log(document.documentElement.clientWidth);
}
}
或:
function thorttle(callback, delay){
var timeout = 0;
var now = new Date() - 0;
return function(){
var arg = arguments;
var last = new Date() - 0;
clearTimeout(timeout);
if(last - now >= delay){
now = last; // 将上次执行的时间赋值给now
}else{
// 目标函数在这里执行
timeout = setTimeout(function(){
callback.apply(this, arg);
}, delay);
}
};
}
function fn(e){
console.log("节流" + e);
}
window.addEventListener("resize", thorttle(fn, 500));
使用开关:
设置一个开关,一次只能有一个触发执行,并对执行设置计时一段时间再执行,执行完毕之后再解锁;如:滚动事件;
function loadMore(){
var canRun = true;
return function(){
if(!canRun) return;
canRun = false;
setTimeout(function(){
var docHeight = document.documentElement.offsetHeight; // 文档高度
var winHeight = window.innerHeight; // 窗口高度
var scrollDistance = document.documentElement.scrollTop; // 滚动距离
// 当滚动到底部时
if(docHeight - (winHeight + scrollDistance) <= 100){
console.log("Loading...");
}
canRun = true;
},600);
}
}
window.addEventListener("scroll", loadMore());
两者比较:
节流在某个时间段内,目标函数能执行一次,限制目标函数的执行频率,不管事件触发了多少次;
防抖是多次触发事件,目标函数只执行一次,不管触发了这些事件用了多少时间;
节流函数限制目标函数的执行频率,有连续变化的效果,适用于关注变化过程的操作,可以调整目标函数执行频率使得变化更加平滑,比如动画、改变窗口时执行某些操作等,常用事件resize、scroll、mouseWheel、touchmove、mouseover等;
防抖函数适用于更关注结果的操作,不太关注操作过程,常见的事件有 input、keyup等;
FocusEvent焦点事件:
焦点事件会在页面元素获得或失去焦点时触发,或某些对象调用了focus()和blur()方法也会触发该事件;利用这些事件并与document.hasFocus()方法及document.activeElement属性配合,可以知晓用户在页面上的行踪;
有以下6个焦点事件:
- blur:在元素失去焦点时触发,该事件不会冒泡;
- focus:在元素获得焦点时触发,该事件不会冒泡;
- DOMFocusIn:在元素获得焦点时触发,该事件与HTML事件focus等价,但它冒泡;DOM3级事件废弃了它,应使用focusin;FF及低版本的IE不支持;
- DOMFocusOut:在元素失去焦点时触发,该事件是HTML事件blur等价,但它冒泡;DOM3级事件废弃了它,应使用focusout;FF及低版本的IE不支持;
- focusin:在元素获得焦点时触发,该事件与HTML事件focus等价,但它冒泡;
- focusout:在元素失去焦点时触发,该事件是HTML事件blur等价,但它冒泡;
要确定浏览器是否支持这些事件,可以检测:
var isSupported = document.implementation.hasFeature("FocusEvent", "3.0");
可以获得焦点事件的元素一般指的是window或表单控件或是超链接或是可编辑元素,称为focusable元素;但在IE中普通元素也可以获得焦点;
window.onblur = function(){ document.title = "你离开了";};
window.onfocus = function(){ document.title = "你来了";};
var oDiv = document.getElementById("mydiv");
oDiv.contentEditable = true;
// oDiv.tabIndex = 1; // 或者添加tabIndex属性也可以
oDiv.focus();
console.log(document.activeElement);
oDiv.addEventListener("focus", function(event){
console.log(event.target.id);
});
这一类事件中最主要的两个是focus和blur,它们都是Javascript早期就得到所有浏览器都支持的事件,这两个事件的最大问题是它们不冒泡,因此,才出现了IE的focusin和focusout与Opera的DOMFocusIn和DOMFocusOut这两对事件,后来IE的方式被DOM3级事件纳为标准方式;
var btn = document.getElementById("btn");
btn.addEventListener("focus", function(event){
console.log(event); // FocusEvent
});
FocusEvent类:
表示和焦点相关的事件类,其继承自UIEvent类;
其自身只添加了一个属性relatedTarget,代表此次事件的相关目标,但在实用中,例如切换浏览器tab标签时,为了安全起见,所有浏览器都会返回null;
当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件:
blur在失去焦点的元素上触发、focusout在失去焦点的元素上触发、DOMFocusOut在失去焦点的元素上触发、focus在获得焦点的元素上触发、focusin在获得焦点的元素上触发、DOMFocusIn在获得焦点的元素上触发;但IE不遵循此顺序;
function handler(event){
console.log(event.target.id + ":" + event.type);
}
var btn = document.getElementById("btn");
btn.addEventListener("DOMFocusIn", handler, false);
btn.addEventListener("DOMFocusOut", handler, false);
btn.addEventListener("focus", handler, false);
btn.addEventListener("blur", handler, false);
btn.addEventListener("focusin", handler, false);
btn.addEventListener("focusout", handler, false);
btn.focus();
var txt = document.getElementById("txt");
txt.addEventListener("focus", handler, false);
txt.addEventListener("blur", handler, false);
txt.addEventListener("DOMFocusIn", handler, false);
txt.addEventListener("DOMFocusOut", handler, false);
txt.addEventListener("focusin", handler, false);
txt.addEventListener("focusout", handler, false);
其中,blur、DOMFocusOut和focusout的事件目标是失去焦点的元素,而focus、DOMFocusIn和focusin的事件目标是获得焦点的元素;
另外,如果同时注册了focusin和DOMFocusIn或focusout和DOMFocusOut,在IE中只会触发focusin和focusout;
另外,除了focus和blur事件,其他事件只能通过DOM2级事件添加,如:
var btn = document.getElementById("btn");
btn.onfocusin = function(event){
console.log(event); // 不会触发
};
btn.onDOMFocusIn = function(event){
console.log(event); // 不会触发,IE会触发
};
onfocusin和onfocusout事件,在HTML事件处理中,除FF,其它都支持;DOMFocusIn和DOMFocusOut,在HTML事件处理中,都不支持;
小应用:改变文本框样式,如:
<style>
.focusInput{border:1px solid purple;outline: none; background-color: rgba(0, 0, 0, .6);}
</style>
<script>
function focusInput(focusClass){
var elements = document.getElementsByTagName("input");
for(var i=0,len=elements.length; i<len; i++){
var elt = elements[i];
if(elt.type == "text"){
elt.onfocus = function(){
this.className = focusClass;
};
elt.onblur = function(){
this.className = "";
}
}
}
}
window.onload = function(){
focusInput('focusInput');
}
</script>
focusin和focusout事件是冒泡的,因此可以使用事件代理,如:
<form id="myform" action="demo.jsp">
<input type="text" id="firstname" value="firstname" />
<input type="text" id="lastname" value="lastname" />
</form>
<script>
var myform = document.getElementById("myform");
myform.addEventListener("focusin", function(event){
event.target.className = "focused";
});
myform.addEventListener("focusout", function(event){
event.target.className = "";
});
</script>
示例:验证数据,如:
<style>
.invalid{border-color:red;}
#error{color:red}
</style>
<p>邮箱:<input type="email" id="email" /></p>
<div id="error"></div>
<script>
var email = document.getElementById("email");
var error = document.getElementById("error");
email.addEventListener("blur", function(event){
if(!event.target.value.includes("@")){
event.target.classList.add("invalid");
error.innerHTML = "请输入正确的邮箱";
}
});
email.addEventListener("focus", function(event){
if(this.classList.contains("invalid")){
this.classList.remove("invalid");
error.innerHTML = "";
}
});
</script>
或者使用focus()和blur()方法,如:
<style>
.error{background-color: red !important;}
</style>
<p>邮箱:<input type="email" id="email" /></p>
<script>
var email = document.getElementById("email");
email.addEventListener("blur", function(event){
if(!event.target.value.includes("@")){
event.target.classList.add("error");
event.target.focus();
}else
event.target.classList.remove("error");
});
</script>
示例:一个HTML编辑器;
<style>
.container,.editor{width:400px; height: 150px; display: block;}
.container{padding: 2px; border:1px solid;}
.editor{padding: 0; border:2px solid blue;}
.editor:focus{outline: none;}
</style>
<div id="container" class="container">
<h1>Web前端开发</h1>
</div>
<script>
var area = null;
var container = document.getElementById("container");
container.addEventListener("click", function(event){
editStart();
},false);
function editStart(){
area = document.createElement("textarea");
area.className = "editor";
area.value = container.innerHTML;
area.addEventListener("keydown", function(event){
if(event.keyCode == 13)
this.blur();
},false);
area.addEventListener("blur", function(event){
editEnd();
});
container.replaceWith(area);
area.focus();
}
function editEnd(){
container.innerHTML = area.value;
area.replaceWith(container);
}
</script>
当用户按下Enter键或失去焦点时,<textarea>变回<div>,其内容在<div>中变为HTML;
猜你喜欢
- 2024-10-18 前端反向代理(前端反向代理怎么配置)
- 2024-10-18 JavaScript 九种跨域方式实现原理
- 2024-10-18 Proxy 来代理 JavaScript 里的类(js中proxy)
- 2024-10-18 octokit.js:2023每个前端都值得学习的通用SDK!
- 2024-10-18 一面 2:JS-Web-API 知识点与高频考题解析
- 2024-10-18 使用reveal.js制作精美的网页版PPT
- 2024-10-18 es6中的代理-Proxy(es proxy)
- 2024-10-18 事件——《JS高级程序设计》(javascript高级程序设计 javascript权威指南)
- 2024-10-18 「JavaScript 从入门到精通」18.WebApi介绍
- 2024-10-18 day7:前端面试题(js)(前端面试题2021及答案js)
- 最近发表
- 标签列表
-
- cmd/c (64)
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- sqlset (64)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- linux删除一个文件夹 (65)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)