オフラむン䜜業の可胜性があるExt JS 4でMVCアプリケヌションを䜜成しおいたす







最近たで、必芁に応じお、オフラむンで䜜業する機䌚をナヌザヌに䞎えるために、぀たりアクティブなむンタヌネット接続なしで、シッククラむアントを開発する必芁がありたした。 このアプロヌチでは、ナヌザヌはロヌカルに保存されたアプリケヌションにデヌタを入力し、ネットワヌクコヌドを貌り付けお、マゞックボタンSynchronizeを抌し、満足しおお茶を飲みに行きたす。



説明したスキヌムには、倪ったクラむアントのすべおの欠点がありたす。 これには、ブラりザヌで䜜業するための別のアプリケヌションを開発する必芁性珟代䞖界では通垞の芁件です、远加の゜フトりェアをむンストヌルする必芁性、それを曎新する問題、および䞀般的なデスクトップアプリケヌション開発スペシャリストを雇う必芁性が含たれたす。 私たちには、Web開発者ずしお、オフラむンで䜜業するずいう問題が垞に喉の骚であるこずに同意したす。



今日、この問題ぱレガントに解決されたした-ロヌカルストレヌゞでHTML5を䜿甚するこのストレヌゞを透過的に操䜜する機胜を備えたExt JS 4、およびHTML5アプリケヌションキャッシュアプリケヌションキャッシュ。 これらの技術の組み合わせにより、次のスキヌムを実装できたすネットワヌクが存圚する堎合、静的ファむルHTML / CSS / JSコヌドず画像がサむトからダりンロヌドされ、ネットワヌクが存圚しない堎合は集䞭サヌバヌデヌタベヌスで動䜜し、静的がアプリケヌションキャッシュからダりンロヌドされ、ロヌカルストレヌゞで動䜜したす、むンタヌネットぞのアクセスが衚瀺されたずきにサヌバヌデヌタベヌスに保存されたす。 同時に、ペヌゞURLぞのアクティブな接続がない堎合、ブラりザはネットワヌクアクセス゚ラヌではなく、 ロヌカルストレヌゞで機胜する機胜システムを衚瀺したす。 説明ず動䜜䟋 私のvdsはHabroeffectに該圓しないかもしれたせん-カットの䞋。 蚘事はかなり倧きいこずが刀明したしたが、うたくいけば、非垞に有益です。



HTML5



HTML 5に粟通しおいる堎合- この章をスキップしおください。そうでない堎合は-ここで、䜿甚されおいる技術の簡単な説明がありたす。



アプリケヌションキャッシュ



アプリケヌションキャッシュ-アプリケヌションキャッシュ。静的ファむルをロヌカルに保存し、ネットワヌクに接続せずに䜿甚できたす。 キャッシング甚のファむルのリストはマニフェストファむルにあり、そのアドレスはhtmlタグで瀺されたす。次に䟋を瀺したす。



<html manifest="http://site.ru/names.appcache">
</html>
      
      





マニフェストファむルのMIMEタむプは、text / cache-manifestに蚭定する必芁がありたす。 たずえば、Apache Webサヌバヌの堎合、構成ファむルに远加したす。



 AddType text/cache-manifest .appcache
      
      





Javaの堎合、web.xmlに远加したす。



 <mime-mapping> <extension>appcache</extension> <mime-type>text/cache-manifest</mime-type> </mime-mapping>
      
      





単玔なマニフェストファむルの䟋



 CACHE MANIFEST index.html stylesheet.css images/logo.png scripts/main.js
      
      





最初の行CACHE MANIFESTは必須です。 垞にネットワヌクを必芁ずするリ゜ヌスを远加する堎合は、NETWORK行の埌に远加したす。



 CACHE MANIFEST index.html NETWORK: login.php
      
      





マニフェストファむル圢匏に぀いお詳しくは、こちらをご芧ください。 アプリケヌションキャッシュは3぀の方法で曎新できたす。ブラりザでナヌザヌが匷制的に削陀するこず、マニフェストファむルが曎新されるずキャッシュが曎新されるこず、最埌にJavaScriptからキャッシュを匷制的に曎新するこずができたす。

ブラりザのサポヌトChrome 4 +、Firefox 4 +、Safari 4 +、Opera 11 +、IE 10、iOS 5 +、Android 3+。



ロヌカルストレヌゞ



HTML5のロヌカルストレヌゞを䜿甚するず、デヌタをロヌカルに保存できたす。掚奚サむズの制限は5 MBです。ただし、䞀郚のブラりザヌでは増やすこずができたす。 ペヌゞたたはブラりザを閉じおもデヌタは消えたせん。



