一 简述 JavaScript 及其在浏览器中的地位
(一) 浏览器主要构成
虽然不同浏览器之间存在差异(如 Google Chrome,Firefox,Safari 和 IE 等), 但单从浏览器构成来说, 大同小异, 大致可归结为如下几类:
1.User Interface(用户界面): 所谓用户界面, 就是通过浏览器渲染出来, 让用户可见的界面, 如地址栏, 书签菜单栏等;
2.Browser Engine(浏览器引擎): 主要操作呈现的引擎界面;
3.Rendering Engine(渲染引擎): 负责渲染响应请求内容, 如负责解析 html 和 CSS;
4.Networking(网络): 负责网络呼叫处理, 如 http 请求;
5.JS Interpreter(JavaScript 解释器): 负责解析和执行 JavaScript 代码;
6.UI Back(UI 后端): 用于绘制组合框和窗口等基本组建;
7.Data Persistence(数据持久): 通常用来持久化存储少量数据, 如 cookie 等;
(二)JavaScript 在浏览器中的地位
如上图, JavaScript 处于浏览器中的核心位置, 负责解释和执行 JS 脚本, 内置于浏览器中, 通过浏览器提供的 API 来访问.
(三)JavaScript 构成
关于 JavaScript 的构成, 大致可归结为三个部分: ECMAScript,DOM 和 BOM.
1.ECMAScript 是对 JS 的约束和规范, 如基本语法结构;
2.DOM 就是文档对象模型, 是交互的资源, 如 HTML 文档;
3.BOM 主要是对浏览器本身描述, 如浏览器名称, 版本号等;
(四)JavaScript 基本执行原理
这里不深入谈及 JavaScript 的深层次执行原理, 只是大致描述一下, 关于更深层次的, 在后续文章推出, 与大家分享.
JS 的执行原理, 用一句话来归结之: 单线程异步. 下图很好地表述该过程.
所有的执行函数统一放在队列中进行排队.
二 事件流
所谓事件流, 也可理解为事件的轨迹. 一般地, 将事件流分为三个阶段: 捕获阶段, 目标阶段和冒泡阶段.
下图为三个阶段的大致流程图.
(一)捕获阶段
捕获阶段处于事件流的第一阶段, 该阶段的主要作用是捕获截取事件. 在 DOM 中, 该阶段始于 Document, 结束于 body(当然, 在现在的很
多高版本浏览器中, 该过程结束于目标元素, 只不过不执行目标元素而已, 这也体现了目标元素具有双重范围).
(二)目标阶段
目标阶段处于事件流的第二阶段, 该阶段的主要作用是执行绑定事件. 一般地, 该阶段具有双重范围, 即捕获阶段的结束, 冒泡阶段的开始;
(三)冒泡阶段
冒泡阶段处于事件流的第三阶段, 该阶段的主要作用是将目标元素绑定事件执行的结果返回给浏览器, 处理不同浏览器之间的差异, 主要在该阶段完成.
(四)三阶段在 Dom 中的完整流程
三 事件处理程序
JS 事件处理程序按照种类来划分, 大致可分为五大类: HTML 事件处理程序, DOM0 级事件处理程序, DOM2 级事件处理程序, IE 事件处理程序和跨浏览器事件处理程序.
尤其是 DOM0,DOM2 和 IE 事件处理程序, 利用它们之间的差异化有效地解决浏览器差异问题, 从而实现跨浏览器的兼容性问题.
(一)HTML 事件处理程序
所谓 HTML 事件处理程序, 就是在 dom 结构中嵌套 JS 代码. 在 HTML 中, 元素支持的所有事件, 都可以使用与相应事件处理程序同名的 HTML 特性来指定, 这个特性的值应该是能执行的 JS 代码.
如点击事件.
- <body>
- <!--html 事件处理程序 -->
- <input type="button" value="请点击" onclick="alert('测试 html 事件处理程序!!')"/>
- </body>
当然, 一般不采用如上方法, 常规的做法是, 将 JS 代码定义在目标元素外部. 因此, 与如上相同功能的定义为:
目标元素
- <body>
- <!--html 事件处理程序 -->
- <input type="button" value="请点击" onclick="HtmlEventHandlerProc()"/>
- </body>
外部 JS
- <script>
- function HtmlEventHandlerProc() {
- alert('测试 html 事件处理程序!!');
- }
- </script>
- Tip:
1. 事件处理程序中的代码, 能够访问全局作用域中的任何变量;
2. 每个 function()存在一个局部变量, 即事件对象 event, 通过 event 变量, 可以直接访问事件对象.
- <body>
- <input type="button" value="请点击" onclick="alert(event.type)"/>
- </body>
执行结果
3. 在函数内部, this 值等于事件的目标元素.
- <body>
- <input type="button" value="请点击" onclick="alert(this.value)"/>
- </body>
执行结果
this 具有扩展作用域的功能, 其功能相当于
- function myfunction() {
- with (document) {
- with (this) {
- //add your logic
- }
- }
- }
如果当前元素是一个表单元素, 则作用域还会包含访问表单元素 (父元素) 的入口.
- function myfunction() {
- with (document) {
- with (this.form) {
- with (this) {
- //add your logic
- }
- }
- }
- }
这样做, 有什么本质意义呢? 当然是想让事件处理程序更快捷访问表单其他字段(无需引用表单元素就能访问)
- <form>
- <input type="text" name="userName" value="Alan_beijing" />
- <input type="button" value="测试表单元素" onclick="alert(userName.value)" />
- </form>
执行结果
4.HTML 事件处理程序存在哪些缺点?
缺点一: 时差问题
缺点二: 扩展的作用域链在不同浏览器中会导致不同结果
缺点三: HTML 代码与 JS 代码高度耦合
(二)DOM0 级事件处理程序
DOM0 级事件很好地解决了 HTML 和 JS 代码强耦合的问题.
1. 为元素绑定事件
- var btn = document.getElementById('myBtn');
- btn.onclick = function () {
- alert('Clicked');
- }
2. 为元素解除事件
btn.onclick = null;
(三)DOM2 级事件处理程序
DOM2 级事件定义了两个方法来为目标元素绑定事件处理程序 (addEventListener()) 和解除事件处理程序(removeEventListener()), 所有节点中都包含这两个方法, 并且他们都接收三个参数:
要处理的事件名, 事件处理程序和一个布尔值(true 表示是在捕获阶段进行, false 表示在冒泡阶段进行)
1. 为事件添加 click 事件处理程序(冒泡阶段进行)
- var btn = document.getElementById("myBtn");
- btn.addEventListener("click", function () {
- alert(this.id);
- }, false);
执行结果:
2. 添加多个事件处理程序
- var btn = document.getElementById("myBtn");
- btn.addEventListener("click", function () {
- alert(this.id);
- }, false);
- btn.addEventListener("click", function myfunction() {
- alert("添加的第二个事件处理程序");
- }, false);
执行结果:
3 移除事件处理程序
通过 addEventListener()添加的事件处理陈旭只能使用 removeEventListener()来移除, 移除时, 传入的参数与添加的程序时使用的参数相同
(这意味着匿名函数不能通过 removeEventListener()来删除)
匿名函数不能删除
- var btn = document.getElementById("myBtn");
- btn.addEventListener("click", function () {
- alert(this.id);
- }, false);
- // 不能删除, 因为是匿名函数
- btn.removeEventListener("click", function () {
- alert(this.id);
- }, false);
非匿名函数能删除
- var btn = document.getElementById("myBtn");
- var handler = function () {
- alert(this.id);
- };
- btn.addEventListener("click", handler, false);
- // 删除事件处理程序
- btn.removeEventListener("click", handler, false);
(四)IE 事件处理程序
IE 提供了两个方法来绑定和卸载事件处理程序, attachEvent()和 detachEvent(), 这两个方法均接收两个参数, 即事件处理程序名称和事件处理程
序函数, 并且在冒泡阶段添加(IE8 及更早版本只支持冒泡)
1. 为目标按钮添加绑定事件
- var btn = document.getElementById("myBtn");
- btn.attachEvent("onclick", function () {
- alert("IE 事件处理程序!!");
- });
2. 为目标按钮添加绑定事件
多个执行绑定事件的结果是倒过来的.
- var btn = document.getElementById("myBtn");
- btn.attachEvent("onclick", function () {
- alert("IE 事件处理程序 1!!");
- });
- btn.attachEvent("onclick", function () {
- alert("IE 事件处理程序 2!!");
- });
3. 为目标元素移除事件处理程序
注意: 匿名事件处理程序是不能够移除的
- var btn = document.getElementById("myBtn");
- var handler = function () {
- alert("IE 事件处理程序");
- };
- // 绑定事件
- btn.attach("onclick", handler);
- // 移除事件
- btn.detachEvent("onclick", handler);
(五)跨浏览器事件处理程序
在跨浏览器中, 无非就是三种选择: DOM0 级选择(不常用, 基本被废弃),DOM2 级选择和 IE 选择(不常用, IE8 及以下版本).
- // 定义 EventUtil
- var EventUtil = {
- addHandler: function (element, type, handler) {
- if (element.addEventListener) {
- element.addEventListener(type, handler, false);
- } else if (element.attachEvent) {
- element.attachEvent("on" + type, handler);
- }
- },
- removeHandler: function (element, type, handler) {
- if (element.removeEventListener) {
- element.removeEventListener(type, handler, false);
- } else if (element.detachEvent) {
- element.detachEvent("on" + type, handler);
- } else {
- element["on" + type] = null;
- }
- }
- }
- // 调用
- var btn = document.getElementById("myBtn");
- var handler = function () {
- alert("事件处理程序跨浏览器!!");
- };
- // 绑定事件处理程序
- EventUtil.addHandler(btn, "click", handler);
- // 移除事件处理程序
- EventUtil.removeHandler(btn, "click", handler);
四 事件类型
内容相对比较简单, 这里就暂且列举主要内容, 若有需要, 会在下篇文章论述.
五 事件对象及其事件委托
介于文章篇幅有限, 暂且列举主要内容, 代码部分将在下篇文章论述.
来源: https://www.cnblogs.com/wangjiming/p/9983023.html