JavaScript__事件的练习题

一、选择题
1.不属于表单事件的是( )
A. submit
B. reset
C. keydown
D. focus

2.当文档和其所有外部资源完全加载并显示给用户时就会触发的事件是( )
A.scroll
B. unload
C. focus
D. load

3.用户每次移动或拖动鼠标时,会触发哪个事件?( )
A. mousedown
B. mouseup
C. mouseover
D. mousemout

4.指定按下或释放的键是哪个的属性是?( )
A. altKey
B. metaKey
C. keyCode
D. shiftKey

5.指定按下或释放的键是哪个的属性是?( )
A. altKey
B. metaKey
C. keyCode
D. shiftKey

6.关于mouseenter事件的表述,正确的是?( )
A. 当用户按下或释放鼠标按键时
B. button属性指定了按下的鼠标键是哪个
C. mouseenter会冒饱直到文档最顶层
D. 指明当时是否有任何辅助键按下

7.事件对象的relatedTarget属性,表示?( )
A. 可以探测和响应鼠标的拖动
B. 描述当事件发生时鼠标的位置和按键状态
C. 指定了鼠标在窗口坐标中的位置
D. 指明这个过程涉及的其他元素

8.gesturechange表示?( )
A. 当手势开始时
B. 手势结束时
C. 跟踪手势过程事件
D. 两个手指之间当前距离和初始距离的比值

9.关于addEventListener,表述错误的是?( )
A. 第一个参数是注册处理程序的事件类型,这个事件类型是字符串

B. 事件类型必须包括用于设置事件处理程序属性的前缀“on”
C. 第二个参数是当指定类型的事件发生时应该调用的函数

D. 最后一个参数是捕获事件处理程序,并在事件不同的调度阶段调用

10.关于attachEvent()和detachEvent()方法,表述错误的是?( )
A. attachEvent()和detachEvent()要求只有两个参数:事件类型和处理程序函数

B. IE方法的第一个参数使用了带“on”前缀的事件处理程序属性名
C. attachEvent()允许相同的事件处理程序函数注册多次

D. attachEvent()和detachEvent()方法支持所有主流的浏览器

11.关于事件传播,表述正确的是?( )
A. focus不会冒泡
B. blur会冒泡
C. 大部分事件会冒泡到DOM树根
D. 事件一直冒泡,到达document对象

12.如何事件取消?( )
A. 通过preventDefault()方法
B. returnValue属性设置为true
C. 使用return false
D. 设置cancal 为true

二、综合题
1.在指定的事件目标上注册用于处理指定类型事件的指定处理程序函数
/*
*
*确保处理程序一直作为事件目标的方法调用
*/
function addEvent(target, type,Handler) {
if (target.addEventListener)
target.addEventListener(type,Handler, false);
else
target.attachEvent(“on” + type,
function(event) {
//把处理程序作为事件目标的方法调用,
//传递事件对象
returnHandler.call(target, event);
});
}

2.取消事件的默认操作
function cancelHandler(event) {
var event = event || window.event; // 针对 IE
//现在取消事件相关的默认行为
if (event.preventDefault) event.preventDefault(); // 标准技术
if (event.returnValue) event.returnValue = false; // IE
return false; //用于处理使用对象属性注册的处理程序
}

3.当文档准备就绪时调用函数
/*
* 传递函数给whenReady(),当文档解析完毕且为操作淮备就绪时,
*函数将作为文档对象的方法调用
* DOMContentLoaded,readystatechange或load事件发生时会触发注册函数
*一旦文档淮备就绪,所有函数都将被调用,任何传递给whenReady()的函数都将立即调用
*/
var whenReady = (function() { // 这个函数返回whenReady()函数
var funcs = []; // 当获得事件时,要运行的函数
var ready = false; // 当触发事件处理程序时,切换到true
// 当文档准备就绪时,调用事件处理程序
functionHandler(e) {
// 如果已经运行过一次,只需要返回
if (ready) return;
//如果发生readystatechange事件,
//但其状态不是“complete”的话,那么文档尚未淮备好
if (e.type === “readystatechange” && document.readyState !== “complete”)
return;

//运行所有注册函数
//注意每次都要计算funcs.length,
//以防这些函数的调用可能会导致注册更多的函数
for(var i = 0; i < funcs.length; i++)
funcs[i].call(document);
// 现在设置ready标识为true,并移除所有函数
ready = true;
funcs = null;
}
// 为接收到的任何事件注册处理程序
if (document.addEventListener) {
document.addEventListener(“DOMContentLoaded”,Handler, false);
document.addEventListener(“readystatechange”,Handler, false);
window.addEventListener(“load”,Handler, false);
}
else if (document.attachEvent) {
document.attachEvent(“onreadystatechange”,Handler);
window.attachEvent(“onload”,Handler);
}
// 返回whenReady()函数
return function whenReady(f) {
if (ready) f.call(document); // 若准备完毕,只需要运行它
else funcs.push(f); // 否则,加入队列等候
}
}());