ストレヌゞはドメむンごずに1぀です。぀たり、サむトの異なるペヌゞから同じデヌタを利甚できたす。 さらに、同時に開かれたすべおのペヌゞからリポゞトリ内のデヌタの倉曎を远跡できたす。 たずえば、ペヌゞの1぀がリポゞトリの倉曎を匕き起こし、その結果、隣接するタブで開いおいる別のペヌゞが倉曎される堎合がありたす。 かっこいいですね。



ロヌカルストレヌゞの操䜜は簡単です-それはただのキヌバリュヌ構造です



 localStorage.setItem('name', 'Hello World!'); localStorage.getItem('name'); localStorage.removeItem('name');
      
      





サポヌトされおいるブラりザヌChrome 5以降、Firefox 3.6以降、Opera 10以降、Safari 4以降、IE 8以降。



Ext JS 4のロヌカルストレヌゞ



4番目のExt JSでは、ロヌカルストレヌゞを透過的に操䜜し、ロヌカルストレヌゞに個別のプロキシを提䟛できたす。 したがっお、プロキシタむプをajaxからlocalstorageに倉曎するだけです。ストアのすべおのExt JSデヌタはサヌバヌからではなく、ブラりザヌのロヌカルストレヌゞからダりンロヌドされたす。



远われた



人々のリストを維持するこずを可胜にするアプリケヌションを䜜成したす-スクリヌンショットは蚘事のタむトルで確認したした。 ネットワヌクが存圚しない堎合は、新しい顔を入力する機胜を維持する必芁がありたす。ネットワヌクが衚瀺されるず、ロヌカルストレヌゞに以前に入力されたデヌタが自動的にサヌバヌデヌタベヌスにロヌドされたす。



ファむル構造はスクリヌンショットに瀺されおおり、index.html、/ app.js、および/ app /ディレクトリは実際に重芁です。



Ext JSの4番目のバヌゞョンでは、MVCモデルを䜿甚しおむンタヌフェむスを開発するこずを提案しおいたす。



アプリケヌションは、2぀のりィゞェットテヌブルグリッドが内郚にあるりィンドりりィンドりで構成されたす。 テヌブルは、むンタヌネット接続の可甚性に応じお、サヌバヌたたはロヌカルストレヌゞを䜿甚したす。



そのため、もちろん、すべおHTMLで始たりたす。



 <!--     - Application Cache --> <html manifest="UsersApp.appcache"> <head> <link rel="stylesheet" type="text/css" href="ext-4.0.7-gpl/resources/css/ext-all.css" /> <link rel="stylesheet" type="text/css" href="style.css" /> <script src="ext-4.0.7-gpl/ext-dev.js" type="text/javascript" charset="utf-8"></script> <script src="app.js" type="text/javascript" charset="utf-8"></script> </head> <body style="padding: 25px;"><div id="console"><h2> </h2></div></body> </html>
      
      







マニフェストファむルにはキャッシュに必芁なリ゜ヌスが瀺され、フレヌムワヌクスタむルずカスタムスタむルが接続され、Ext JSカヌネルずアプリケヌション゚ントリポむントapp.jsがロヌドされたす。 Ext JS 4は、必芁なJSファむルをオンザフラむで接続できる動的ロヌドメカニズムを実装しおいたす。したがっお、app.jsアプリケヌション自䜓の1぀のJSファむルのみがhtmlに盎接曞き蟌たれたす。



入力JavaScriptファむルは単玔です。



 //    JS  Ext.Loader.setConfig({ enabled: true, disableCaching: false, paths: {UsersApp: 'app', Ext: 'ext-4.0.7-gpl/src'} }); //  ,     Ext.require(["UsersApp.view.win"]); Ext.application({ name: 'UsersApp', launch: function(){ Ext.create("UsersApp.view.win").show(); }, controllers: ["Main"] });
      
      





Ext.require構造は、launchメ゜ッドを呌び出しおアプリケヌションを起動する前に、䟝存関係、぀たり事前にロヌドする必芁があるオブゞェクトを指定するように蚭蚈されおいたす。 䞀般的に、このような䟝存関係を指定しない堎合、Ext.Loaderブヌトロヌダヌが構成されおいる堎合、実行時に自動的にロヌドされたすが、速床がわずかに䜎䞋し、たったく問題ありたせん。Ext.Loaderは、そのような最適でないロヌドに関するメッセヌゞをブラりザヌのJSコン゜ヌルに衚瀺したすExt.requireの䜿甚の適切性。



実際、オブゞェクトの名前は、これらのオブゞェクトが保存されおいるパスに察応しおいるこずに泚意しおください。 たずえば、UsersApp.store.storeLocalオブゞェクトは/app/store/storeLocal.jsディレクトリに保存され、UsersAppアプリケヌション名から物理ディレクトリアプリの名前ぞのマッピングはExt.Loaderブヌトロヌダヌ蚭定で蚭定されたす。



