ADS4.2 响应用户操作和事件——事件流

前端技术 everyinch 4266℃ 0评论

为了更好地解析事件流,首先看一下示例文件的效果:
效果演示
示例文件flow.html包含嵌套的列表和一些JavaScript和CSS文件:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Event Flow</title>
    <link rel="stylesheet" type="text/css" href="../styles/source.css" />
    <link rel="stylesheet" type="text/css" href="style.css" />
	
    <script type="text/javascript" src="../libs/ADS-final-verbose.js"></script>
    <script type="text/javascript" src="../libs/myLogger.js"></script>
    <script type="text/javascript" src="flow.js"></script>
</head>
<body>
<h1>Event Flow</h1>
<div id="content">
    <ul id="list1">
        <li>
            <p>List 1 </p>
            <ul id="list2">
                <li>
                    <p>List 2 </p>
                    <ul id="list3">
                        <li>
                            <p>List 3 </p>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
    
    <ul id="list4">
        <p>List 4 </p>
    </ul>
</div>
</body>
</html>

使用CSS样式设置第3个列表(List 3)的位置,使它的位置处于祖先元素之外,且位于第4个列表(List 4)之上。这个设置是要关注的重点,因为即使List 3浮动到了List 4的上面,它仍然嵌套在其祖先元素中:

#list1 {
	height:80px;
}
#list2 {
	margin-top: 10px;
	height:20px;
}

#list3 {
	position:absolute;
	top:190px;
	left:150px;
}

#list4 {
	margin-top:10px;
	height:100px;
}
[/code]
flow.js文件为每个无序列表都注册了click事件侦听器,主要任务是修改被单击元素的类样式:
ADS.addEvent(window,'load',function() {

    // 使用经过修改的addEvent()方法
    function modifiedAddEvent( obj, type, fn ) {
        if(obj.addEventListener) {
            // W3C方式
            obj.addEventListener( type, fn, true );

        } else if ( obj.attachEvent ) {
            // IE方式
            obj['e'+type+fn] = fn;
            obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
            obj.attachEvent( 'on'+type, obj[type+fn] );
        } else {
            return false;
        }
    }
    
    var counter = 0;
    
    // 取得无序列表
    var lists = document.getElementsByTagName('ul');
    for(var i = 0 ; i < lists.length ; i++ ) {        
        // 注册事件侦听器
        modifiedAddEvent(lists&#91;i&#93;,'click',function() {
            // 向段落中添加表示先后顺序的数字
            var append = document.createTextNode(':' + counter++);
            this.getElementsByTagName('p')&#91;0&#93;.appendChild(append) ;
            
            // 修改被单击元素的样式
            this.className = 'clicked';
        });
    }
    
});
&#91;/code&#93;
查看了效果演示并在浏览器中单击List 3,会发现List 1和List 2也改变了颜色,而这与List 3的位置无关,只与元素的嵌套关系有关。
<a href="http://www.everyinch.net/wp-content/uploads/2014/01/blog_flow1.jpg"><img src="http://www.everyinch.net/wp-content/uploads/2014/01/blog_flow1.jpg" alt="blog_flow1" width="550" height="231" class="alignnone size-full wp-image-4721" /></a>
1. 事件的顺序
注意到上图在调用事件侦听器之后,出现在列表名称后面的数字。这些数字表示的是事件被处理的顺序,0表示首先被处理。如果看到的数字和图中的不一致,且数字顺序相反,则说明使用的不是与DOM2级事件规范兼容的浏览器。这也在于示例中修改了addEvent()方法,以不同的方式注册click事件侦听器:

function modifiedAddEvent( obj, type, fn ) {
    if(obj.addEventListener) {
        // W3C方式
        obj.addEventListener( type, fn, true );

    } else if ( obj.attachEvent ) {
        // IE方式
        obj['e'+type+fn] = fn;
        obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
        obj.attachEvent( 'on'+type, obj[type+fn] );
    } else {
        return false;
    }
}

修改后的函数将addEventListener()方法的最后一个参数替换成true。即启用了事件流的捕获阶段,而禁用了冒泡阶段。当事件被注册在捕获阶段,浏览器会先从最外层的祖先元素开始触发click事件,然后向内部依次传递。
blog_flow2
然而,IE不支持捕获,其attachEvent()方法只能按照从目标元素向外传播到祖先元素的顺序。如下图所示:
blog_flow3
2. 两个阶段和三个模型
事件冒泡和事件捕获恰好是相反的过程。由IE提出的事件冒泡,指的是目标元素的事件首先触发,然后事件向外传播到每个祖先组员,直至document对象。考虑下面这个非常简单的文档:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <title>Sample Markup</title>
</head>
<body>
    <ul>
        <li>
            <a href="http://example.com">Link 1</a>
        </li>
        <li>
            <a href="http://example.com">Link 2</a>
        </li>
    </ul>
</body>
</html>

单击Link 1的冒泡事件流如下图所示:
blog_flow4
由Netscape提出的事件捕获,则把优先权赋予最外层的祖先元素,事件向内传播,直至目标元素。如下图所示:
blog_flow5
在所有支持W3C DOM的浏览器中,冒泡事件流是默认事件流。事实上,W3C事件规范中并没有提出不同的事件流,但却通过同时包含捕获和冒泡阶段较好地解决了这两个极端的问题。如下图所示
blog_flow6
3. 阻止冒泡
要在W3C DOM2级事件中取消冒泡阶段,可以简单地在事件对象上调用stopPropagation()方法。同样,对于IE浏览器需要将事件的cancelBubble属性设置为true。
为了弥合这种差异性,在自定义的ADS库中添加ADS.stopPropagation()方法:

/**
 * 阻止事件的传播
 */
function stopPropagation(eventObject) {
    eventObject = eventObject || getEventObject(eventObject);
    if(eventObject.stopPropagation) {
        eventObject.stopPropagation();
    } else {
        eventObject.cancelBubble = true;
    }
}
window['ADS']['stopPropagation'] = stopPropagation;

4.取消默认操作
与事件流有关的最后一个问题是默认动作。例如可以通过使用由click事件侦听器返回的false值,阻止浏览器重定向到href属性所指向的页面。虽然这种方式也有效,但正确的方式还是要根据浏览器的能力而进行处理。DOM2事件规范使用了preventDefault()方法取消默认动作,IE将事件对象的retureValue属性设置为false来取消默认事件。
在自定义的ADS库中添加ADS.preventDefault()方法:

/**
 * 阻止浏览器的默认行为
 */
function preventDefault(eventObject) {
    eventObject = eventObject || getEventObject(eventObject);
    if(eventObject.preventDefault) {
        eventObject.preventDefault();
    } else {
        eventObject.returnValue = false;
    }
}
window['ADS']['preventDefault'] = preventDefault;

转载请注明:陈童的博客 » ADS4.2 响应用户操作和事件——事件流

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

表情

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

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
'; } if( dopt('d_footcode_b') ) echo dopt('d_footcode'); ?>