4.拖动文档元素
/**
* Drag.js: 拖动绝对定位的HTML元素
*
*这个模块定义了一个drag()函数,它用于mousedown事件处理程序的调用
*随后的mousemove事件将移动指定元素,mouseup事件将终止拖动
* 这些实现能同标准和IE两种事件模型一起工作
* 它需要用到本书其他地方介绍的getScrollOffsets()方法
*
* 参数:
*
*elementToDrag:接收mousedown事件的元素或某些包含元素
*它必须是绝对定位的元素
*它的style.left和style.top值将随着用户的拖动而改变
* event: mousedown事件对象
**/
function drag(elementToDrag, event) {
// 初始鼠标位置,转换为文档坐标
var scroll = getScrollOffsets(); // 来自其他地方的工具函数
var startX = event.clientX + scroll.x;
var startY = event.clientY + scroll.y;
//在文档坐标下,待拖动元素的初始位置
//因为elementToDrag是绝对定位的,
//所以我们可以假设它的。ffsetParent就是文档的body元素
var origX = elementToDrag.offsetLeft;
var origY = elementToDrag.offsetTop;
//计算mousedown事件和元素左上角之间的距离
//我们将它另存为鼠标移动的距离
var deltaX = startX – origX;
var deltaY = startY – origY;
//注册用于响应接着mousedown事件发生的mousemove和mouseup事件的事件处理程序
if (document.addEventListener) { //标准事件模型
//在document对象上注册捕获事件处理程序
document.addEventListener(“mousemove”, moveHandler, true);
document.addEventListener(“mouseup”, upHandler, true);
}
else if (document.attachEvent) { //用于IE5-8的IE事件模型
//在IE事件模型中,
//捕获事件是通过调用元素上的setCapture()捕获它们
elementToDrag.setCapture();
elementToDrag.attachEvent(“onmousemove”, moveHandler);
elementToDrag.attachEvent(“onmouseup”, upHandler);
//作为mouseup事件看待鼠标捕获的丢失
elementToDrag.attachEvent(“onlosecapture”, upHandler);
}
//我们处理了这个事件,不让任何其他元素看到它
if (event.stopPropagation) event.stopPropagation(); //标准模型
else event.cancelBubble = true; // IE
//现在阻止任何默认操作
if (event.preventDefault) event.preventDefault(); //标准模型
else event.returnValue = false; // IE
/**
*当元素正在被拖动时,这就是捕获mousemove事件的处理程序
*它用于移动这个元素
**/
function moveHandler(e) {
if (!e) e = window.event; //IE事件模型
//移动这个元素到当前鼠标位置,
//通过滚动条的位置和初始单击的偏移量来调整
var scroll = getScrollOffsets();
elementToDrag.style.left = (e.clientX + scroll.x – deltaX) + “px”;
elementToDrag.style.top = (e.clientY + scroll.y – deltaY) + “px”;
//同时不让任何其他元素看到这个事件
if (e.stopPropagation) e.stopPropagation(); // 标准
else e.cancelBubble = true; // IE
}
/**
*这是捕获在拖动结束时发生的最终mouseup事件的处理程序
**/
function upHandler(e) {
if (!e) e = window.event; //IE事件模型
// Unregister the capturing eventHandlers.
if (document.removeEventListener) { // DOM事件模型
document.removeEventListener(“mouseup”, upHandler, true);
document.removeEventListener(“mousemove”, moveHandler, true);
}
else if (document.detachEvent) { // IE 5+事件模型
elementToDrag.detachEvent(“onlosecapture”, upHandler);
elementToDrag.detachEvent(“onmouseup”, upHandler);
elementToDrag.detachEvent(“onmousemove”, moveHandler);
elementToDrag.releaseCapture();
}
// 并且不让事件进一步传播
if (e.stopPropagation) e.stopPropagation(); // 标准模型
else e.cancelBubble = true; // IE
}
}