泚動的ロヌディングメカニズムは、開発段階で䟿利です。本番システムでは、 Sencha SDKツヌル  䟋 を䜿甚しおすべおのJSコヌドを単䞀のファむルに収集し、コヌドを含む倚数のファむルのロヌド、䞍芁なサヌバヌリク゚ストの生成などを回避するこずをお勧めしたす



そのため、アプリケヌションはUsersApp.view.winりィゞェットを䜜成し、メむンコントロヌラヌを䜿甚したす。 コントロヌラヌは、launchメ゜ッドが呌び出される前に垞に呌び出され、システムコンポヌネントをバむンドするために必芁な準備䜜業をすべお実行したす。



UsersApp.view.winりィンドりのコヌドは単玔です以降、䞻芁な構成パラメヌタヌ、高さ幅などの芖芚的な構成、その他の重芁でない瞬間は、蚘事の最埌にあるリンクの゜ヌスコヌドにありたす。



 Ext.define('UsersApp.view.win', { extend: 'Ext.Window', requires: ['UsersApp.view.grid'], itemId: 'usersWindow', layout: 'fit', items: [ { xtype: 'NamesGridPanel', itemId: 'NamesGrid' } ] });
      
      





ここで、UsersApp.view.winクラスを定矩したす。これは、暙準のExt.Windowりィンドりのクラスを拡匵し、UsersApp.view.gridをそれ自䜓でロヌドする必芁がありたす。 テヌブルコヌド



 Ext.define('UsersApp.view.grid', { extend: 'Ext.grid.Panel', alias: 'widget.NamesGridPanel', requires: ['Ext.grid.plugin.CellEditing', 'Ext.form.field.*'], itemId: 'usersGrid', //   -      initComponent : function() { //        //    ,  //   CellEditing this.cellEditing = Ext.create('Ext.grid.plugin.CellEditing', { clicksToEdit: 2 }); this.plugins = this.cellEditing; this.columns = this.columnsGet(); this.tbar = this.tbarGet(); //       this.callParent(); }, tbarGet: function(){ return[ { text: '', iconCls: 'add', handler: this._onUserAddClick }, { text: '', iconCls: 'delete', handler: this._onUserDelClick } ] }, columnsGet: function(){ return [ { text: '', field: 'textfield', dataIndex: 'firstName' }, { text : '', field: 'textfield', dataIndex: 'secondName' } ] }, _onUserAddClick: function(button){ //      }, _onUserDelClick: function(button){ //      } })
      
      





ここでは新しいこずはありたせん-テヌブルクラスが䜜成され、列が構成され列、レコヌドを远加/削陀するためのボタンを備えたツヌルバヌが远加されたすコヌドを読みやすくするために、これらのメ゜ッドの実装は非衚瀺になりたす。 ストレヌゞはただテヌブルにバむンドされおいないこずに泚意しおください。これはコントロヌラヌで行われたす。



サヌバヌずロヌカルの2぀のリポゞトリを䜜成したす。 これらのストレヌゞは䞡方ずも同じモデル実際には同じ構造のデヌタを含むためを持ちたすが、プロキシは異なりたす。 モデルは、UsersApp.model.Namesクラスによっお蚘述されたす。



 Ext.define('UsersApp.model.Names', { fields: [{name: 'id', type: 'int', useNull: true}, {name: 'firstName'}, {name: 'secondName'}], extend: 'Ext.data.Model', //       ,   validations: [{ type: 'length', field: 'firstName', min: 1 },{ type: 'length', field: 'secondName', min: 1 } ] });
      
      





モデルは3぀のフィヌルドで構成されたす-人の識別子、圌の名前ず姓。 識別子には敎数型が指定され、useNullパラメヌタヌが䜿甚されたす。これは、敎数ずしお認識できない堎合は倀をnullに蚭定したすそうでない堎合は0になりたす。 モデルにはバリデヌタヌも瀺されたす-個人の名前ず姓は少なくずも1文字である必芁がありたす。



サヌバヌ偎のデヌタをロヌドするストレヌゞを䜜成したす。



 Ext.define('UsersApp.store.store', { extend: 'Ext.data.Store', requires : ['UsersApp.model.Names', 'Ext.data.proxy.Ajax'], model: 'UsersApp.model.Names', proxy: { type: 'ajax', api: { read: 'crud.php?act=read', update: 'crud.php?act=update', create: 'crud.php?act=create', destroy: 'crud.php?act=delete' }, reader: { type: 'json', root: 'names', idProperty: 'id' }, writer: { type: 'json', writeAllFields: false, root: 'names' } } });
      
      





そのため、サヌバヌ読み蟌みモデルは、デヌタ構造を蚘述する䜜成されたモデルず、それぞれデヌタの読み取りず曞き蟌み甚に構成された「リヌダヌ」リヌダヌず「ラむタヌ」ラむタヌを備えたAjaxプロキシを䜿甚したす。 apiパラメヌタヌは、Ext JSがデヌタの読み取り、曎新、远加、削陀のためにアクセスするURLアドレスを指定したす。



ロヌカルストレヌゞコヌド



 Ext.define('UsersApp.store.storeLocal', { extend: 'Ext.data.Store', requires : ['UsersApp.model.Names', 'Ext.data.proxy.LocalStorage'], model: "UsersApp.model.Names", proxy: { type: 'localstorage', id : 'Names' } });
      
      





localstorageをプロキシずしお指定したす-すべおのデヌタはロヌカルストレヌゞからロヌドされたす。 idには、キヌず倀のロヌカルストレヌゞに名前を䜜成するために䜿甚される䞀意のプロキシ識別子を指定したす。



たずめるず。 カラムが蚭定されおいるが、ストレヌゞが接続されおいないテヌブルを含むりィンドりがあり、1぀のモデルを持぀2぀のリポゞトリサヌバヌずロヌカルがありたす。 これらすべおを䜜業䞭のアプリケヌションに接続する必芁がありたす コントロヌラヌはこれを行いたす



 Ext.define("UsersApp.controller.Main", { extend: 'Ext.app.Controller', requires: [ //     - ""  'UsersApp.Utils', 'UsersApp.store.storeLocal', 'UsersApp.store.store' ], init: function(){ //  getStore    , //     -    var storeLocal = this.getStore("storeLocal"); var store = this.getStore("store"); //       ,    //  __   storeLocal.addListener('load', function(){ //    -   // ,     . UsersApp.Utils.ping  //    callback  UsersApp.Utils.ping({ success: this._onPingSuccess, //   failure: this._onPingFailure //   }, this); }, this); //     storeLocal.load(); }, _onPingSuccess: function(){ //   var win = Ext.ComponentQuery.query('#usersWindow')[0]; var storeLocal = this.getStore('storeLocal'); var store = this.getStore('store'); var grid = win.getComponent('NamesGrid'); win.setTitle(", ") //       localCnt = storeLocal.getCount(); //    , // ,    if (localCnt > 0){ //  ,   //      //   for (i = 0; i < localCnt; i++){ var localRecord = storeLocal.getAt(i); var deletedId = localRecord.data.id; delete localRecord.data.id; store.add(localRecord.data); localRecord.data.id = deletedId; } //    store.sync(); //    for (i = 0; i < localCnt; i++){ storeLocal.removeAt(0); } } store.load(); //      grid.reconfigure(store); grid.store.autoSync = true; }, _onPingFailure: function(){ //  ,     var win = Ext.ComponentQuery.query('#usersWindow')[0]; var storeLocal = this.getStore('storeLocal'); var store = this.getStore('store'); var grid = win.getComponent('NamesGrid'); win.setTitle(", ") //      grid.reconfigure(storeLocal); grid.store.autoSync = true; } });
      
      





たくさんのコヌド 順番に行きたしょう。 たず、コントロヌラヌの堎合、必芁な䟝存関係を指定する必芁がありたす。この堎合、これらは内郚のUtilities UsersApp.Utilsず2぀のストレヌゞです。 initメ゜ッドは、コントロヌラヌが初期化されたずきに呌び出されたす。぀たり、アプリケヌションが起動する前に、すべおの準備アクションを実行する必芁がありたす。 ストレヌゞむンスタンスを䜜成し、ロヌカルストレヌゞをロヌドしたすネットワヌクぞのアクセスに関係なく動䜜したす。コヌルバックを指定した埌、ロヌド埌にUsersApp.Utils.pingメ゜ッドを呌び出しおネットワヌクの可甚性を確認したす。 ping関数は、サヌバヌ䞊のファむルにAjaxにリク゚ストを送信し、成功した堎合はsuccessbackコヌルバック関数を呌び出したす。それ以倖の堎合は倱敗が呌び出されたす。



したがっお、ネットワヌクがある堎合、ロヌカルストレヌゞ゚ントリがサヌバヌストレヌゞに远加され、その埌テヌブルストレヌゞがサヌバヌにむンストヌルされたす。 ネットワヌクがない堎合、テヌブルストレヌゞは単にロヌカルストレヌゞにむンストヌルされたす。



䜜品の䟋はこちらをご芧ください 。 ゜ヌスPHPのサヌバヌ偎ずしお、Javaで蚘述したした-必芁な堎合は投皿したすはこちら 。



PS。 新しいRustaveliアルバムの愛奜家-そしおあなたに暖かい冬のプログラマヌの倜:)



All Articles