25 【进度事件和表单事件】
25 【进度事件和表单事件】
1.文档的加载
浏览器在加载一个页面时,是按照自上向下的顺序加载的,加载一行执行一行。 如果将js代码编写到页面的上边,当代码执行时,页面中的DOM对象还没有加载, 此时将会无法正常获取到DOM对象,导致DOM操作失败。
解决方式一: 可以将js
代码编写到body的下边
<body>
<button id="btn">按钮</button>
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
};
</script>
</body>
解决方式二: 将js
代码编写到window.onload = function(){}
中 window.onload
对应的回调函数会在整个页面加载完毕以后才执行, 所以可以确保代码执行时,DOM对象已经加载完毕了
<script>
window.onload = function(){
var btn = document.getElementById("btn");
btn.onclick = function(){
};
};
</script>
2.进度事件的种类
进度事件用来描述资源加载的进度,主要由 AJAX 请求、<img>
、<audio>
、<video>
、<style>
、<link>
等外部资源的加载触发,继承了ProgressEvent
接口。它主要包含以下几种事件。
abort
:外部资源中止加载时(比如用户取消)触发。如果发生错误导致中止,不会触发该事件。error
:由于错误导致外部资源无法加载时触发。load
:外部资源加载成功时触发。loadstart
:外部资源开始加载时触发。loadend
:外部资源停止加载时触发,发生顺序排在error
、abort
、load
等事件的后面。progress
:外部资源加载过程中不断触发。timeout
:加载超时时触发。
注意,除了资源下载,文件上传也存在这些事件。
下面是一个例子。
image.addEventListener('load', function (event) {
image.classList.add('finished');
});
image.addEventListener('error', function (event) {
image.style.display = 'none';
});
上面代码在图片元素加载完成后,为图片元素添加一个finished
的 Class。如果加载失败,就把图片元素的样式设置为不显示。
有时候,图片加载会在脚本运行之前就完成,尤其是当脚本放置在网页底部的时候,因此有可能load
和error
事件的监听函数根本不会执行。所以,比较可靠的方式,是用complete
属性先判断一下是否加载完成。
function loaded() {
// ...
}
if (image.complete) {
loaded();
} else {
image.addEventListener('load', loaded);
}
由于 DOM 的元素节点没有提供是否加载错误的属性,所以error
事件的监听函数最好放在<img>
元素的 HTML 代码中,这样才能保证发生加载错误时百分之百会执行。
<img src="/wrong/url" onerror="this.style.display='none';" />
loadend
事件的监听函数,可以用来取代abort
事件、load
事件、error
事件的监听函数,因为它总是在这些事件之后发生。
req.addEventListener('loadend', loadEnd, false);
function loadEnd(e) {
console.log('传输结束,成功失败未知');
}
loadend
事件本身不提供关于进度结束的原因,但可以用它来做所有加载结束场景都需要做的一些操作。
另外,error
事件有一个特殊的性质,就是不会冒泡。所以,子元素的error
事件,不会触发父元素的error
事件监听函数。
3.表单事件的种类
3.1 input 事件
input
事件当<input>
、<select>
、<textarea>
的值发生变化时触发。对于复选框(<input type=checkbox>
)或单选框(<input type=radio>
),用户改变选项时,也会触发这个事件。另外,对于打开contenteditable
属性的元素,只要值发生变化,也会触发input
事件。
input
事件的一个特点,就是会连续触发,比如用户每按下一次按键,就会触发一次input
事件。
input
事件对象继承了InputEvent
接口。
该事件跟change
事件很像,不同之处在于input
事件在元素的值发生变化后立即发生,而change
在元素失去焦点时发生,而内容此时可能已经变化多次。也就是说,如果有连续变化,input
事件会触发多次,而change
事件只在失去焦点时触发一次。
下面是<select>
元素的例子。
/* HTML 代码如下
<select id="mySelect">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
*/
function inputHandler(e) {
console.log(e.target.value)
}
var mySelect = document.querySelector('#mySelect');
mySelect.addEventListener('input', inputHandler);
上面代码中,改变下拉框选项时,会触发input
事件,从而执行回调函数inputHandler
。
3.2 select 事件
select
事件当在<input>
、<textarea>
里面选中文本时触发。
// HTML 代码如下
// <input id="test" type="text" value="Select me!" />
var elem = document.getElementById('test');
elem.addEventListener('select', function (e) {
console.log(e.type); // "select"
}, false);
选中的文本可以通过event.target
元素的selectionDirection
、selectionEnd
、selectionStart
和value
属性拿到。
3.3 change 事件
change
事件当<input>
、<select>
、<textarea>
的值发生变化时触发。它与input
事件的最大不同,就是不会连续触发,只有当全部修改完成时才会触发,另一方面input
事件必然伴随change
事件。具体来说,分成以下几种情况。
- 激活单选框(radio)或复选框(checkbox)时触发。
- 用户提交时触发。比如,从下列列表(select)完成选择,在日期或文件输入框完成选择。
- 当文本框或
<textarea>
元素的值发生改变,并且丧失焦点时触发。
下面是一个例子。
// HTML 代码如下
// <select size="1" onchange="changeEventHandler(event);">
// <option>chocolate</option>
// <option>strawberry</option>
// <option>vanilla</option>
// </select>
function changeEventHandler(event) {
console.log(event.target.value);
}
如果比较一下上面input
事件的例子,你会发现对于<select>
元素来说,input
和change
事件基本是等价的。
3.4 invalid 事件
用户提交表单时,如果表单元素的值不满足校验条件,就会触发invalid
事件。
<form>
<input type="text" required oninvalid="console.log('invalid input')" />
<button type="submit">提交</button>
</form>
上面代码中,输入框是必填的。如果不填,用户点击按钮提交时,就会触发输入框的invalid
事件,导致提交被取消。
3.5 reset 事件,submit 事件
这两个事件发生在表单对象<form>
上,而不是发生在表单的成员上。
reset
事件当表单重置(所有表单成员变回默认值)时触发。
submit
事件当表单数据向服务器提交时触发。注意,submit
事件的发生对象是<form>
元素,而不是<button>
元素,因为提交的是表单,而不是按钮。