5.处理鼠标滚轮事件
//把内容元素装入到一个指定大小(最小是50 x 50)的窗体或视口内
//可选参数contentX和contentY指定内容相对于窗体的初始偏移量
//(如果指定,它们必须<=0)
//这个窗体有mousewheel事件处理程序,
//它允许用户平移元素和缩放窗体
function enclose(content, framewidth, frameheight, contentX, contentY) {
// 这些参数不仅仅是初始值,
// 它们保存当前状态,能被mousewheel处理程序使用和修改
framewidth = Math.max(framewidth, 50);
frameheight = Math.max(frameheight, 50);
contentX = Math.min(contentX, 0) || 0;
contentY = Math.min(contentY, 0) || 0;
// 创建frame元素,且设置CSS类名和样式
var frame = document.createElement(“div”);
frame.className = “enclosure”; // 这样我们能在样式表中定义样式
frame.style.width = framewidth + “px”; // 设置frame的尺寸
frame.style.height = frameheight + “px”;
frame.style.overflow = “hidden”; // 没有滚动条,不能溢出
frame.style.boxSizing = “border-box”; // border-box简化了调整frame大小的计算
frame.style.webkitBoxSizing = “border-box”;
frame.style.MozBoxSizing = “border-box”;
// 把frame放人文档中,并把内容移人frame中
content.parentNode.insertBefore(frame, content);
frame.appendChild(content);
// 确定元素相对于frame的位置
content.style.position = “relative”;
content.style.left = contentX + “px”;
content.style.top = contentY + “px”;
// 我们将需要针对下面一些特定浏览器怪癖进行处理
var isMacWebkit = (navigator.userAgent.indexOf(“Macintosh”) !== -1 &&
navigator.userAgent.indexOf(“Web Kit”) !== -1);
var isFirefox = (navigator.userAgent.indexOf(“Gecko”) !== -1);
// 注册mousewheel事件处理程序
frame.onwheel = wheelHandler; // 未来浏览器
frame.onmousewheel = wheelHandler; // 大多数当前浏览器
if (isFirefox) // 仅Firefox
frame.addEventListener(“DOMMouseScroll”, wheelHandler, false);
function wheelHandler(event) {
var e = event || window.event; // 标准或IE事件对象
//查找wheel事件对象、mousewheel事件对象(包括2D和1D形式)
//和Firefox的DOMMouseScroll事件对象的属性,
//从事件对象中提取旋转量
//绽放delta以便一次鼠标滚轮“单击”相对于屏幕的缩放增量是30像素
//如果未来浏览器在同一事件上同时触发“wheel”和“mousewheel”,
//这里最终会重复计算,
//所以,希望取消wheel事件将阻止mousewheel事件的产生
var deltaX = e.deltaX*-30 || //wheel事件
e.wheelDeltaX/4 || // mousewheel
0; // 属性未定义
var deltaY = e.deltaY*-30 || // wheel事件
e.wheelDeltaY/4 || // Webkit中的mousewheel事件
(e.wheelDeltaY===undefined && // 如果没有2D属性,
e.wheelDelta/4) || // 那么就用1D的滚轮属性
e.detail*-10 || //Firefox的DOMMouseScroll事件
0; // 属性未定义
//在大多数浏览器中,每次鼠标滚轮单击对应的delta是120
//但是,在Mac中,鼠标滚轮似乎对速度更敏感,
//其delta值通常要大120倍,使用Apple鼠标至少如此
//使用浏览器测试解决这个问题
if (isMacWebkit) {
deltaX /= 30;
deltaY /= 30;
}
//如果在Firefox(未来版本)中得到mousewheel或wheel事件,
//那么就不再需要DOMMouseScroll
if (isFirefox && e.type !== “DOMMouseScroll”)
frame.removeEventListener(“DOMMouseScroll”, wheelHandler, false);
// 获取内容元素的当前尺寸
var contentbox = content.getBoundingClientRect();
var contentwidth = contentbox.right – contentbox.left;
var contentheight = contentbox.bottom – contentbox.top;
if (e.altKey) { // 如果按下Alt键,就可以调整frame大小
if (deltaX) {
framewidth -= deltaX; // 新宽度,但不能比内容大
framewidth = Math.min(framwidth, contentwidth);
framewidth = Math.max(framewidth,50); // 且也不能比50小.
frame.style.width = framewidth + “px”; // 在frame上设置它
}
if (deltaY) {
frameheight -= deltaY; // 同样的操作对frame的高度做一遍
frameheight = Math.min(frameheight, contentheight);
frameheight = Math.max(frameheight-deltaY, 50);
frame.style.height = frameheight + “px”;
}
}
else { // 没有按下Alt辅助键,就可以平移frame中的内容
if (deltaX) {
// 不能再滚动了
var minoffset = Math.min(framewidth-contentwidth, 0);
// 把deltaX添加到contentX中,但不能小于minoffset
contentX = Math.max(contentX + deltaX, minoffset);
contentX = Math.min(contentX, 0); // 或比0大
content.style.left = contentX + “px”; // 设置新的偏移量
}
if (deltaY) {
var minoffset = Math.min(frameheight – contentheight, 0);
// 把deltaY添加到contentY,但不能小于minoffset
contentY = Math.max(contentY + delta Y, minoffset);
contentY = Math.min(contentY, 0); //或比0大
content.style.top = contentY + “px”; //设置新的偏移量
}
}
//不让这个事件冒泡,阻止任何默认操作
//这会阻止浏览器使用mousewheel事件滚动文档
//希望对于相同的鼠标滚动,
//调用、heel事件上的preventDefault()也能阻止mousewheel事件的产生
if (e.preventDefault) e.preventDefault();
if (e.stopPropagation) e.stopPropagation();
e.cancelBubble = true; // IE事件
e.returnValue = false; // IE事件
return false;
}
}

