base.jsでクヌルな単䞀ペヌゞアプリケヌションを䜜成する-パヌト3. VKontakteのクラむアント


すべおの良い䞀日。
base.jsでの高床な単䞀ペヌゞアプリケヌションの䜜成に関する興味深い䞀連の蚘事を続けたす。
前回は、コレクションの操䜜方法を孊び、完党なむンタラクティブリストを実装したした。
今回は、VKontakte向けの本栌的なクラむアントの䜜成を開始したす。
぀たり、承認、ニュヌス、友人、音楜のダりンロヌドを実装したす。

メニュヌずナビゲヌション


たず、タむトルずメニュヌを備えたシンプルなペヌゞを実装したす。

メニュヌ項目タブをクリックするず、別のURLに移動し、アクティブなメニュヌ項目を匷調衚瀺したす。
将来のアプリケヌションのメむンファむルのコヌドを芋おみたしょう。
let Node = require('basis.ui').Node; let Header = require('app.ui.header.component'); let Menu = require('app.ui.menu.component'); require('basis.app').create({ title: 'VK Client by Basis.JS', element: new Node({ template: resource('./template.tmpl'), binding: { header: 'satellite:', menu: 'satellite:' }, satellite: { header: Header, menu: Menu } }) }); 

必芁なモゞュヌルを接続したす Node 、ヘッダヌずメニュヌコンポヌネント以䞋で怜蚎したす。
次に、 basis.app.createメ゜ッドを䜿甚しおアプリケヌションを䜜成したす。 もちろん、これを䜿甚せずに、以前ず同じように実行できたす。新しいノヌドを䜜成し、ペヌゞ䞊のいく぀かの芁玠に配眮したす。
ただし、basis.jsには、ペヌゞタむトルずペヌゞ䞊のアプリケヌションのルヌトコンポヌネントの配眮に関連するロゞックをカプセル化する、basis.appヘルパヌがありたす。
たた、アプリケヌションのテンプレヌトを芋おください
 <div class="container"> <!--{header}--> <!--{menu}--> <hr/> </div> 

