フォームまたはWebの8ゼロ1から3の改善

そのため、スタンドアロンのファットクライアントではなくブラウザを選択しました。 ユーザーは本当にデータを入力したいと考えています。 ただし、普通のフォームは悪いです。 なぜなら:



データとHTMLが混在しています。
ドロップダウンリストと名前の先頭で検索する便利なウィジェットはありません。
フォームにデータをロードする便利な組み込み機能はありません。
AJAXを介してフォームデータを送信する便利な方法はありません。


何が欲しい?

データからフォームのHTMLコードを完全に解きます。
フォームをプリロードする機能があります。
フォームをカスタマイズする柔軟性があります。
名前の先頭で検索できる便利なドロップダウンリストがあります。
その環境からフォームのコントロールを解きます。
などなど。

最後から始めましょう。 ドロップダウンリストはどうあるべきですか? 確かに標準のSELECTは好きではありません!
まず、ディレクトリを使用する必要があります。 つまり、ペアのセット["key"、 "value"]。 この場合、ユーザーには文字列「value」が表示され、「key」がサーバーに送信されます。
第二に、文字を入力するとき、リストを表示するとき、ディレクトリと一緒にINPUTに接続する必要があります。

ドロップダウンリストを作成するには(略してドロップダウンと呼びます)、jQueryを使用します。 jQueryの利点は何ですか? 少なくともこれ:

1.ドキュメントのDOM構造が既にロードされている(そして、それを台無しにすることができる)場合、便利なコールバック関数で、あらゆる種類の画像がまだロードされていない可能性があります。

$(document).ready(function(){

// ... DOM

});


2. IDによる必要な要素の便利な検索

$('#some_id')

3.任意のDOM要素のjQueryオブジェクトによる便利なバインディング

$(some_DOM_element)

4.イベントの便利なバインド

$(li).hover( function() { this.style.fontWeight = 'bold'; }, function() { this.style.fontWeight = 'normal'; } )

この呼び出しは、2つのイベントをli DOM要素にバインドします:カーソルが要素上を移動するときと要素が移動するとき。
これらのイベントの間隔で、DOM要素は太字のフォントを受け取ります(これはイベントハンドラーで正確に指すためです)

5.個々のDOM要素またはそのセットに普遍的に適用される便利なjQueryオブジェクトメソッド

.show() show
.hide() hide
.val()制御値を取得
.val(new_value)制御値を設定

などなど。

jQueryの拡張機能を活用します。 ドロップダウンの基礎として、オートコンプリートスクリプトを使用しました。Googleで検索すると、同様のクエリが表示されます。 グーグルで検索するのは簡単です。 完成したソリューションは次のように動作するはずです。フォームを設定するとき、ドロップダウンをディレクトリにバインドし、次のようにコントロールにバインドできる必要があります。

$(form.some_element_name).dropdown( some_directory, options ) ;

some_directoryこれは参照(何らかのJavaScriptオブジェクト。これについては後で説明します)

これを達成する方法は? 上記で呼び出される新しいjQueryメソッドを作成します。

jQuery.fn.dropdown = function (data, options)
{
options = options || {};
options.data = (( typeof data == "object" ) && (data.constructor == Array)) ? data : null ;
options.key = options.key || "key" ;
options.value = options.value || "value" ;
options.matchCase = options.matchCase || 0;
options.list_size = options.list_size || 11;
options.containerClass = options.containerClass || "__dropdown_container_class" ;
options.selectedItemClass = options.selectedItemClass || "__dropdown_selected_item_class" ;
options.items = options.data ? clone_quicksort(options.data, options.value, options.matchCase ? less_than_compare : less_than_ignore_case_compare) : null ;
options.items_hash = options.items ? hash_array(options.items, options.key) : null ;
this .each( function () { var input = this ; new jQuery.dropdownConstructor(input, options); } );
return this ;
}


* This source code was highlighted with Source Code Highlighter .


私は彼を完全に連れてきました。 このスクリプトがさまざまなオプションを永続的にチェックしていることは簡単にわかります(まったくない場合は作成されます)。 オプションにはデフォルト値が詰め込まれています。 最後に、この行は次のとおりです。

this.each( function() { var input = this; new jQuery.dropdownConstructor(input, options); } );

セレクターが選択した要素のリストを反復処理し、それぞれに対して、dropdownConstructorコンストラクターを使用して新しいjQueryドロップダウンオブジェクトを作成します。 これには必要なすべてのコードが含まれており、次のようになります。