6.作为拖放目标和拖放源的列表
/*
* DnD AP工相当复杂,且浏览器也不完全兼容
*这个例子基本正确,但每个浏览器会有一点不同,每个似乎都有自身独有的bug
*这些代码不会尝试浏览器特有的解决方案
*/
whenReady(function() { // 当文档准备就绪时运行这个函数
// 查找所有的<u1 class=’dnd’>元素,并对其调用dnd()函数
var lists = document.getElementsByTagName(“ul”);
var regexp = /\bdnd\b/;
for(var i = 0; i < lists.length; i++)
if (regexp.test(lists[i].className)) dnd(lists[i]);
// 为列表元素添加拖放事件处理程序
function dnd(list) {
var original_class = list.className; // 保存原始CSS类
var entered = 0; // 跟踪进入和离开
//当拖放对象首次进入列表时调用这个处理程序
//它会检查拖放对象包含的数据格式它是否能处理
//如果能,它返回false来表示有兴趣放置
//在这种情况下,它会高亮拖放目标,让用户知道该兴趣
list.ondragenter = function(e) {
e = e || window.event; // 标淮或IE事件
var from = e.relatedTarget;
// dragenter和dragleave事件冒泡,
//它使得在像<u1》元素有<1i》子元素的情况下,
//何时高亮显示或取消高亮显示元素变得棘手
//在定义relatedTarget的浏览器中,我们熊跟踪它
//否则,我们需要通过统计进入和离开的次数
//如果从列表外面进入或第一次进入,
//那么需要做一些处理
entered++;
if ((from && !ischild(from, list)) || entered == 1) {
// 所有的DnD信息都在dataTransfer对象上
var dt = e.dataTransfer;
// dt.types对象列出可用的拖放数据的类型或格式
//HTML5定义这个对象有contains()方法
//在一些浏览器中,它是一个有indexOf()方法的数组
//在IE8以及之前版本中,它根本不存在
var types = dt.types; // 可用数据格式是什么
//如果没有任何类型的数据或可用数据是纯文本格式,
//那么高亮显示列表让用户知道我们正在监听拖放,
//同时返回false让浏览器知晓
if (!types || // IE
(types.contains && types.contains(“text/plain”)) || //HTML5
(types.indexOf && types.indexOf(“text/plain”)!=-1)) //Webkit
{
list.className = original_class + ” droppable”;
return false;
}
// 如果我们无法识别数据类型,我们不希望拖放
return; // 没有取消
}
return false; // 如果不是第一次进入,我们继续保持兴趣
};
// 当鼠标指针悬停在列表上时,会调用这个处理程序
// 我们必须定义这个处理程序并返回false,否则这个拖放操作将取消
list.ondragover = function(e) { return false; };
//当拖放对象移出列表或从其子元素中移出时,会调用这个处理程序
//如果我们真正离开这个列表(不是仅仅从一个列表项到另一个),
//那么取消高亮显示它
list.ondragleave = function(e) {
e = e || window.event;
var to = e.relatedTarget;
//如果我们要到列表以外的元素或打破离开和进入次数的平衡,
//那么取消高亮显示列表
entered–;
if ((to && !ischild(to,list)) || entered <= 0) {
list.className = original_class;
entered = 0;
}
return false;
};
// 当实际放置时,会调用这个程序
// 我们会接受放下的文本并将其放到一个新的<1i>元素中
list.ondrop = function(e) {
e = e || window.event; // 获得事件
// 获得放置的纯文本数据
//“Text”是.’text/plain”的昵称,
//IE不支持“text/plain”,所以在这里使用“Text”
var dt = e.dataTransfer; // dataTransfer对象
var text = dt.getData(“Text”); // 获取放置的纯文本数据
// 如果得到一些文本,把它放入列表尾部的新项中
if (text) {
var item = document.createElement(“li”); // 创建新<li>
item.draggable = true; // 使它可拖动
item.appendChild(document.createTextNode(text)); // 添加文本
list.appendChild(item); // 把它添加到列表中
// 恢复列表的原始样式且重置进入次数
list.className = original_class;
entered = 0;
return false;
}
};
// 使原始所有列表项都可拖动
var items = list.getElementsByTagName(“li”);
for(var i = 0; i < items.length; i++)
items[i].draggable = true;
//为拖动列表项注册事件处理程序
//注意我们把处理程序放在列表上,
//让事件从列表项向上冒泡
//当在列表中开始拖动对象,会调用这个处理程序
list.ondragstart = function(e) {
var e = e || window.event;
var target = e.target || e.srcElement;
// 如果它不是从<1i>向上冒泡,那么忽略它
if (target.tagName !== “LI”) return false;
// 获得最重要的dataTransfer对象
var dt = e.dataTransfer;
// 设置拖动的数据和数据类型
dt.setData(“Text”, target.innerText || target.textContent);
// 设置允许复制和移动这些数据
dt.effectAllowed = “copy Move”;
};
// 当成功的放置后,将调用这个处理程序
list.ondragend = function(e) {
e = e || window.event;
var target = e.target || e.srcElement;
//如果这个拖放操作是move,那么要删除列表项
//在IE8中,它将是“none”,除非在之前的ondrop处理程序中显式设置它为move
//但为IE强制设置“move”会阻止其他浏览器给用户选择复制还是移动的机会
if (e.dataTransfer.dropEffect === “move”)
target.parentNode.removeChild(target);
}
//这是在ondragenter和ondragleave使用的工具函数
//如果a是b的子元素则返回true
function ischild(a,b) {
for(; a; a = a.parentNode) if (a === b) return true;
return false;
}
}
});