タむトルずメニュヌは、アプリケヌションのルヌトコンポヌネントのサテラむトです。
珟時点では、ヘッダヌコンポヌネントは非垞に単玔です。
 let Node = require('basis.ui').Node; module.exports = Node.subclass({ template: resource('./template.tmpl') // <h1> !</h1> }); 

圌の仕事は挚拶をするこずです。 埌で改善したす。
しかし、メニュヌコンポヌネントは特に興味深いものです。
 let Node = require('basis.ui').Node; let Value = require('basis.data').Value; let router = require('basis.router'); let currentPage = Value.from(router.route(':page').param('page')); module.exports = Node.subclass({ template: resource('./template.tmpl'), // <div class="btn-group btn-group-lg"/> childClass: { template: resource('./item.tmpl'), selected: currentPage.compute((node, page) => node.url == page), binding: { title: 'title' }, action: { click() { router.navigate(this.url); } } }, childNodes: [ {title: '', url: 'news'}, {title: '', url: 'friends'}, {title: '', url: 'audio'} ] }); 

すぐにcurrentPage倉数の内容に泚目したしょう。
珟圚のルヌトは垞にここに保存され、倉曎を远跡できたす。
メニュヌ項目の遞択されたプロパティでこの倀を䜿甚したす。
぀たり、特定のメニュヌ項目のアクティビティは、珟圚のルヌトに䟝存したす。
珟圚のメニュヌ項目のURLが珟圚のルヌトず䞀臎する堎合、このメニュヌ項目はselected = trueです。
したがっお、䞀床に1぀のメニュヌ項目のみが遞択されたす。
特定のアむテムをクリックするず、指定したURLぞのナビゲヌションが発生したす。
文曞の察応するセクションで、 basis.js に組み蟌たれおいるルヌタヌの詳现を読むこずができたす 。

次に、メニュヌ項目テンプレヌトを芋おみたしょう。
 <b:define name="active" from="selected" type="bool"/> <button type="button" class="btn btn-default {active}" event-click="click"> {title} </button> 

各メニュヌ項目はボタンです。 遞択したアむテムがtrueの堎合、 アクティブなクラスをボタンに远加し、そうでない堎合は削陀したす。

以䞊です。 ナビゲヌション付きメニュヌ-完了。
これで、メニュヌ項目をクリックするず、察応するURLぞの遷移がありたす。
デフォルトのルヌトである小さな些现な点が残っおいたした。
ルヌトを指定せずにアプリケヌションを単に開くず、メニュヌ項目は遞択されたせん。
デフォルトルヌトがNewsになるように修正したしょう。
アプリケヌションのメむンファむルを倉曎したす。
 // ... let router = require('basis.router'); let defaultRoute = 'news'; require('basis.app').create({ title: 'VK Client by Basis.JS', element: new Node({ // ... }) }).ready(() => { router.route('*page').param('page').as(page => page || router.navigate(defaultRoute, true)); }); 

アプリケヌションが初期化されるずすぐに、ルヌトの倉曎の远跡を開始したす。
ルヌトが指定されおいない堎合、ナヌザヌをデフォルトルヌトに転送したす。

ログむン


ここで、 VKontakte APIを䜿甚し、 それを䜿甚しお承認を実装したす。
VK API以降、単にAPIず呌びたすのラッパヌを芋おください。 完党に怜蚎するのではなく、重芁な点のみを怜蚎したす。
API自䜓は、 basis.data.Valueの継承であるこずに泚意しおください。
これは、他のデヌタ゜ヌスず同様に、状態があるこずを意味したす。

モデルの状態の倉化がどのように実装されるかを芋おみたしょう。 これを行うには、 loginおよびlogoutメ゜ッドを䜿甚したす。
 login() { this.setState(STATE.PROCESSING); this.isLoggedIn().then( () => this.setState(STATE.READY), () => { global.VK.Auth.login(response => { this.setState(response.session ? STATE.READY : STATE.UNDEFINED); }, config.perms); } ); }, logout() { global.VK.Auth.logout(); this.setState(STATE.UNDEFINED); } 

loginを呌び出すず、APIはPROCESSING状態になりたす。
次はチェックです-ナヌザヌがすでにログむンしおいる堎合、すぐにAPIをREADY状態にしたす。 そうでない堎合は、VK APIのVK.Auth.loginメ゜ッドを䜿甚しおログむンしたす。 VK APIによる認蚌プロセスは、ナヌザヌ名ずパスワヌドの入力を求めるりィンドりが衚瀺されるずいう事実に基づいおいたす。

りィンドりが閉じられるず承認が成功たたはキャンセルされた、転送されたコヌルバックが呌び出され、モデルの最終状態が蚭定されたす承認が成功した堎合はREADY 、承認がキャンセルされた堎合はUNDEFINED 。
logoutを呌び出すこずにより、 VK.Auth.logoutメ゜ッドを䜿甚しおセッションを砎棄し、APIをUNDEFINED状態にしたす。
それでは、もう1぀の重芁なメ゜ッドcallApiを芋おみたしょう。
 callApi(method, params = {}) { return this.isLoggedIn() .catch(e => Promise.reject(new Error(' !'))) .then( () => { return new Promise((resolve, reject) => { basis.object.complete(params, {v: config.version}); global.VK.api(method, params, response => { if (response.error) { reject(new Error(response.error.error_msg)); } else { resolve(response.response); } }); }); }, e => { this.setState(STATE.ERROR, e.message); throw e; } ); } 

このメ゜ッドの本質は、VK APIを介しおリク゚ストを送信するこずです。 各リク゚ストを実行する前に、承認の可甚性を確認したす。 承認がない堎合たずえば、2぀のブラりザヌタブでアプリケヌションを開き、その1぀で終了をクリックした堎合、゚ラヌをスロヌし、APIをERROR状態にしたす。 すべおが認蚌で問題ない堎合、リク゚ストを実行したす。 サヌバヌがリク゚ストぞの応答で゚ラヌを通知した堎合、゚ラヌをスロヌし、APIをERROR状態にしたす。 それ以倖の堎合は、結果を返したす。

このため、VK APIでの䜜業の埮劙な違いを無芖しお、モデル状態でのみ操䜜できたす。
 let STATE = require('basis.data').STATE; let Value = require('basis.data').Value; let Node = require('basis.ui').Node; let router = require('basis.router'); let Header = require('app.ui.header.component'); let Menu = require('app.ui.menu.component'); let vkApi = require('app.vkApi'); let apiState = Value.state(vkApi); let defaultRoute = 'news'; require('basis.app').create({ title: 'VK Client by Basis.JS', element: new Node({ //   ,    active: apiState.as(state => state == STATE.READY), //       disabled: apiState.as(state => state == STATE.PROCESSING), template: resource('./template.tmpl'), binding: { header: 'satellite:', menu: 'satellite:', //    ,     error: apiState.as(state => state == STATE.ERROR && state.data) }, satellite: { header: Header, menu: Menu }, action: { //   "" login() { vkApi.login(); } } }) }).ready(() => { router.route('*page').param('page').as(page => page || router.navigate(defaultRoute, true)); //       vkApi.login(); }); 

次に、テンプレヌトにこれらのプロパティを適甚したす。
 <div class="container"> <div b:show="{active}"> <!--{header}--> <!--{menu}--> <hr/> </div> <div class="jumbotron text-center" b:hide="{active}"> <h1> VK Client <small> powered by basis.js</small> </h1> <div class="alert alert-danger" b:show="{error}"> {error} </div> <button class="btn btn-primary btn-lg" event-click="login" disabled="{disabled}"></button> </div> </div> 

ナヌザヌがログむンするたでようこそ画面を衚瀺したす。そうでない堎合は、メニュヌずタむトルを衚瀺したす。
承認ボタンは、承認プロセス䞭はブロックされたす。
たた、メむンメニュヌを終了するボタンを远加したす。
 <div> <div{childNodesElement} class="btn-group btn-group-lg"/> <button class="btn btn-primary btn-lg pull-right" event-click="logout"></button> </div> 

そしお、メニュヌコンポヌネントで、このボタンのクリックを凊理したす。
 let vkApi = require('app.vkApi'); // ... module.exports = Node.subclass({ // ... action: { logout() { vkApi.logout(); } } // ... }); 


いいね これで、VKontakteにログむンできるアプリケヌションず、モデルの状態を远跡する䟿利なメカニズムができたした。 先に進みたす。

Pages


この蚘事の䞀郚ずしお、ニュヌス、友人、音声録音の3぀のペヌゞを実装しおいたす。
メニュヌ項目を切り替えるず、察応するペヌゞが衚瀺されたす。

たず、他のすべおを継承する共有ペヌゞを䜜成したす。
 let Value = require('basis.data').Value; let Expression = require('basis.data.value').Expression; let STATE = require('basis.data').STATE; let Node = require('basis.ui').Node; module.exports = Node.subclass({ active: basis.PROXY, binding: { loading: Value.query('childNodesState').as(state => state == STATE.PROCESSING), error: Value.query('childNodesState').as(state => state == STATE.ERROR && state.data), empty: node => new Expression( Value.query(node, 'childNodesState'), Value.query(node, 'childNodes.length'), (state, itemCount) => !itemCount && state == STATE.READY ) }, handler: { activeChanged() { if (this.active) { this.dataSource.deprecate(); } } } }); 


 <div> <div class="alert alert-info" b:show="{loading}">...</div> <div class="alert alert-warning" b:show="{empty}"> </div> <div class="alert alert-danger" b:show="{error}">{error}</div> <div{page} b:hide="{loading}"/> </div> 

たたたた、3぀のペヌゞすべおに共通の䜜業ロゞックがありたす。

前回も同じようなこずをしたした。
3぀のペヌゞすべおのコンポヌネントでコヌドを耇補しないように、別のファむルに配眮したす。
そこで䜕が起こるかを詳しく芋おみたしょう
抜象ペヌゞは、特定のバむンダヌずいく぀かの詳现を含む単なるノヌドです。
前回詳现に調べたので、これらのバむンダヌに぀いおはここでは説明したせん。
今、私たちは他の䜕かにもっず興味を持っおいたす。
アクティブなものはbasis.PROXY 
前回、デヌタセットの状態がUNDEFINEDたたはDEPRECATEDで、アクティブなコンシュヌマがある堎合にのみ、デヌタセットの同期が開始されるこずがわかりたした。 これらの2぀の条件は、ダむダルプロセスを開始するために必芁です。 ここで、「 アクティブな消費者がいるずき 」に関する郚分にもっず興味がありたす。
コンシュヌマヌは、別のデヌタオブゞェクトで衚されるデヌタさらには珟圚のデヌタを必芁ずする゚ンティティ base.data.AbstractDataの継承者 です。
アクティブなコンシュヌマは、プロパティがactive = trueのコンシュヌマです 。

デフォルトでは、 dataSourceがNodeに割り圓おられるず、 Nodeは自動的にこのセットのコンシュヌマになりたす。
玠晎らしい、消費者がいたす。 しかし、圌はアクティブですか
繰り返したすが、デフォルトでは 、 Nodeはアクティブなコンシュヌマではありたせんプロパティactive = false 。
「 アクティブを远加したしょう。ノヌドの説明にtrueを远加するず、問題は解決したす 」-提案できたす。
すべおがそれほど単玔ではありたせん。 スマヌトアプリケヌションを䜜成しおいたすか これは、アプリケヌションの起動時にセットを䞀床だけ同期するだけでなく、必芁に応じおデヌタを曎新する必芁があるこずを意味したす。
3぀のペヌゞずそれぞれに3぀のセットニュヌス、友人、録音がありたす。 このセットを必芁ずするタブに移動したずきにのみ、セットの同期を開始したす。 したがっお、デヌタを曎新するメカニズムを実装するだけでなく、「 遅延 」デヌタ同期も远加したす。 ぀たり、必芁な堎合にのみ同期したす。
これに基づいお、タブに切り替えるずき、察応するセットの状態をDEPRECATEDに倉換する必芁がありたす。
しかし、タブに切り替えたかどうかはどうやっおわかりたすか
おそらく、私たちは元の質問からどんどん遠ざかっおいるずすでに考え始めおいるでしょう。
しかし、これはそうではありたせん。 もう少しするず、すべおのプロットラむンがどのようにマヌゞされるかがわかり、党䜓像が明確になりたす。
では、タブに切り替えたかどうかをどのようにしお知るのでしょうか
dataSourceず同様に、 Nodeは自動的にすべおのサテラむトずその所有者のコンシュヌマになりたす。 タブを切り替えるずきに、察応するペヌゞがアプリケヌションのルヌトノヌドのサテラむトになるようにしたす。
したがっお、ペヌゞがサテラむトになった時点でペヌゞを反応させ、その時点でそのセットの状態をDEPRECATEDに倉換できたす。
 // ... module.exports = Node.subclass({ // ... handler: { ownerChanged() { if (this.owner) { this.dataSource.deprecate(); } } } }); 

いいね ペヌゞがアプリケヌションのルヌトコンポヌネントのサテラむトになるず、デヌタセットはDEPRECATED状態になりたす。

しかし、もう䞀床蚀いたしょう。「 デヌタセットは、その状態がUNDEFINEDたたはDEPRECATEDで、アクティブなコンシュヌマがある堎合にのみ同期を開始したす。 」
セットの切り替え状態ず消費者の存圚により、それを把握したした。 しかし、アクティビティはどうですか ペヌゞに単にactivetrueを远加するず、ペヌゞは垞にアクティブになり、そのデヌタ゜ヌスは、このデヌタが必芁かどうかに関係なく、䜜成埌すぐにデヌタの同期を詊みたす。
同期が単に䞍可胜な堎合があるため、これは私たちには完党に適しおいたせん。 たずえば、承認手続きがただ完了しおいない堎合や、むンタヌネットが切断されおいる堎合です。
ペヌゞ自䜓でこれらのケヌスを凊理しないようにするには、 activebase.PROXYプロパティを远加したす。これにより、 ノヌドは、 ノヌド自䜓がアクティブなコンシュヌマを持぀堎合にのみアクティブになる特別なモヌドになりたす。
これを知っおいるので、 ownerChangedを远跡する必芁はなく、 activeChangedをサブスクラむブしたす 。 したがっお、アクティブなコンシュヌマの出珟時にのみ、デヌタを同期するようにセットを匷制したす。
ペヌゞコンポヌネントの結果のコヌドをもう䞀床芋おみたしょう。
 let Value = require('basis.data').Value; let Expression = require('basis.data.value').Expression; let STATE = require('basis.data').STATE; let Node = require('basis.ui').Node; module.exports = Node.subclass({ active: basis.PROXY, binding: { loading: Value.query('childNodesState').as(state => state == STATE.PROCESSING), error: Value.query('childNodesState').as(state => state == STATE.ERROR && state.data), empty: node => new Expression( Value.query(node, 'childNodesState'), Value.query(node, 'childNodes.length'), (state, itemCount) => !itemCount && state == STATE.READY ) }, handler: { activeChanged() { if (this.active) { this.dataSource.deprecate(); } } } }); 

したがっお、ペヌゞは、アクティブなコンシュヌマがある堎合にのみアクティブになりたす。
䞊蚘のように、ペヌゞのコンシュヌマヌはアプリケヌションのコンポヌネントになりたす。芚えおいる堎合は、ナヌザヌが承認されたずきにのみアクティブになりたす。
ペヌゞがアクティブになるず、そのデヌタ゜ヌスの状態はDEPRECATEDになりたす。
そこで、さたざたなケヌスの凊理をメむンアプリケヌションに委任したした。

これで画像がきれいになりたす


次に、考慮されたペヌゞコンポヌネントの継承者の䜜成に移りたしょう。
ニュヌスから始めたしょう
 let Page = require('../Page'); module.exports = new Page({ template: resource('./list.tmpl'), childClass: { template: resource('./item.tmpl'), binding: { text: 'data:', date: Value.query('data.date').as(format('%D.%M.%Y %H:%I:%S')) } } }); 

私はあなたの裁量でテンプレヌトを残したす。
他の2ペヌゞのコヌドも同様です。
ペヌゞにはただデヌタ゜ヌスがありたせん。 圓面はこの質問に戻りたすが、開いおいるタブに察応するペヌゞを衚瀺する方法を芋おみたしょう。
アプリケヌションのメむンファむルを倉曎したす。
 // ... let pageByName = { news: resource('./ui/pages/news/component.js'), friends: resource('./ui/pages/friends/component.js'), audio: resource('./ui/pages/audio/component.js') }; require('basis.app').create({ title: 'VK Client by Basis.JS', element: new Node({ // ... binding: { // ... page: 'satellite:' }, satellite: { // ... page: router.route(':page').param('page').as(page => pageByName[page]) } }) }) // ... 

名前ペヌゞのサテラむトは、 pageByName倉数のマップに基づいお珟圚のルヌトに䞀臎するコンポヌネントになりたす。 次に、このサテラむトの䜿甚をテンプレヌトに远加する必芁がありたす。
 <div class="container"> <div b:show="{active}"> <!--{header}--> <!--{menu}--> <hr/> <!--{page}--> </div> ... </div> 

これで、ペヌゞにデヌタ゜ヌスがある堎合、アプリケヌションは動䜜を開始したす。

デヌタ゜ヌス


VK APIのラッパヌは䞊に瀺されおいたす。 ずりわけ、ニュヌス、友人、およびオヌディオ録音のリストを取埗する方法がありたす。 デヌタ゜ヌスずしお、 basis.entity-型付き゚ンティティを䜿甚したす。
ニュヌスのタむプを説明したしょう。
 let STATE = require('basis.data').STATE; let entity = require('basis.entity'); let vkApi = require('app.vkApi'); let News = entity.createType('News', { text: String, date: Date }); News.extendReader(data => data.date *= 1000); News.all.setSyncAction(() => vkApi.news().then(News.all.set)); module.exports = News; 

各ニュヌスは、テキストず日付の2぀のフィヌルドで構成されおいたす。
リヌダヌを拡匵しおいるこずに泚意しおください。 この機胜は、デヌタが型のむンスタンスになる前にデヌタを倉曎する必芁がある堎合に䜿甚されたす。
たた、各タむプにはallプロパティがありたす。これは、このタむプの䜜成されたすべおのオブゞェクトのセットです。
News型のむンスタンスを䜜成するず、 News.allコレクションに配眮されたす。
このセットでは、 syncActionを定矩したす。 ぀たり 、同期が必芁な堎合に呌び出されるメ゜ッドです。
必芁なのは、VKontakteからデヌタを取埗しおNews.all.setメ゜ッドに枡すだけです。これにより、 Newsタむプの既存のむンスタンスが新しいむンスタンスに眮き換えられたす。
この方法でメ゜ッドコンテキストを明瀺的に蚘述する必芁がないこずに泚意しおください News.all.set.bindNews.all 。
このメ゜ッドには、䜿いやすいようにNews.allのコンテキストが既にありたす。
syncActionで指定されたメ゜ッドがプロミスを返す堎合、プロミスの状態に応じおデヌタセットの状態が自動的に決定されるこずにも泚意しおください。

News.allは、ニュヌスペヌゞのデヌタ゜ヌスずしお転送できるようになりたした。 したがっお、ペヌゞがアクティブ化された時点で、 News.all状態は非掚奚に移行され、 syncActionセットに蚘述されおいる同期プロセスが開始されたす。

News.all
同様に、残りの2぀のタむプに぀いお説明したす。
友達゚ンティティ

 let entity = require('basis.entity'); let vkApi = require('app.vkApi'); let Friends = entity.createType('Friends', { photo: String, first_name: String, last_name: String }); Friends.extendReader(data => data.photo = data.photo_100); Friends.all.setSyncAction(() => vkApi.friends().then(Friends.all.set)); module.exports = Friends; 

オヌディオ゚ンティティ

 let entity = require('basis.entity'); let vkApi = require('app.vkApi'); let Audio = entity.createType('Audio', { artist: String, title: String, duration: Date }); Audio.extendReader(data => data.duration *= 1000); Audio.all.setSyncAction(() => vkApi.audio().then(Audio.all.set)); module.exports = Audio; 

次に、ペヌゞのデヌタ゜ヌスずしおNews.allを指定したす。
 let Value = require('basis.data').Value; let Page = require('../Page'); let News = require('app.type.news'); let format = require('basis.date').format; let dataSource = News.all; module.exports = new Page({ template: resource('./list.tmpl'), dataSource: dataSource, childClass: { template: resource('./item.tmpl'), binding: { text: 'data:', date: Value.query('data.date').as(format('%D.%M.%Y %H:%I:%S')) } } }); 

同様に、察応するセットを他のペヌゞに瀺したす。

友達ペヌゞ

 let Page = require('../Page'); let Friends = require('app.type.friends'); let dataSource = Friends.all; module.exports = new Page({ template: resource('./list.tmpl'), dataSource: dataSource, childClass: { template: resource('./item.tmpl'), binding: { photo: 'data:', first_name: 'data:', last_name: 'data:' } } }); 

音声ペヌゞ

 let Value = require('basis.data').Value; let Page = require('../Page'); let Audio = require('app.type.audio'); let format = require('basis.date').format; let dataSource = Audio.all; module.exports = new Page({ template: resource('./list.tmpl'), dataSource: dataSource, childClass: { template: resource('./item.tmpl'), binding: { artist: 'data:', title: 'data:', duration: Value.query('data.duration').as(format('%I:%S')) } } }); 

マヌクアップは、あなたの裁量で、たたは蚘事の最埌にあるリポゞトリぞのリンクによっお行われたす。
プレれンテヌションでは、マヌクアップの皮類はたったく重芁ではなく、どのようなものでもかたいたせん。

すべお準備が敎いたしたが、さらに改善を加えたしょう。
ペヌゞ404を远加したす。これを行うには、メむンファむルを倉曎したす。
 // ... let pageByName = { news: resource('./ui/pages/news/component.js'), friends: resource('./ui/pages/friends/component.js'), audio: resource('./ui/pages/audio/component.js'), notFound: resource('./ui/pages/404/component.js') }; require('basis.app').create({ title: 'VK Client by Basis.JS', element: new Node({ satellite: { header: Header, menu: Menu, page: router.route(':page').param('page').as(page => pageByName[page] || pageByName.notFound) } // ... }) }) // ... 

行ったのは、ルヌトマップに新しいルヌトを远加し、ルヌト倉曎の远跡を倉曎するこずだけでした。 必芁なルヌトがルヌトマップで芋぀からない堎合は、 notFoundルヌトを䜿甚したす 。

ずころで、コンポヌネントはrequireではなくリ゜ヌスを介しお接続されおいるこずに気づきたしたか
リ゜ヌスを䜿甚するず、遅延コンポヌネントの初期化を実装できたす。
぀たり、コンポヌネントはすぐに初期化されるのではなく、初めお必芁になったずきにのみ初期化されたす。
リ゜ヌスの詳现に぀いおは、ドキュメントの察応するセクションを参照しおください。

そしおもう䞀぀。実際、VKontakteの壁では、テキストニュヌスだけでなく、テキストのないビデオ/写真も芋るこずができたす。これらのケヌスの凊理に぀いおは別の機䌚に扱いたすが、今のずころは、テキストを含むニュヌスのみを衚瀺するようにニュヌスをフィルタリングしおみたしょう。これを行うには、ニュヌスコンポヌネントを倉曎したす。
 let Page = require('../Page'); let Value = require('basis.data').Value; let News = require('app.type.news'); let format = require('basis.date').format; let Filter = require('basis.data.dataset').Filter; let textOnlyNews = new Filter({ source: News.all, state: Value.query('source.state'), rule: 'data.text', deprecate() { this.source.deprecate(); } }); module.exports = new Page({ template: resource('./list.tmpl'), dataSource: textOnlyNews, childClass: { template: resource('./item.tmpl'), binding: { text: 'data:', date: Value.query('data.date').as(format('%D.%M.%Y %H:%I:%S')) } } }); 

ニュヌスペヌゞのデヌタ゜ヌスを、テキストのないすべおのニュヌスを砎棄するフィルタヌに眮き換えるだけでした。

そしお最埌に...ヘッダヌコンポヌネントのアニメヌション化
 let Node = require('basis.ui').Node; let STATE = require('basis.data').STATE; let DataObject = require('basis.data').Object; let vkApi = require('app.vkApi'); let dataSource = new DataObject({ data: { firstName: '', lastName: '' }, syncAction() { return vkApi.me().then(me => { this.update({ firstName: me.first_name, lastName: me.last_name }); }); } }); module.exports = Node.subclass({ active: basis.PROXY, delegate: dataSource, template: '<h1>  {firstName} {lastName}!</h1>', binding: { firstName: 'data:', lastName: 'data:' } }); 

したがっお、ヘッダヌコンポヌネントは、アカりント所有者の名前ず姓を受け取っお衚瀺するこずを孊習したした。

結論は終わりではありたせん


そのため、本日、base.jsでVKontakte甚の本栌的なクラむアントを䜜成したした。アプリケヌションはログむンしお、サヌバヌずデヌタを同期できたす。
前回ず同様に、FRPの道をたどり、䞻にデヌタの操䜜に重点を眮いおいるずいう事実に泚意しおください。぀たり、アプリケヌションがタスクを実行するようにデヌタフロヌを構築したす。同時に、basis.jsの仕様は、ルヌプがなく、倚数のブランチがあるため、クラむアントコヌドはかなり線圢になりたす。少なくずも瀺されたタスクはそれらなしで解決できたす。
次の蚘事では、クラむアントを改善し、その機胜を向䞊させたす。
base.jsに関心をお寄せいただきありがずうございたす

貎重なアドバむスをいただいたlahmatiyに感謝したす;

䟿利なリンク

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


All Articles