jQuery.dropdownConstructor = function (input, options)
{

var input = input; // DOM
this .control = input;
var $input = $(input); // jQuery , DOM ( jQuery )
var container = document .createElement( "div" ); // DIV list
var $container = $(container);
var list = document .createElement( "ul" );
var $list = $(list);
var active = false ;
var last_key_pressed = null ;
var timeout = null ;
var value_of_key = ""
var prev_truevalue, next_truevalue;
var that = this ;
input.dropdown = that;
input.truevalue = input.truevalue || null ;

container.appendChild(list); //
$container.hide().addClass(options.containerClass).css( "position" , "absolute" ); //
if ( options.width > 0 ) $container.css( "width" , options.width);
$( "body" ).append(container); set_truevalue(input.truevalue);


function postpone(func)
{
if (timeout) clearTimeout(timeout);
timeout = setTimeout( function (){ func(); }, 25);
}

function set_truevalue(new_truevalue)
{
if (!options.items_hash[new_truevalue])
{
input.truevalue = null ;
value_of_key = "" ;
$input.val( "" );
return ;
}
input.truevalue = new_truevalue;
if (input.truevalue) value_of_key = options.items_hash[input.truevalue][options.value]; else value_of_key = "" ;
$input.val( value_of_key );
}

input.update_control = function () { set_truevalue(that.control.truevalue); }

function activate()
{
if (active) return ;
var pos = element_position(input);
var W = (options.width > 0) ? options.width : $input.width();
$container.css( { width: parseInt(W) + "px" , left: pos.x + "px" , top: (pos.y + input.offsetHeight) + "px" } ).show();
var index = binary_search(options.items, value_of_key, options.value, options.matchCase ? less_than_compare : less_than_ignore_case_compare);
build_list(index - (options.list_size >> 1), index);
active = true ;
}

function deactivate()
{
if (!active) return ;
$container.hide();
active = false ;
}

function move_up()
{
...
}

function move_down()
{
...
}

function select_text_part(start, end)
{
...
}


* This source code was highlighted with Source Code Highlighter .


そして出発。

コードは十分に明確であると思いますが、それでもです。 truevalueがキーです。 これは、キー値を保存するコントロールの属性です(ユーザーには表示されません)。 set_truevalue()はキーを設定し、表示された値を同期します。 active()はドロップダウンを表示し、deactive()は非表示にします。 move_up()、move_down()-リストを上下に移動します。 select_text_part()-テキストの一部を選択します。

これは、コンストラクター内のイベントにバインドする方法です。

$input.keydown( function (e)
{
last_key_pressed = e.keyCode;
switch (e.keyCode)
{
case 38: e.preventDefault(); move_up(); break ;
case 40: e.preventDefault(); move_down(); break ;
case 13: case 9: select_text_part(); deactivate(); break ;
default : postpone(on_change); break ;
}
}).focus( function (){
activate(); select_text_part();
}).blur( function (){
deactivate();
}).mousedown( function (e) { if (!active && !input.disabled) { e.preventDefault(); $input.focus(); activate(); } } );

* This source code was highlighted with Source Code Highlighter .


それでは、参考書について話しましょう。 ディレクトリは、同じタイプの(同じフィールドセットを持つ)オブジェクトのJavaScript配列です。 例えば、「 [ { key:'m', value:'male' }, { key: 'f', value: 'female' } ] 」 デフォルトでは、キーはキーフィールドにあり、値は値フィールドにあります。 ただし、これはいつでも変更できます。

ドロップダウンには、値を増やして(つまり、キー値ではなく表示値を増やして)ソートされたディレクトリが必要です。 通常、文字の大文字と小文字を無視します(ほとんどの場合、ユーザーがキーボードで名前の先頭を入力するとき、彼はまだCAPS LOCKを保持するかどうか)。 したがって、この配列を並べ替える必要があります。そのために、JavaScriptとバイナリ検索で簡単な並べ替えを記述する必要がありました。 結局、ユーザーは名前の一部を入力できます。 ソートは行わず、例としてバイナリ検索のみを行います。

function less_than_compare(val1, val2)
{
return val1 < val2;
}

function binary_search(items,value,key,compare)
{
key = key || "key" ;
compare = compare || less_than_compare;
var l = -1;
var r = items.length;
while ( true )
{
var m = (r - l) >> 1;
if (m == 0) return r;
m += l;
if ( compare(items[m][key],value) )
l = m;
else if ( compare(value, items[m][key]) )
r = m;
else
return m;
}
}

* This source code was highlighted with Source Code Highlighter .


そのため、ハードコーディングの後、すばらしいドロップダウンが機能しました。

画像 www.picamatic.com/show/2009/05/12/06/35/3618111_557x236.png

次に、フォームの処理を開始します。 フォームは、HTMLコード、JavaScript構成コード、およびフォームが機能するために必要なディレクトリのリストの3つの部分に分かれています。 フォームのサーバー側スクリプトは、要求に応じてこれらのすべての部分を返し、さらに、データを受信して​​処理のエラーを返す必要があります。 ファイル/foo.jsのサーバースクリプトは次のようになります。

function receive_request()
{
if (request._command == "jason" ) return "/joo.js,/boo.js" ;

if (request._command == "html" ) return "\
<tr><th> <td><INPUT name=user_name>\
<tr><th> <td><INPUT name=sex truevalue='u'>\
<tr><th> <td><INPUT name=birth_country>\
<tr><th> <td><INPUT name=country>\
"
;

if (request._command == "code" ) return "\
enterAsTab(form, 1);\
$(form.country).dropdown( jason('/boo.js') );\
$(form.birth_country).dropdown( jason('/boo.js') );\
$(form.sex).dropdown( jason('/joo.js') );\
"
;

if (request._command == "post" )
{
var error = "" ;
if (request.user_name.length == 0) error += "user_name: \r" ;
if (request.user_name.length < 5) error += "user_name: 5 \r" ;
if (request.birth_country.length == 0) error += "country: \r" ;
if (request.country.length == 0) error += "country: \r" ;
if (error) return error;

// .. ..

return "OKAY" ;
}


return "" ;
}

* This source code was highlighted with Source Code Highlighter .


サーバーがJavaScriptを使用する理由はここで説明されています: habrahabr.ru/blogs/development/48842

HTMLは単なるコントロールであり、周囲の「<form />」はありません。 少しトリッキーなフォーム構成コードには、2つのパラメーターが必要です。フォームのDOM要素と、URLによって読み込まれた参照を返す関数(jason())です。

そのため、これらすべてを非同期でページにロードして使用します。 2つの考慮事項があります。 まず、ディレクトリは1つのフォームではなくページ全体に属します。 同じディレクトリで異なるフォームを使用できます。 第二に、フォームは、そのすべてのコンポーネントが完全に正常にダウンロードされた後にのみ使用できます。

実際、後で、ダウンロードしたデータをキャッシュし、ダウンロードを相互に階層的にネストできる非同期ローダーを作成しました(たとえば、アクティブなフォームロードをすべて完全に削除するため)。 次に、この上にフォームローダーがあります。これは、ディレクトリのリストを受信すると、ダウンロードするように要求し、表示されるのを待ちます。

したがって、フォームの必要なすべてのコンポーネント(HTML、javascript、およびリファレンスブック)が用意されている(ページにアップロードされている)としましょう。 次のステップは、フォームの_instance_を作成することです。これはユーザーに見えるものです。 以下は、コンテナDOM要素にform_nameという名前のフォームフォームのインスタンスを作成するコードです。 インスタンスはinstance_nameという名前を取得します。

activate: function (instance_name, form_name, container)
{
if (!form_loader.ready(form_name)) return false ;
var form = document .createElement( "form" ); \\ , DOM- form
var jason = function (url) { return jason_loader.data(url); } \\ , jason()
container.innerHTML = '' ;
container.appendChild(form);
form.innerHTML = "<table class='form' >" + form_loader.html(form_name) + "</table>" ;
try
{
eval(form_loader.code(form_name));
}
catch (e)
{
form_loader.forms[form_name].error = ' <i>' + form_name + '</i><BR>' + e.message;
return false ;
}
this .actor[instance_name] = { type: 'form' , name: form_name, form_elem: form, container_elem: container, disabled: [], post: null };
return true ;
}



* This source code was highlighted with Source Code Highlighter .


その考えは明確だと思います。

そして最後に:デザート。 そのため、このコードはすべて作成されました。 このメカニズムを使用するHTMLページのロードコードは次のようになります。

$( document ).ready( function (){

register_form( "foo" , "/foo.js" ); // foo /foo.js
register_form( "voo" , "/voo.js" ); //
await(load_callback); //
});

function load_callback(form_name)
{
if (form_name) //
$( '#report' ).html( $( '#report' ).html() + '<BR>' + form_loader.error(form_name) );
else
{
// !
}

}

* This source code was highlighted with Source Code Highlighter .


あまり簡潔ではないですか? そして、フォームの使用方法は次のとおりです。

id = 'foo_form'でDOM要素にインスタンスを作成します。

director.activate( 'foo_instance' , "foo" , $( '#foo_form' )[0]);



フォームインスタンスにデータをアップロードします。

director.fill( "foo_instance" , {user_name: 'John Smith' , country: 'RO' } );



そして最後に、これが必要なのはデータを送信することです。

director.submit( "foo_instance" , foo_submit);


foo_submit関数は次のようになります。

function foo_submit(instance_name, result, error)
{
if (result)
$( '#report' ).html( ' ' + instance_name + ' ' );
else if (error)
$( '#report' ).html( ' ' + instance_name + ' <BR>' + error);
else
$( '#report' ).html( ' ' + instance_name);
}


* This source code was highlighted with Source Code Highlighter .



submit()メソッドは、データに従ってサーバースクリプトから一連のエラーを受信し、自動的に表示できます。 そして、次に送信されるときに、フォームを削除し、フォームを完全に無効にします。

画像

一般に、フォームを使用すると、表示、消去、データのロード、完全な無効化と有効化のバック、サーバーへの送信、送信の成功の待機など、ほとんどすべてのことができます。
最後に、ページからフォームインスタンスを削除します。 繰り返しますが、ページ上に同じフォームの複数のインスタンスを簡単に作成できます。
たとえば、そのような形式でサーバーへの失敗した送信を表示できます。

ここにそのような解決策があります。


コメントや提案を待っています。 時間を見つけたら、JavaScriptで構文ハイライトコードを作成します(そして、Habréを手元に置いてみませんか?)。

Source: https://habr.com/ru/post/J59413/


All Articles