Backbase AJAXフレームワークと緊密に連携して、ハンドラーが使用される場所で定義されている場合、宣言型イベントハンドラーを使用する便利さを感じました。
ボタンのイベント
クリックハンドラーの例を次に示します。
< button >
< tb:handler event ='click' >
alert(' click ')
</ tb:handler >
</ button >
* This source code was highlighted with Source Code Highlighter .
実装の基礎を簡単に説明してください。 ハンドラーを宣言するには、名前空間で非標準のタグを使用します(xhtmlでの正しい操作のため)。 ページの読み込み時に、すべての要素を見つけて、実際のイベントハンドラーを作成します。 使いやすさに加えて、このアプローチにより、ハンドラーの機能を拡張し、IEでイベントを処理したり、
キーボードイベントを共通の分母に導くなど、さまざまなブラウザーで作業を統合することができます。
最初のバージョンは、主な実装のアイデアを示しています。
if (!window.ev){
// ,
window.ev = {};
//
ev.namespaceURI = 'http://tedbeer.net' ;
// ,
ev.browser = {ie : false , standard : false };
ev.browser.standard = Boolean( document .addEventListener);
ev.browser.ie = '\v' == 'v' ; //for other browsers it's a vertical tab - \u000B
//
ev.init = function ( event ){
var arr = [];
if (ev.browser.ie) {
arr = document .getElementsByTagName( 'handler' );
for ( var i = 0; i < arr.length; i++) {
if (arr[i].tagUrn == ev.namespaceURI) {
arr[i].parentNode[ 'on' + arr[i].getAttribute( 'event' )] =
new Function( 'event' , arr[i].innerText);
arr[i].innerText = '' ; //clean up to avoid displaying
}
}
} else {
arr = document .getElementsByTagNameNS(ev.namespaceURI, 'handler' ); //xhtml
if (!arr.length) //html
arr = document .getElementsByTagName( 'tb:handler' );
for ( var i = 0; i < arr.length; i++) {
arr[i].parentNode.addEventListener( arr[i].getAttribute( 'event' ),
new Function( 'event' , arr[i].textContent), false );
arr[i].textContent = '' ; //clean up to avoid displaying
}
}
};
if (ev.browser.standard)
window.addEventListener( 'load' , ev.init, false );
else
window.onload = ev.init;
}
* This source code was highlighted with Source Code Highlighter .
テストページ:
< style type ="text/css" >
.test-div {
width: 200px;
height: 200px;
background-color: #6699FF;
}
</ style >
< script type ="text/javascript" src ="ev.js" ></ script >
< div class ="test-div" >
< tb:handler event ='click' >
alert('click');
</ tb:handler >
</ div >
* This source code was highlighted with Source Code Highlighter .
オンラインテスト コードev.jsコードは何をしているのかを簡単に理解できるほど十分に透過的ですが、意図的に誤解を招くような妨害が含まれています。
- ブラウザはスペースと改行を食べるため、すべての演算子は「;」で終わる必要があります
- 同じ理由で、「//」は現在の行だけでなく、その後のコード全体もコメントアウトします
- 多くの開発者が行うように、IEでハンドラーをアタッチする方法の代わりに、 .attachEventを使用する必要があります。 この場合、いくつかのハンドラーが要素に正しくアタッチされています。
- IEのハンドラーは、他のブラウザーの場合のように、ローカルイベントパラメーターを受け取りません
- 構文エラーは処理されません
有能な開発者はより多くのショールを見つけるでしょう、私はこれを私の宿題として残します:-)コメントに何か書くことがあるように。 次のコードでは、これらの妨害を修正し、次の機能を追加します。
- IEにイベントイベントオブジェクトを渡す
- IEの標準event.targetプロパティを追加します
- 機能を拡張する-特定の子要素のハンドラーのみが機能するように、 match属性を追加します
コードは少し複雑になっています。
if (!window.ev){
// ,
window.ev = {};
//
ev.namespaceURI = 'http://tedbeer.net' ;
// ,
ev.browser = {ie : false , standard : false };
ev.browser.standard = Boolean( document .addEventListener);
ev.browser.ie = '\v' == 'v' ; //for other browsers it's a vertical tab - \u000B
//
ev.setEventHandler = function (oNode, oEventNode){
if ( this .browser.ie) {
var vHandler = function (){
var self = arguments.callee;
var ev = window. event ;
ev.target = ev.srcElement;
ev.currentTarget = self.node.parentNode;
var sMatch = self.node.getAttribute( 'match' );
if (sMatch === null || Sizzle.matches(sMatch, [ev.target]).length > 0)
return self.handler(ev);
}
vHandler.node = oEventNode;
var sBody = oEventNode.innerText;
if (!sBody.length) { // CDATA (xhtml)
for ( var i = 0; i < oEventNode.childNodes.length; i++)
if (oEventNode.childNodes[i].nodeType) { //4 or 8 - CDATA or comment
sBody = oEventNode.childNodes[i].nodeValue;
break ; //
}
} else //
oEventNode.innerText = '' ;
//
try {
vHandler.handler = new Function( 'event' , sBody);
} catch (e) { //
alert(e.message + ':\n' + sBody)
}
oNode.attachEvent( 'on' + oEventNode.getAttribute( 'event' ), vHandler);
} else {
var vHandler = function ( event ){
var self = arguments.callee;
var sMatch = self.node.getAttribute( 'match' );
if (sMatch === null || Sizzle.matches(sMatch, [ event .target]).length > 0)
return self.handler( event );
}
vHandler.node = oEventNode;
var sBody = oEventNode.textContent;
if (!sBody.length) { // CDATA (xhtml)
for ( var i = 0; i < oEventNode.childNodes.length; i++) {
if (oEventNode.childNodes[i].nodeType) { //4 or 8 - CDATA or comment
sBody = oEventNode.childNodes[i].nodeValue;
break ; //
}
}
} else //
oEventNode.textContent = '' ;
//
try {
vHandler.handler = new Function( 'event' , sBody);
} catch (e) { //
alert(e.message + ':\n' + sBody)
}
oNode.addEventListener( oEventNode.getAttribute( 'event' ), vHandler, false );
}
};
ev.init = function ( event ){
var arr = [];
if ( document .getElementsByTagNameNS) { //xhtml
arr = document .getElementsByTagNameNS(ev.namespaceURI, 'handler' )
}
if (!arr.length) {
if (ev.browser.ie) { //ie
arr = []; //convert a nodelist to array
var arr2 = document .getElementsByTagName( 'handler' );
for ( var i = 0; i < arr2.length; i++) {
if (arr2[i].tagUrn == ev.namespaceURI) { //accept our namespace only
arr.push(arr2[i]);
}
}
} else //html
arr = document .getElementsByTagName( 'tb:handler' );
}
for ( var i = 0; i < arr.length; i++) {
ev.setEventHandler(arr[i].parentNode, arr[i]);
}
};
if (ev.browser.standard) {
window.addEventListener( 'load' , ev.init, false );
} else
window.attachEvent( 'onload' , ev.init);
}
* This source code was highlighted with Source Code Highlighter .
テストページ:
.test-div {
width: 200px;
height: 200px;
background-color: #6699FF;
border-bottom: 1px dotted #666666;
}
.inner-div {
width: 100px;
height: 100px;
background-color: #66CCCC;
}
.test-div2 {
width: 200px;
height: 200px;
background-color: #6699FF;
}
.inner-div2 {
width: 100px;
height: 100px;
background-color: #66CCCC;
}
</ style >
< script type ="text/javascript" src ="sizzle.js" ></ script >
<script type= "text/javascript" src= "ev2.js" > </ script >
</ head >
< body >
Click on boxes to see what event handlers are called.
< div class ="test-div" >
< tb:handler event ='click' match ='.inner-div' ><!--
alert('A: ' + event.target.className)
// comment
alert('<A2>')
--></ tb:handler >
< tb:handler event ='click' match ='.test-div' ><!--
alert('B: ' + event.target.className)
// comment
alert('<B2> ')
--></ tb:handler >
< div class ="inner-div" > XXX </ div >
</ div >
< div class ="test-div2" >
< tb:handler event ='click' match ='.inner-div2' >
alert('C: ' + event.target.className)
</ tb:handler >
< div class ="inner-div2" > YYY </ div >
</ div >
*このソースコードは、 ソースコードハイライターで強調表示されました。
オンラインhtmlテスト xhtmlテスト コードev2.jsこのコードはコメント内にあり、ブラウザーの解析を回避し、スペースと改行を保持します。
xhtmlの場合 、コードを
CDATAセクションに配置します。
CSSセレクターが機能するための
シズルライブラリの使用に注意してください。 同様に、独自のイベントハンドラー機能拡張を追加できます。
結論 :
上記のコードはほんの小さなデモンストレーションです。 本格的なプロジェクトに適したフレームワークを探していて、宣言型言語を気にしない場合は、
Backbaseと
AmpleSDKをご覧になることをお勧めします。 実際、1人が両方のフレームワークに取り組みました。 後者(
AmpleSDK )については、まもなく
ayaxinに関する発表がある
はずです。 著者はまだ古い契約に関する彼の権利に驚いており、ソースコードを開くことができません。 しかし、この期間が過ぎるとすぐに、彼はフレームワークをオープンソースにすることを約束しました。 フレームワークは他の多くのモジュール(svg、smil、xinclude、schema ...)を実装します。これらはすべてクロスブラウザー(IEを含む)であり、最も重要なことは、自家製APIではなく標準APIを使用します。 したがって、使用を開始するのは簡単です-単に標準に目を通すだけです。
脅威 このコードは、プロジェクトに制限なく使用できます。 どこからもコピーされません。 私は基本的に、これを回避するために利用可能なフレームワークの実装を見ていませんでした。
UPD 熟したAmpleSDKの発表はここにあります:
ajaxian.com/archives/ample-sdk-browser-in-a-browser