7.过滤用户输入
/**
* Input Filter.js:不唐突地过滤<input>元素的键盘输入
*
*这个模块查找文档中拥有”data-allowed-chars”属性的所有<input type=”text”>元素
*它为所有这类元素都注册keypress, textInput和textinput事件处理程序,
*来限制用户只能输入出现在许可属性值中的字符
*如果<input>元素也有一个“data-messageid”属性,
*那么认为这个值是另一个文档元素的id
*如果用户输入了不允许的字符,那么会显示消息元素
*如果用户输入了允许的字符,那么会隐藏消息元素
*这个信息id元素用于向用户说明拒绝输入的原因
*它通常应该由CSS控制样式,所以它开始不可见
*下面是使用这个模块的HTML代码示例
*
* Zipcode: <input id=”zip” type=”text”
* data-allowed-chars=”0123456789″ data-messageid=”zipwarn”>
* <span id=”zipwarn” style=”color:red;visibility:hidden”>Digits only</span>
*
* 这个模块相当地不唐突,它没有定义全局命名空间中的任何符号
*/
whenReady(function () { // 当文档加载完毕时,运行这个函数
//查找所有<input>元素
var inputelts = document.getElementsByTagName(“input”);
//遍历它们
for(var i = 0 ; i < inputelts.length; i++) {
var elt = inputelts[i];
//跳过不是文本域或没有data-allowed-chars属性的元素
if (elt.type != “text” || !elt.getAttribute(“data-allowed-chars”))
continue;

//在input元素上注册事件处理程序函数
//传统的keypress事件处理程序能够在任何地方运行
//textInput(混合大小写)在2010年后Safari和Chrome支持
// textinput (小写)是3级DOM事件规范草案中的版本
if (elt.addEventListener) {
elt.addEventListener(“keypress”, filter, false);
elt.addEventListener(“textInput”, filter, false);
elt.addEventListener(“textinput”, filter, false);
}
else { //不支持addEventListener()的IE也不会支持textinput
elt.attachEvent(“onkeypress”, filter);
}
}
//这是用于过滤用户输入的keypress,textInput和textinput事件处理程序
function filter(event) {
//获取事件对象和目标元素对象
var e = event || window.event; //标准或IE模型
var target = e.target || e.srcElement; //标准或IE模型
var text = null; //输入的文本
// 获取输入的字符或文本
if (e.type === “textinput” || e.type === “textInput”) text = e.data;
else { //这是传统的keypress事件
//对于可打印键的keypress事件,Firefox使用charCode
var code = e.charCode || e.keyCode;
//如果按下的是任何形式的功能键,不要过滤它
if (code < 32 || // ASCII控制字符
e.charCode == 0 || //功能键(仅指Firefox)
e.ctrlKey || e.altKey) //按下辅助键
return; //不过滤这个事件
//把字符编码转化为字符串
var text = String.fromCharCode(code);
}

//现在需要从input元素中寻找所需信息
var allowed = target.getAttribute(“data-allowed-chars”); //合法字符
var messageid = target.getAttribute(“data-messageid”); //信息元素id
if (messageid) //如果存在消息元素id,那么获取这个元素
var messageElement = document.getElementById(messageid);

//遍历输人文本中的字符
for(var i = 0; i < text.length; i++) {
var c = text.charAt(i);
if (allowed.indexOf(c) == -1) { //这是不允许的字符吗?
//如果存在不合法字符,显示消息元素
if (messageElement) messageElement.style.visibility = “visible”;
//取消默认行为,所有不会插入文本
if (e.preventDefault) e.preventDefault();
if (e.returnValue) e.returnValue = false;
return false;
}
}
//如果所有的字符都合法,隐藏存在的消息元素
if (messageElement) messageElement.style.visibility = “hidden”;
}
});

