こんにちは、ハブラビテスさん!
今日、クライアント側で、サーバーと「対話」する機能なしに、GETパラメーターとURL全体をクライアント側で生成するタスクに直面しました。 すぐに予約をして、この記事を書く直前にこの投稿について知りました。最初に執筆を終えてから検索に頼ったので、その投稿は私のものと同じではないからです。
要するに。
挑戦と問題
問題は、上記で引用した投稿と同じです。
-
window.location
を使用してURLを「準備」できません。 - ブラウザのセキュリティポリシーにより、複数の
window.location
を一度に使用することはできません。 - よく知られている既製のソリューションの欠如(そして今では、しばらくして、同様のコードは見つかりませんでした)
自分のために設定したタスク:
- 便利な構文
- URLの一部を読み取り、それらを変更する機能
- GETパラメーターを使用する
- クロスブラウザーの互換性と汎用性
IE <9はこれを行う方法を知らないため、クロスブラウザー互換性のために、
prototype.__defineGetter__
または
prototype.__defineSetter__
を使用せずに、純粋なJavaScriptで
prototype.__defineSetter__
ました。 この投稿でゲッター/セッターの詳細をご覧ください。
興味のある方-私たちが座って、既製のソリューションを必要とする人-あなたは投稿の終わりに歓迎されています、ダウンロードリンクがあります。
さあ始めましょう!
コンストラクター
コンストラクターコード
var URL = function( param, param2 ){ param = param || false; param2 = ( param2 === false ) ? false : true; this.urlEncode = param2; this.data = { scheme: false, user: false, pass: false, host: false, port: false, path: false, query: false, params: {}, fragment: false }; if( typeof(param) == 'string' ){ this.url = param; this.parse(); } else if ( typeof(param) == 'object' ){ for(var key in param){ if( this.data.hasOwnProperty( key ) ){ if( param[ key ] || ( key == 'params' && typeof(param.params) == 'object' ) ) this.data[ key ] = param[ key ]; } } this.update(); } }
詳細
- 私が言ったように、普遍性が必要です。 つまり 不完全なURLを処理し、ゼロから作成することもできるため、ソースURLをコンストラクターに渡すか、適切なパラメーターを使用してハッシュを渡すか、まったく転送しないことができます。
- すべてのurlパラメーターはハッシュに保存されます(JSでは、パラメーターを持つオブジェクトにすぎません)。これは、ゲッター/セッターがこれについて少し後で説明するためです。 PHPの
parse_url()
スタイルで名前が付けられており、とても便利です。
解析
既存のURLを解析する必要があります。これは
RegExp
ます。 いいえ、もちろん
str.split()
ですべてを処理できますが、これは、私には思えるが、特別な種類のフェティシズムです。
regExp = /^(?:([a-z0-9_\-\.]+):\/\/)*(?:([a-z0-9_\-\.]+)(?:\:)*([a-z0-9_\-\.]+)*\@)*([a-z0-9][a-z0-9_\-\.]+)(?:\:([\d]+))*(?:\/([^?#]*))*(?:\?([^?#]*))*(?:\#([^?#]*))*/gi;
そして部分的に
-
(?:([a-z0-9_\-\.]+):\/\/)*
- ウィキペディアによると、スキームは://
ように見えます://
ここで、-
と_
両方があります。 普遍性のために、インストール済み*すなわち スキームが示されていない場合があります。 -
(?:([a-z0-9_\-\.]+)(?:\:)*([a-z0-9_\-\.]+)*\@)*
-ユーザー:パスワード、パスワードなしユーザー名はありませんが、パスワードのないユーザー名があります。 -
([a-z0-9][a-z0-9_\-\.]+)
-ホスト、私の知る限り、ドメイン名は文字/数字で始まり、その後-および_で始まり、さらに進むことができます。 さらに、6文字より短いドメイン名はありませんが、リンクはイントラネットワークにすることもできます。イントラネットワークでは、ホスト名を好きなように使用して、1つ以上の文字を入力します。 -
(?:\:([\d]+))*
-PORT、このパラメーターはオプションです::および数字 -
(?:\/([^?#]*))*
-PATH、ファイルへのパス、一般に、理論的には、これは任意の数の文字ですが、カットされますか? #GETパラメータまたはパスへのフラグメントポインターを解析しないようにします。 パスが示されていない可能性があります。 -
(?:\?([^?#]*))*
-クエリ、GETパラメータのセット、キー=値のペア。 省略することもできます。 -
(?:\#([^?#]*))*
-フラグメント、フラグメント化されたポインタ。 誰も知らない場合、//index.html#fragment
id="fragment"
はブラウザにid="fragment"
DOM要素までスクロールするよう指示します
もちろん、RegExpを理解するすべての言語で動作します。 使用して、恥ずかしがらないでください。
パーサー
parse: function(){ this.res = /^(?:([a-z0-9_\-\.]+):\/\/)*(?:([a-z0-9_\-\.]+)(?:\:)*([a-z0-9_\-\.]+)*\@)*([a-z0-9][a-z0-9_\-\.]+)(?:\:([\d]+))*(?:\/([^?#]*))*(?:\?([^?#]*))*(?:\#([^?#]*))*/gi.exec( this.url ); this.data.scheme = this.res[ 1 ] || false; this.data.user = this.res[ 2 ] || false; this.data.pass = this.res[ 3 ] || false; this.data.host = this.res[ 4 ] || false; this.data.port = this.res[ 5 ] || false; this.data.path = this.res[ 6 ] || false; this.data.query = this.res[ 7 ] || false; this.data.fragment = this.res[ 8 ] || false; if( this.data.query ){ this.parts = this.data.query.split( '&' ); for( var i = 0; i < this.parts.length; i++ ){ param = this.parts[ i ].split( '=' ); this.data.params[ param[ 0 ] ] = decodeURIComponent( param[ 1 ] ); } } delete this.res; delete this.parts; }
複雑なことは何もありません。上記のように
regExp
を分割し、
this.data
ハッシュにデータを保存します
前に言及した場合を
regExp
、urlのGETパラメーターを使用した便利な作業が必要です。したがって、split(この場合はsplit()は
regExp
よりも「安い」)を使用してクエリを中断し、同じ悪名高いハッシュに保存します。 GETパラメータはurlencodedであるため、decodeURIComponentの使用に注意する価値があります。
オプション1.「美」による
ゲッター/セッター
パラメータの読み取り/変更に関する便利な作業のために、JSウェイゲッターとセッターを選択することにしました。 Teは、プロパティの名前によるメソッドであり、メソッドがパラメーターで呼び出された場合はセッターであり、パラメーターがない場合はゲッターです。
メモリ内でメソッドの冗長インスタンスを生成しないように、
URL.prototype = { }
を介して
URL.prototype = { }
します。
例として1つ例を挙げます。これらは類似しているためです。
scheme: function( param ){ if( typeof( param ) != 'undefined' ){ this.data.scheme = param; return this.update(); } else { return this.data.scheme ? this.data.scheme : false; } }
値が変更された場合、
String
返されませんが、
Object
セッターチェーンを記述できるように行われます。
var url = new URL(); url.scheme('https').host('example.com').path('index.php').params({'p1':"v1", 'p2':"2"}).url; // : https://example.com/index.php?p1=v1&p2=%D0%B22
params
プロパティのゲッター/セッターについて個別に説明しましょう
params: function( param1, param2 ){ if( typeof( param1 ) != 'undefined' ){ if( typeof( param1 ) == 'string' ){ if( typeof( param2 ) != 'undefined' && ( param2 == '' || param2 === false ) ){ if( this.data.params.hasOwnProperty( param1 ) ){ delete this.data.params[ param1 ]; } } else if( typeof( param2 ) != 'undefined' ){ this.data.params[ param1 ] = param2; } else{ return this.data.params[ param1 ] ? this.data.params[ param1 ] : false; } } else if( typeof( param1 ) == 'object' ){ for( var key in param1 ){ if( typeof( param1[ key ] ) != 'undefined' && ( param1[ key ] == '' || param1[ key ] === false ) ){ if( this.data.params.hasOwnProperty( key ) ) delete this.data.params[ key ]; } else{ this.data.params[ key ] = param1[ key ]; } } } return this.update(); } else { return this.data.params ? this.data.params : false; } }
ご覧のとおり、両方のパラメーターはオプションです。
そして、私が言ったように-私は自分自身に目標を設定しました-GETパラメータを使用することの利便性、つまり次のことができるようになる必要があることを意味します。
- 読む
- 変更
- 削除する
単一のパラメーターおよびパラメーターのグループとして。
したがって、構文は次のようになります。
- 単一のパラメーターは渡されません-すべてのGETパラメーターを読み取ります
- 最初のパラメーターのみが渡されます-GETパラメーターを1つ読み取ります
- 2つのパラメーターが渡されます-名前
param1
と値param2
GETパラメーターを記述します - 空の値または
false
がパラメーター値として渡されます -指定されたGETパラメーターは削除されます
URLを元に戻す
お気づきのように、
this.update()
は
this.update()
で呼び出され、2つの機能を実行します。
- urlプロパティでURLを収集します
- GETパラメーターを操作するときに
query
プロパティを更新しquery
コレクターコード
update: function(){ this.data.query = ''; for( var key in this.data.params ){ this.data.query += this.urlEncode ? key+'='+encodeURIComponent( this.data.params[ key ] )+'&' : key+'='+this.data.params[ key ]+'&'; } if( this.data.query ) this.data.query = this.data.query.slice( 0, -1 ); this.url = ''; this.url += this.data.scheme ? this.data.scheme+'://' : ''; this.url += this.data.user ? this.data.user+':' : ''; this.url += this.data.pass ? this.data.pass+'@' : ''; this.url += this.data.host ? this.data.host+'/' : ''; this.url += this.data.path ? this.data.path : ''; this.url += this.data.query ? '?'+this.data.query : ''; this.url += this.data.fragment ? '#'+this.data.fragment : ''; return this; }
GETパラメーターをアセンブルするときに、パラメーター値がエスケープシーケンスに変換されることに注意してください。
最初:そうです。
第二に 、GETパラメーターを使用してユーザーが入力したデータを転送すると、ユーザーが挿入したアンパサンドによってキーと値のシーケンスが破壊され、すべてがタルタルになります。
さて、鼻からまっすぐに、あなたはurlencodedラインを必要としない場合-あなたは2つのオプションがあります:
コンストラクターに2番目のパラメーターを渡すfalse
- プロパティ
URL.urlEncode=false;
手動で設定しますURL.urlEncode=false;
- メソッド
URL.update();
呼び出しURL.update();
test = new URL({"path":"index.php", "params":{"param1":"value1", "param2":" &"}}, false); test.url; //index.php?param1=value1¶m2= & test2 = new URL({"path":"index.php", "params":{"param1":"value1", "param2":" &"}}); test2.url; //index.php?param1=value1¶m2=%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BF%D0%B0%D1%80%D0%B0%D0%BC%D0%B5%D1%82%D1%80%D0%B0%26 test2.urlEncode=false; test2.update().url; //index.php?param1=value1¶m2= &
まあ、それを便利にするために-生成されたリンクをたどる方法:
go: function(){ if(!this.data.scheme && this.data.host) this.data.scheme = 'http'; window.location.href = this.update().url; }
ご覧のとおり、スキームが指定されていないが、ホストが指定されている場合、
http
スキームが自動的に最も一般的なものとして置換されます。
次に、リンクが更新され、クリックされます。
文字列オブジェクトの拡張
理論的には、これで終了する可能性があります。 しかし、オブジェクトのインスタンスを明示的に作成せずに文字列変数を直接操作する方が便利だと思われました(ただし、奇妙に聞こえますが、JSにはクラスはありません)。
いつものように、1つの方法の例を示します。
String.prototype.scheme = function( param ){ var url = new URL( this.valueOf() ); if( typeof( param ) != 'undefined' ){ url.scheme( param ); result = url.url; } else{ result = url.scheme(); } delete url; return result; }
一般に、コードはURLオブジェクトの対応するメソッドにパラメーターを渡すだけです。
しかし、URLオブジェクトを作成および削除し、毎回1つのアクションのみを呼び出すことは奇妙に思えるかもしれません。このアクションは、実行される変数の値を変更しません。
これは、
String
オブジェクトの最も重要な不便なところです;既存の変数の値を変更することはできません。 何もできません。 常に新しい変数を作成してください。 したがって、新しいオブジェクトが作成され、
String
型の変数
String
返されるたびに。
チェーンはもちろんサポートされています:
url = 'example.com'; url.scheme('https').path('index.php').params({'p1':"v1", 'p2':"2"}); // : https://example.com/index.php?p1=v1&p2=%D0%B22
オプション2.「風水による」
たとえば、以前のバージョンが使用中の「美しい」場合、このオプションは簡潔になります。 コードと使用の両方の面で。
ゲッター/セッター
そのため、この場合のゲッター/セッターは、すべて、つまり完全に1つになります。
val: function( key, param, param2 ){ if( this.data.hasOwnProperty( key ) ){ if( typeof( param ) == 'undefined' ){ return this.data[ key ] ? this.data[ key ] : false; } else if( typeof( param ) != 'undefined' ){ if( key == 'params' ){ if( typeof( param ) == 'string' ){ if( typeof( param2 ) != 'undefined' ){ this.data[ key ][ param ] = param2; } else{ return this.data[ key ][ param ] ? this.data[ key ][ param ] : false; } } else if( typeof( param ) == 'object' ){ for( var keys in param ){ if( typeof( param[ keys ] ) != 'undefined' && ( param[ keys ] == '' || param[ keys ] === false ) ){ if( this.data[ key ].hasOwnProperty( keys ) ){ delete this.data[ key ][ keys ]; } } else{ this.data[ key ][ keys ] = param[ keys ]; } } } } else{ this.data[ key ] = param; } return this.update(); } } else return 'undefined'; }
文字列オブジェクトの拡張
状況は
String
オブジェクトの拡張でも同じです。コードが少ないだけです。 このメソッドは、パラメーターをURL.val()にのみ転送します。
まとめ
したがって、出力には、URLを適切に処理する機会を提供するライブラリがあり、URLの個々の部分を解析するだけでなく、変更することもできます。 これは、私の意見では、GETパラメーターを操作するための非常に便利なツールは言うまでもありません。
アプローチの長所と短所
オプション1
長所:
- 読みやすさ
- 使いやすい
短所:
- 8.75kb(圧縮および放電除去なし)
- 機能の一般的な小さな拡張のためのコードの360行
- 私がそう言うかもしれない-オプション2と比較して面倒
オプション2
長所:
- わずか144行のコード
- 重量4.25kb(圧縮および放電の除去なし)
- 設計のシンプルさと簡潔さ
短所:
- 少し読みにくい
以下の両方のオプションのソースをダウンロードできます:[ オプション1 || オプション2 ]。 ファイルが1つしかないため、githubに拡散する理由はありません。
サポート:
- はい、一般的に、
JavaSript
動作するすべての場所で、プラグインは純粋なネイティブJSで書かれているため、古いブラウザーではサポートされていないmagic
機能を使用しません。
そして、シムのために-私は私の休暇が私の投稿が誰かのためになることを心から願っています。
すべての良いコード、より多くの睡眠、そしてそのIEは人生を台無しにしません。