8.使用propertychange事件探测文本输入
function forceToUpperCase(element) {
if (typeof element === “string”) element = document.getElementById(element);
element.oninput = upcase;
element.onpropertychange = upcaseOnPropertyChange;
//简易案例:用于input事件的处理程序
function upcase(event) { this.value = this.value.toUpperCase(); }
//疑难案例:用于propertychange事件的处理程序
function upcaseOnPropertyChange(event) {
var e = event || window.event;
//如果value属性发生改变
if (e.propertyName === “value”) {
//移除onpropertychange处理程序,避免循环调用
this.onpropertychange = null;
//把值都变成大写
this.value = this.value.toUpperCase();
//然后恢复原来的propertychange处理程序
this.onpropertychange = upcaseOnPropertyChange;
}
}
}

9.键盘快捷健的Keymap类
/*
* Keymap.js:绑定键盘事件和处理程序函数
*
* 这个模块定义一个Keymap类
* 这个类的实例表示按键标识符(下面有定义)到处理程序函数的映射
* Keymap能配置到HTML元素上以处理keydown事件
* 当此类事件发生时,Keymap会使用它的映射来调用合适的处理程序
*
* 当创建Keymap时,
* 能传入一个JavaScript对象,它表示Keymap绑定的初始设置
* 对象的属性名是按键标识符,而属性值是处理程序函数
* 在创建Keymap之后,
* 通过给bind()方法传人按键标识符和处理程序函数可以添加一个新绑定
* 能给unbind()方法传入按键标识符来移除绑定
*
* 通过给Keymap的install()方法传入像document对象这样的HTML元素,然后就可以使用它
* install()方法给指定的对象添加onkeydown事件处理程序
* 当调用这个处理程序时,
* 它判断按下键的按键标识符,
* 如果有这个按键标识符的任何绑定,就调用对应的处理程序函数
* 一个Keymap可以在多个HTML元素上配置*
*
* 按键标识符
*
* 按键标识符是一个区分大小写的字符串,
* 它表示按键加上同一时刻按下的辅助键
* 按键的名字通常是按键上的字符(不会变)
* 法定的键名包括“A”,“7”,“F2”,“PageUp”,“Left”,“Backspace”和“Esc”
*
* 请参阅模块的Keymap.keyCodeToKeyiVame对象中的键名列表
* 这里有3级DOM规范定义的键名子集,
* 并且当实现时这个类将使用事件对象的key属性
*
* 按键标识符也可能包含辅助键前缀
* 这些前缀是Alt, Ctrl, Meta和Shift
*它们区分大小写,且必须使用空格、下划线、连字符或’‘+”来和按键名或彼此分开
* 例如:”SHIFT+A”, “Alt_F2”, “meta-v”和”ctrl alt left”
* 在Mac中,Meta是Commnad键,Alt是Option键
* 一些浏览器把Windows键映射到Meta辅助键
*
* 处理程序函数
*
* 处理程序在配置Keymap的文档或文档元素上作为其方法调用,
* 并传人两个参数:
* 1) keydown事件的事件对象
* 2)按下的按键的标识符
* 处理程序的返回值就是keydown处理程序的返回值
* 如果处理程序函数返回false,
* Keymap将停止冒泡并取消和keydown事件相关的默认操作
*
* 限制
*
* 在所有按键上绑定一个事件处理函数是不可能的
* 操作系统会限制一些按键序列(例如,Alt+F4)
* 而浏览器本身也可能限制其他一些按键序列(比如:Ctrl+S)
* 这些代码受限于浏览器、OS和本地设置。功能键和有辅助键的功能键工作得很好,
* 而没有辅助键的字母数字键也工作得很好
* Ctrl和Alt与字母键盘键的结合非常强健
*
* 在美国标准键盘布局上,
* 能够支持大多数不需要Shift键的标点字符(`=[];’,./\不包括连字符)
* 但是它们不特别适合其他键盘布局,应该避免
*/
// 这是构造函数
function Keymap(bindings) {
this.map = {}; //定义按键标识符->处理程序映射
if (bindings) { //给它复制初始绑定
for(name in bindings) this.bind(name, bindings[name]);
}
}
//绑定指定的按键标识符和指定的处理程序函数
Keymap.prototype.bind = function(key, func) {
this.map[Keymap.normalize(key)] = func;
};
//删除指定按键标识符的绑定
Keymap.prototype.unbind = function(key) {
delete this.map[Keymap.normalize(key)];
};
//在指定HTML元素上配置Keymap
Keymap.prototype.install = function(element) {
//这是事件处理程序函数
var keymap = this;
functionHandler(event) { return keymap.dispatch(event, element); }
//现在安装它
if (element.addEventListener)
element.addEventListener(“keydown”,Handler, false);
else if (element.attachEvent)
element.attachEvent(“onkeydown”,Handler);
};
//这个方法基于Keymap绑定分派按键事件
Keymap.prototype.dispatch = function(event, element) {
//开始没有辅助键和键名
var modifiers = “”
var keyname = null;
//按照标准的小写字母顺序构建辅助键字符串
if (event.altKey) modifiers += “alt_”;
if (event.ctrlKey) modifiers += “ctrl_”;
if (event.metaKey) modifiers += “meta_”;
if (event.shiftKey) modifiers += “shift_”;
//如果实现3级DOM规范的key属性,获取keyname很容易
if (event.key) keyname = event.key;
//在Safari和Chrome上用keyIdentifier获取功能键键名
else if (event.keyIdentifier && event.keyIdentifier.substring(0,2) !== “U+”)
keyname = event.keyIdentifier;
//否则,使用keyCode属性和后面编码到键名的映射
else keyname = Keymap.keyCodeToKeyName[event.keyCode];
//如果不能找出键名,只能返回并忽略这个事件
if (!keyname) return;
//标准的按键id是辅助键加上小写的键名
var keyid = modifiers + keyname.toLowerCase();
//现在查看按键标识符是否绑定了任何东西
varHandler = this.map[keyid];
if (handler) { //如果这个键有处理程序,调用它
//调用处理程序函数
var retval =Handler.call(element, event, keyid);
//如果处理程序返回+alse,取消默认操作并阻止冒饱
if (retval === false) {
if (event.stopPropagation) event.stopPropagation(); // DOM模型
else event.cancelBubble = true; // IE模型
if (event.preventDefault) event.preventDefault(); // DOM
else event.returnValue = false; // IE
}
//返回处理程序的返回值
return retval;
}
};
//用于把按键标识符转换成标谁形式的工具函数
//在非Mac硬件,我们这里把“meta”映射到“ctrl”,
//这样在Mac中“Meta+C”将变成“Command+C”,其他都是“Ctrl+C”
Keymap.normalize = function(keyid) {
keyid = keyid.toLowerCase(); // 一切都小写
var words = keyid.split(/\s+|[\-+_]/); //分割辅助键和键名
var keyname = words.pop(); // 键名是最后一个
keyname = Keymap.aliases[keyname] || keyname; //它是别名吗?
words.sort(); // 排序剩下的辅助键
words.push(keyname); // 添加到序列化名字后面
return words.join(“_”); // 把它们拼接起来
};
Keymap.aliases = { // 把按键的常见别名映射到它们的“正式名”
“escape”:”esc”, // 键名使用3级DOM规范的定义
“delete”:”del”, // 和后面的编码到键名的映射
“return”:”enter”, // 所有的键和值都必须小写
“ctrl”:”control”,
“space”:”spacebar”,
“ins”:”insert”
};
// 传统的keydown事件对象的keyCode属性是不标准的
// 但下面的值似乎可以在大多数浏览器和OS中可行
Keymap.keyCodeToKeyName = {
// 使用词或方向键的按键
8:”Backspace”, 9:”Tab”, 13:”Enter”, 16:”Shift”, 17:”Control”, 18:”Alt”,
19:”Pause”, 20:”Caps Lock”, 27:”Esc”, 32:”Spacebar”, 33:”Page Up”,
34:”Page Down”, 35:”End”, 36:”Home”, 37:”Left”, 38:”Up”, 39:”Right”,
40:”Down”, 45:”Insert”, 46:”Del”,
// 主键盘(非数字小键盘)上的数字键
48:”0″,49:”1″,50:”2″,51:”3″,52:”4″,53:”5″,54:”6″,55:”7″,56:”8″,57:”9″,
// 字母按键,注意我们不区分大小写
65:”A”, 66:”B”, 67:”C”, 68:”D”, 69:”E”, 70:”F”, 71:”G”, 72:”H”, 73:”I”,
74:”J”, 75:”K”, 76:”L”, 77:”M”, 78:”N”, 79:”O”, 80:”P”, 81:”Q”, 82:”R”,
83:”S”, 84:”T”, 85:”U”, 86:”V”, 87:”W”, 88:”X”, 89:”Y”, 90:”Z”,
// 数字小键盘的数字和标点符号按键(Opera不支持这些)
96:”0″,97:”1″,98:”2″,99:”3″,100:”4″,101:”5″,102:”6″,103:”7″,104:”8″,105:”9″,
106:”Multiply”, 107:”Add”, 109:”Subtract”, 110:”Decimal”, 111:”Divide”,
// 功能键
112:”F1″, 113:”F2″, 114:”F3″, 115:”F4″, 116:”F5″, 117:”F6″,
118:”F7″, 119:”F8″, 120:”F9″, 121:”F10″, 122:”F11″, 123:”F12″,
124:”F13″, 125:”F14″, 126:”F15″, 127:”F16″, 128:”F17″, 129:”F18″,
130:”F19″, 131:”F20″, 132:”F21″, 133:”F22″, 134:”F23″, 135:”F24″,
//不需要按下Shift键的标点符号键
//连字符不兼容,FF返回的编码和减号一样
59:”;”, 61:”=”, 186:”;”, 187:”=”, // Firefox和Opera返回59,61
188:”,”, 190:”.”, 191:”/”, 192:”`”, 219:”[“, 220:”\\”, 221:”]”, 222:”‘”
};



转载请注明:陈童的博客 » JavaScript__事件的练习题

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

无觅相关文章插件,快速提升流量

'; } if( dopt('d_footcode_b') ) echo dopt('d_footcode'); ?>