成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Rxjs 響應(yīng)式編程-第六章 使用Cycle.js的響應(yīng)式Web應(yīng)用程序

EastWoodYang / 2710人閱讀

摘要:我們將使用,這是一個現(xiàn)代,簡單,漂亮的框架,在內(nèi)部使用并將響應(yīng)式編程概念應(yīng)用于前端編程。驅(qū)動程序采用從我們的應(yīng)用程序發(fā)出數(shù)據(jù)的,它們返回另一個導(dǎo)致副作用的。我們將使用來呈現(xiàn)我們的應(yīng)用程序。僅采用長度超過兩個字符的文本。

Rxjs 響應(yīng)式編程-第一章:響應(yīng)式
Rxjs 響應(yīng)式編程-第二章:序列的深入研究
Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序
Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整的Web應(yīng)用程序
Rxjs 響應(yīng)式編程-第五章 使用Schedulers管理時間
Rxjs 響應(yīng)式編程-第六章 使用Cycle.js的響應(yīng)式Web應(yīng)用程序

使用Cycle.js的反應(yīng)式Web應(yīng)用程序

隨著單頁應(yīng)用程序的出現(xiàn),網(wǎng)站突然被期望做更多,甚至與“原生”應(yīng)用程序進(jìn)行競爭。在嘗試更快地開發(fā)Web應(yīng)用程序時,開發(fā)人員意識到特定領(lǐng)域是瓶頸,使Web應(yīng)用程序不像其本地應(yīng)用程序那樣快速和強大。

在Facebook React的帶領(lǐng)下,有幾個Web框架正在使用著新技術(shù),以便在保持代碼簡單和聲明式的同時制作更快的Web應(yīng)用程序。

在本章中,我們將介紹一些開發(fā)Web應(yīng)用程序的新技術(shù),例如Virtual DOM。 我們將使用Cycle.js,這是一個現(xiàn)代,簡單,漂亮的框架,在內(nèi)部使用RxJS并將響應(yīng)式編程概念應(yīng)用于前端編程。

Cycle.js

Cycle.js是RxJS之上的一個小框架,用于創(chuàng)建響應(yīng)式用戶界面。 它提供了現(xiàn)代框架(如React)中的功能,例如虛擬DOM和單向數(shù)據(jù)流。

Cycle.js以反應(yīng)方式設(shè)計,Cycle.js中的所有構(gòu)建塊都是Observables,這給我們帶來了巨大的優(yōu)勢。 它比其他框架更容易掌握,因為理解和記憶的概念要少得多。 例如,與狀態(tài)相關(guān)的所有操作都不在路徑中,封裝在稱為驅(qū)動程序的函數(shù)中,我們很少需要創(chuàng)建新的操作。

什么是虛擬DOM?

文檔對象模型(DOM)定義HTML文檔中元素的樹結(jié)構(gòu)。 每個HTML元素都是DOM中的一個節(jié)點,每個節(jié)點都可以使用節(jié)點上的方法進(jìn)行操作。

DOM最初是為了表示靜態(tài)文檔而創(chuàng)建的,而不是我們今天擁有的超級動態(tài)網(wǎng)站。 因此,當(dāng)DOM樹中的元素經(jīng)常更新時,它的設(shè)計并不具有良好的性能。 這就是為什么當(dāng)我們對DOM進(jìn)行更改時會出現(xiàn)性能損失。

虛擬DOM是用JavaScript的DOM的映射。 每次我們更改組件中的狀態(tài)時,我們都會為組件重新計算一個新的虛擬DOM樹,并將其與之前的樹進(jìn)行比較。 如果存在差異,我們只會渲染這些差異。 這種方法非???,因為比較JavaScript對象很快,我們只對“真正的”DOM進(jìn)行絕對必要的更改。

這種方法意味著我們可以編寫代碼,就好像我們?yōu)槊總€更改生成了整個應(yīng)用程序UI。 我們不必跟蹤DOM中的狀態(tài)。 在幕后,Cycle.js將檢查每次更新是否有任何不同,并負(fù)責(zé)有效地渲染我們的應(yīng)用程序。

安裝Cycle.js

我們可以通過使用標(biāo)記將它包含在HTML頁面中來使用Cycle.js,但這不是使用它的最佳方式,因為Cycle.js是以極其模塊化的方式設(shè)計的。 每個模塊都盡可能地自我依賴管理,并且包括幾個模塊。因為可以輕松加載大量重復(fù)代碼,從而導(dǎo)致不必要的下載和更長的啟動時間。

相反,我們將使用Node Package Manager,npm和Browserify為我們的最終腳本生成代碼。 首先,我們將創(chuàng)建一個項目將存在的新文件夾,并安裝我們的項目依賴項:

mkdir wikipedia-search && cd wikipedia-search
npm install browserify
npm install @cycle/core
npm install @cycle/dom

第一個npm命令安裝Browserify,它允許我們?yōu)闉g覽器編寫代碼,就像它是Node.js應(yīng)用程序一樣。 使用Browserify,我們可以使用Node.js的模塊加載器,它將明智地包含哪些依賴項,使代碼下載盡可能小。 接下來,我們安裝了cycle-core和cycle-dom,它們是Cycle.js的兩個基本模塊。

有了這個,我們可以創(chuàng)建一個名為index.js的文件,我們將編輯我們的應(yīng)用程序,然后使用本地Browserify二進(jìn)制文件將其編譯成一個名為bundle.js的文件:

touch index.js
`npm bin`/browserify index.js --outfile bundle.js

上面的命令將遍歷我們的依賴樹并創(chuàng)建一個bundle.js文件,其中包含運行我們的應(yīng)用程序所需的所有內(nèi)容,包括我們在代碼中需要的任何依賴項。 我們可以在index.html中直接包含bundle.js:

cycle/index.html



    
        
        Wikipedia search
    
    
        
我們的項目:維基百科搜索

在本節(jié)中,我們將構(gòu)建一個搜索Wikipedia作為用戶類型的應(yīng)用程序。

RxJS已經(jīng)使得檢索和處理遠(yuǎn)程數(shù)據(jù)變得容易了,但是,正如第4章“構(gòu)建完整的Web應(yīng)用程序”中所看到的那樣,我們?nèi)匀恍枰^一些環(huán)節(jié)來使我們的DOM操作高效。

Cycle.js的目標(biāo)之一是完全消除代碼中的DOM操作。 讓我們從一些基本的腳手架開始:

cycle/step1.js

var Cycle = require("@cycle/core");
? var CycleDOM = require("@cycle/dom")
var Rx = Cycle.Rx;
? function main(responses) {
    return {
        DOM: Rx.Observable.just(CycleDOM.h("span", "Hi there!"))
    };
}
var drivers = {
? DOM: CycleDOM.makeDOMDriver("#container")
};
? Cycle.run(main, drivers);

這段代碼在屏幕上顯示文字hi!,但已經(jīng)有相當(dāng)多的事情發(fā)生了。 重要的部分是主要功能和驅(qū)動對象。 我們來看看這些步驟:

我們需要Cycle Core和Cycle DOM驅(qū)動程序。 我將在下一節(jié)中解釋Cycle.js驅(qū)動程序的內(nèi)容。

主要功能始終是我們應(yīng)用程序的入口點。 它返回一組Observable,一個用于應(yīng)用程序中的每個驅(qū)動程序。 到目前為止,我們只使用一個驅(qū)動程序:DOM驅(qū)動程序。
DOM驅(qū)動程序的Observable發(fā)出一個虛擬樹,我們使用Cycle DOM庫中的h方法創(chuàng)建。 在這種情況下,我們只創(chuàng)建一個帶有“Hi there!”文本的span元素。 DOM驅(qū)動程序使用該虛擬樹并從中呈現(xiàn)頁面上的實際DOM。

我們創(chuàng)建一個DOM驅(qū)動程序,它將根據(jù)main函數(shù)構(gòu)建DOM樹。 DOM樹將構(gòu)建在我們作為參數(shù)傳遞的元素或選擇器中。 在這里傳的是#container。

Cycle.run將main函數(shù)與drivers對象連接起來,在兩者之間創(chuàng)建循環(huán)流。

Cycle.js驅(qū)動程序

Cycle.js驅(qū)動程序是我們用來引起副作用的函數(shù)。在我們的程序中,我們應(yīng)該以任何方式修改狀態(tài)。驅(qū)動程序采用從我們的應(yīng)用程序發(fā)出數(shù)據(jù)的Observable,它們返回另一個導(dǎo)致副作用的Observable。

我們不會經(jīng)常創(chuàng)建驅(qū)動程序 - 只有當(dāng)我們需要副作用時,例如修改DOM,從其他接口讀取和寫入(例如,本地存儲)或發(fā)出請求。 在大多數(shù)應(yīng)用程序中,我們只需要DOM驅(qū)動程序(呈現(xiàn)網(wǎng)頁)和HTTP驅(qū)動程序(我們可以使用它來發(fā)出HTTP請求)。 在這個例子中,我們將使用另一個JSONP驅(qū)動程序。

用戶界面

我們需要頁面的實際內(nèi)容,而不僅僅是span。 讓我們創(chuàng)建一個函數(shù)來創(chuàng)建代表我們頁面的虛擬樹:

cycle/index.js

function vtreeElements(results) {
    var h = CycleDOM.h;
    return h("div", [
        h("h1", "Wikipedia Search "),
        h("input", {className: "search-field", attributes: {type: "text"}}),
        h("hr"),
        h("div", results.map(function(result) {
            return h("div", [
                h("a", { href: WIKI_URL + result.title }, result.title)
            ]);
        }))
    ]);
}

這個功能可能看起來有點奇怪,但不要驚慌。 它使用Virtual Hyperscript,一種用于創(chuàng)建虛擬DOM樹的特定于域的語言。 Virtual Hyperscript包含一個名為h的方法。 h以類似于HTML的方式聲明節(jié)點,但使用JavaScript語言。我們可以通過將額外的對象或數(shù)組作為參數(shù)傳遞給h來向元素添加屬性或?qū)⒆釉馗郊拥剿鼈?。生成的虛擬樹最終將呈現(xiàn)為真正的瀏覽器DOM。

vtreeElements獲取一組對象,結(jié)果,并返回一個虛擬樹,代表我們應(yīng)用程序的簡單UI。 它呈現(xiàn)一個輸入字段和一個由結(jié)果中的對象組成的鏈接列表,最終將包含Wikipedia的搜索結(jié)果。 我們將使用vtreeElements來呈現(xiàn)我們的應(yīng)用程序。

使用JSX

我們可以使用JSX編寫我們的UI,而不是使用h函數(shù),JSX是一種由Facebook發(fā)明的類似XML的語法擴展,它使得編寫虛擬DOM結(jié)構(gòu)更容易,更易讀。 我們的vtreeElements函數(shù)看起來像這樣:

cycle/index.js

function vtreeElementsJSX(results) {
    results = results.map(function(result) {
        var link = WIKI_URL + result.title;
        return 
    });
    return 

Wikipedia Search


{results}
; }

它看起來不是更好嗎?JSX看起來對開發(fā)人員來說比較熟悉,因為它類似于HTML,但是我們可以將它與JavaScript代碼一起編寫,并且我們可以將其視為JavaScript類型。 例如,注意我們?nèi)绾蔚Y(jié)果數(shù)組,我們直接返回一個

元素,使用數(shù)組元素本身中的link和result.title的值。(可以通過將它們放在大括號內(nèi)來內(nèi)聯(lián)JavaScript值。)

由于JSX是一種語法擴展,我們需要一個編譯器將其轉(zhuǎn)換為最終的JavaScript代碼(它看起來非常像我們上一節(jié)中基于h的代碼)。 我們將使用Babel。 Babel是一個編譯器,它將現(xiàn)代JavaScript轉(zhuǎn)換為可在任何地方運行的JavaScript。它還轉(zhuǎn)換了一些JavaScript擴展,例如JSX,也就是之前的用例。

如果要使用JSX,則需要安裝Babel并在編譯項目時使用它。 幸運的是,Babel有一個名為Babelify的Browserify適配器:

npm install babelify

在每個使用JSX的文件中,我們需要在文件頂部添加以下行:

/** @jsx hJSX */
var hJSX = CycleDOM.hJSX;

這告訴Babel使用Cycle.js的hJSX適配器來處理JSX,而不是使用默認(rèn)的React。

現(xiàn)在,當(dāng)我們想要編譯項目時,我們可以使用以下命令:

browserify index.js -t babelify --outfile bundle.js
從用戶那里獲取搜索關(guān)鍵詞

我們需要一個函數(shù)來返回一個Observable of URL,它使用用戶輸入的搜索詞來查詢Wikipedia的API:

cycle/index.js

var MAIN_URL = "https://en.wikipedia.org"; 
var WIKI_URL = MAIN_URL + "/wiki/";
var API_URL = MAIN_URL + "/w/api.php?" +
"action=query&list=search&format=json&srsearch=";

function searchRequest(responses) {
    return responses.DOM.select(".search-field").events("input")
    .debounce(300)
    .map(function(e) { 
        return e.target.value 
        
    })
    .filter(function(value) { 
        return value.length > 2 
        
    }) 
    .map(function(search) { 
        return API_URL + search 
    });
}

首先,我們聲明一些我們的應(yīng)用程序?qū)⒂糜诓樵僕ikipedia的URL。 在函數(shù)searchRequest中,我們獲取包含應(yīng)用程序中所有驅(qū)動程序的響應(yīng)對象,并在DOM驅(qū)動程序中使用get方法。select(element).event(type)的行為與fromEvent類似:它采用DOM元素的選擇器和要監(jiān)聽的事件類型,并返回發(fā)出事件的Observable。

這時,代碼的其余部分看起來應(yīng)該非常熟悉,因為它包含通過我們常用的運算符轉(zhuǎn)換Observable值:

節(jié)流結(jié)果最多每300毫秒接收一個。

提取輸入框的值。

僅采用長度超過兩個字符的文本。

將最終值附加到Wikipedia的API URL。

太棒了! 到目前為止,我們有生成UI的功能和從該UI檢索用戶輸入的功能。我們現(xiàn)在需要添加將從維基百科獲取信息的功能。

修改我們的主要功能

你可能已經(jīng)在之前的代碼中注意到main函數(shù)接受了一個我們沒有使用的參數(shù),responses。這些是來自run函數(shù)中的responses。驅(qū)動程序和main函數(shù)形成一個循環(huán)(因此框架的名稱):main的輸出是驅(qū)動程序的輸入,驅(qū)動程序的輸出是main的輸入。請記住,輸入和輸出始終是Observables。

我們使用JSONP查詢Wikipedia,就像我們在第2章中所做的那樣。我們使用JSONP而不是HTTP來更容易在本地計算機上運行此示例,因為使用HTTP從不同的域檢索數(shù)據(jù)會導(dǎo)致某些瀏覽器因為安全原因阻止這些請求。 在幾乎任何其他情況下,尤其是在生產(chǎn)代碼中,使用HTTP來檢索遠(yuǎn)程數(shù)據(jù)。

無論如何,使用JSONP并不影響本章的要點。 Cycle有一個JSONP的實驗?zāi)K,我們可以使用npm安裝它:

npm install @cycle/jsonp

然后我們在我們的應(yīng)用中使用它,如下所示:

cycle/step2.js

var Cycle = require("@cycle/core");
var CycleDOM = require("@cycle/dom");
var CycleJSONP = require("@cycle/jsonp");
var Rx = Cycle.Rx; var h = CycleDOM.h;
function searchRequest(responses) {
    return responses.DOM.select(".search-field").events("input")
    .debounce(300)
    .map(function(e) { return e.target.value }) .filter(function(value) { 
        return value.length > 2 }) .map(function(search) { 
            return API_URL + search 
        });
}

function vtreeElements(results) { 
    return h("div", [
        h("h1", "Wikipedia Search "),
        h("input", {className: "search-field", attributes: {type: "text"}}), h("hr"),
        h("div", results.map(function(result) {
        return h("div", [
        h("a", { href: WIKI_URL + result.title }, result.title)
        ]); }))
    ]); 
}

function main(responses) { 
    return {
        DOM: Rx.Observable.just(CycleDOM.h("span", "Hey there!")), 
        JSONP: searchRequest(responses)
    }
}

var drivers = {
    DOM: CycleDOM.makeDOMDriver("#container"), JSONP: CycleJSONP.makeJSONPDriver()
};

Cycle.run(main, drivers);

我們希望將searchRequest的結(jié)果插入到JSONP方法中,這樣一旦用戶輸入搜索詞,我們就會用術(shù)語查詢Wikipedia。

為此,我們使用CycleJSONP.makeJSONPDriver創(chuàng)建一個新的JSONP,它將接收我們在main的返回對象中放置在屬性JSONP中的任何內(nèi)容。在這之后,當(dāng)我們在輸入框中引入搜索詞時,我們應(yīng)該已經(jīng)在查詢維基百科,但由于我們沒有將JSONP輸出連接到任何內(nèi)容,我們在頁面上看不到任何更改。 讓我們改變一下:

cycle/step3.js

function main(responses) {
    var vtree$ = responses.JSONP
    .filter(function(res$) {
        return res$.request.indexOf(API_URL) === 0;
    })
    .mergeAll() 
    .pluck("query", "search") 
    .startWith([]) 
    .map(vtreeElements);
    
    return {
        DOM: vtree$,
        JSONP: searchRequest(responses)
    }; 
}

main通過其響應(yīng)參數(shù)接收所有驅(qū)動程序的輸出。我們可以在respond.JSONP中獲取JSON調(diào)用的結(jié)果,這是我們應(yīng)用程序中所有JSONP響應(yīng)的Observable。完成后,我們可以轉(zhuǎn)換Observable以我們想要的形式獲取搜索結(jié)果:

esponses.JSONP會在應(yīng)用程序中發(fā)出所有JSONP響應(yīng)。 我們首先在其請求中過濾包含Wikipedia的API URL的內(nèi)容,以確保我們正在處理相關(guān)的響應(yīng)。

respond.JSONP是一個Observable of Observables。 對于每個響應(yīng),都有一個Observable。 在這一行中,我們將它們?nèi)空蛊剑虼宋覀儚默F(xiàn)在開始處理響應(yīng),而不是它們的Observables。

響應(yīng)是JSON對象,我們感興趣的信息在query.search屬性中。 我們使用pluck運算符來提取它。

我們不知道我們是否會有任何結(jié)果,所以至少我們確保我們有一個空數(shù)組。

最后,我們將vtreeElements函數(shù)應(yīng)用于維基百科的每個結(jié)果。 這將更新我們的UI。

注意變量名稱末尾的$符號。 在本章中,我采用了Cycle.js代碼中使用的命名約定,它將$添加到變量名稱,表示它是一個Observable。 我發(fā)現(xiàn)它可以更容易理解基于Observable的代碼!

前面代碼中最重要的一點是,在最后一步中,我們似乎重新繪制了我們收到的每個結(jié)果的整個UI。 但這里是虛擬DOM閃耀的地方。 無論我們重新呈現(xiàn)頁面多少次,虛擬DOM將始終確保僅呈現(xiàn)差異,從而使其非常高效。 如果虛擬DOM沒有更改,則不會在頁面中呈現(xiàn)任何更改。

這樣我們就不必?fù)?dān)心添加或刪除元素了。 我們每次只渲染整個應(yīng)用程序,我們讓Virtual DOM找出實際更新的內(nèi)容。

Model-View-Intent

我們用于構(gòu)建維基百科實時搜索的架構(gòu)方法不僅僅是另一個框架的編程UI方法。結(jié)構(gòu)化代碼背后有一個設(shè)計模式,就像我們做的那樣:Model-View-Intent(MVI)。

Model-View-Intent是一個由Cycle.js創(chuàng)建者AndréStaltz創(chuàng)建的術(shù)語,用于受模型 - 視圖 - 控制器(MVC)架構(gòu)啟發(fā)的體系結(jié)構(gòu).在MVC中,我們將應(yīng)用程序的功能分為三個部分: 模型,視圖和控制器。 在MVI中,三個組件是模型,視圖和意圖。 MVI旨在適應(yīng)像手套一樣的Reactive編程模型。

MVI是被動的,意味著每個組件都會觀察其依賴關(guān)系并對依賴項的更改做出反應(yīng)。 這與MVC不同,MVC中的組件知道其依賴項并直接修改它們。 組件(C)聲明哪些其他組件影響它,而不是明確更新(C)的其他組件。

MVI中的三個組件由Observables表示,每個組件的輸出是另一個組件的輸入。

該模型表示當(dāng)前的應(yīng)用程序狀態(tài)。 它從intent中獲取已處理的用戶輸入,并輸出有關(guān)視圖消耗的數(shù)據(jù)更改的事件。

視圖是我們模型的直觀表示。 它采用具有模型狀態(tài)的Observable,并輸出所有潛在的DOM事件和頁面的虛擬樹。

意圖是MVI中的新組件。意圖從用戶獲取輸入并將其轉(zhuǎn)換為我們模型中的操作。如果我們重新調(diào)整和重命名我們的代碼,我們可以在我們的應(yīng)用程序中使這三種組件更清晰:

cycle/index-mvi.js

function intent(JSONP) {
    return JSONP.filter(function(res$) {
        return res$.request.indexOf(API_URL) === 0; 
    })
    .concatAll()
    .pluck("query", "search"); 
}

function model(actions) { 
    return actions.startWith([]);
}

function view(state) {
    return state.map(function(linkArray) {
        return h("div", [
            h("h1", "Wikipedia Search "),
            h("input", {className: "search-field", attributes: {type: "text"}}), h("hr"),
            h("div", linkArray.map(function(link) {
            return h("div", [
            h("a", { href: WIKI_URL + link.title }, link.title)
            ]); }))
        ]);
    });
}

function userIntent(DOM) {
    return DOM.select(".search-field")
    .events("input")
    .debounce(300)
    .map(function(e) { return e.target.value }) .filter(function(value) { 
        return value.length > 2 
    }) 
    .map(function(search) { 
        return API_URL + search 
    });
}

function main(responses) { 
    return {
        DOM: view(model(intent(responses.JSONP))),
        JSONP: userIntent(responses.DOM)
    };
}

Cycle.run(main, {
    DOM: CycleDOM.makeDOMDriver("#container"), JSONP: CycleJSONP.makeJSONPDriver()
});

通過將模型,視圖和意圖拆分為多帶帶的函數(shù),我們使代碼更加清晰。 (另一個意圖,userIntent,是JSONP驅(qū)動程序的輸入。)大多數(shù)應(yīng)用程序邏輯在我們傳遞給main函數(shù)中的DOM驅(qū)動程序的屬性中表示為這三個函數(shù)的組合:

function main(responses) { 
    return {
        DOM: view(model(intent(responses.JSONP))),
        JSONP: userIntent(responses.DOM)
    };
}

它沒有那么多功能!

創(chuàng)建可重用的小部件

隨著我們制作更復(fù)雜的應(yīng)用程序,我們希望重用一些UI組件。 我們的維基百科搜索應(yīng)用程序很小,但是它已經(jīng)有一些可以在其他應(yīng)用程序中重用的組件。 以搜索輸入框為例。 我們絕對可以將它變成自己的小部件。

目標(biāo)是將我們的小部件封裝在自己的組件中,以便我們將其用作任何其他DOM元素。 我們還應(yīng)該能夠使用我們想要的任何屬性來參數(shù)化組件。 然后我們將在我們的應(yīng)用程序中使用它,如下所示:

var wpSearchBox = searchBox({ 
    props$: Rx.Observable.just({
        apiUrl: API_URL
    })
});

我們將使用Cycle.js引入的概念構(gòu)建我們的小部件,它將一個Observable事件作為輸入,并輸出一個Observable,其結(jié)果是將這些輸入應(yīng)用于其內(nèi)部邏輯。

讓我們開始構(gòu)建搜索框組件。 我們首先創(chuàng)建一個函數(shù),它接受一個響應(yīng)參數(shù),我們將從主應(yīng)用程序傳遞任何我們想要的屬性:

cycle/searchbox.js

var Cycle = require("@cycle/core"); 
var CycleDOM = require("@cycle/dom"); 
var Rx = Cycle.Rx;
var h = CycleDOM.h;
var a;
function searchBox(responses) {
    var props$ = responses.props$;
    var apiUrl$ = props$.map(function (props) {
        return props["apiUrl"]; 
    }).first();
}

searchBox接收的每個參數(shù)都是一個Observable。 在這種情況下,props $是一個Observable,它發(fā)出一個包含Wikipedia搜索框配置參數(shù)的JavaScript對象。

檢索屬性后,我們?yōu)榇翱谛〔考x虛擬樹。 在我們的例子中,它只是一個非常簡單的輸入字段:

cycle/searchbox.js

var vtree$ = Rx.Observable.just(
    h("div", { className: "search-field" }, [
        h("input", { type: "text" }) 
    ])
);

我們希望所有東西都是一個Observable,所以我們將虛擬樹包裝在一個Observable中,它只返回一個Observable,它發(fā)出我們傳遞它的值。

現(xiàn)在,只要用戶在輸入字段中鍵入搜索詞,我們就需要搜索框來查詢Wikipedia API。 我們重用上一節(jié)函數(shù)userIntent中的代碼:

cycle/searchbox.js

var searchQuery$ = apiUrl$.flatMap(function (apiUrl) {
    return responses.DOM.select(".search-field").events("input")
    .debounce(300)
    .map(function (e) { 
        return e.target.value; 
    })
    .filter(function (value) { 
        return value.length > 3; 
    })
    .map(function (searchTerm) { 
        return apiUrl + searchTerm; 
    });
});

我們?nèi)匀恍枰獙earchQuery的輸出連接到JSON驅(qū)動程序的輸入。 我們就像在正常的Cycle應(yīng)用程序中那樣做:

cycle/searchbox.js

return {
    DOMTree: vtree$, 
    JSONPQuery: searchQuery$
};

最后,我們不應(yīng)該忘記導(dǎo)出搜索框小部件:

cycle/searchbox.js

module.exports = searchBox; // Export it as a module

現(xiàn)在我們已準(zhǔn)備好在您的應(yīng)用程序中使用搜索框小部件。 主要方法現(xiàn)在看起來像這樣:

cycle/index-mvi2.js

var h = CycleDOM.h;
? var SearchBox = require("./searchbox");

function main(responses) {
? var wpSearchBox = SearchBox({
        DOM: responses.DOM,
        props$: Rx.Observable.just({
            apiUrl: API_URL
        })
    });
    ? var searchDOM$ = wpSearchBox.DOMTree;
    var searchResults$ = responses.JSONP
    .filter(function(res$) {
        return res$.request.indexOf(API_URL) === 0;
    })
    .concatAll()
    .pluck("query", "search")
    .startWith([]);
    return {
        ? JSONP: wpSearchBox.JSONPQuery,
        ? DOM: Rx.Observable.combineLatest(
        searchDOM$, searchResults$, function(tree, links) {
            return h("div", [
                h("h1", "Wikipedia Search "),
                tree,
                h("hr"),
                h("div", links.map(function(link) {
                    return h("div", [
                            h("a", { href: WIKI_URL + link.title }, link.title)
                        ]);
                    }))
            ]);
        })
    };
}

Cycle.run(main, {
    DOM: CycleDOM.makeDOMDriver("#container"),
    JSONP: CycleJSONP.makeJSONPDriver()
});

現(xiàn)在我們將處理用戶輸入和呈現(xiàn)搜索框的責(zé)任委托給wpSearchBox小部件,我們可以在另一個需要查詢URL API的搜索框的應(yīng)用程序中輕松地重用該小部件。 這些是主要的變化:

導(dǎo)入我們剛剛創(chuàng)建的searchBox小部件。

創(chuàng)建一個SearchBox實例,傳遞DOM驅(qū)動程序和我們想要搜索小部件的屬性。

我們的wpSearchBox最終將從其DOMTree Observable中發(fā)出項目。 我們在這里分配它以便在我們渲染實際DOM時使用它們。

我們將Wikipedia查詢URL發(fā)送到JSONP驅(qū)動程序,以便檢索其結(jié)果。 當(dāng)這些可用時,它將在response.JSONP中發(fā)出它們,我們在searchResults中對它進(jìn)行了優(yōu)化。

為了渲染最終的DOM樹,我們使用combineLatest與searchDOM和searchResults。它們中的每一個都會導(dǎo)致布局發(fā)生變化,因此只要這兩個Observable中的一個發(fā)出一個項目,我們就會重新渲染DOM樹。

有了最終的代碼,我們可以看到Cycle.js的最大亮點。 框架中沒有不同的類,特殊類型或“魔術(shù)”。 這是所有無副作用的函數(shù),它們接受Observable并輸出更多的Observable。 只有這樣,我們才有一個簡潔的Web應(yīng)用程序框架,清晰,反應(yīng)靈敏,使用起來很有趣。 它不惜一切代價避免副作用,使我們的Web應(yīng)用程序更加健壯。

改進(jìn)的想法

除了迫切需要更好的圖形設(shè)計外,我們的應(yīng)用程序可以使用一些功能,而不僅僅是快速重定向到維基百科的結(jié)果:

讓用戶為特定結(jié)果添加書簽。 您可以在列表中的每個結(jié)果旁邊添加一個小星星,這樣當(dāng)用戶點擊時,它會將該結(jié)果保存為收藏夾。 你可以將星星變成自己的小部件。 如果您使用某些持久性API(反應(yīng)性!),例如本地存儲或IndexedDB,則需要額外的分?jǐn)?shù)。

如果用戶單擊鏈接,則在屏幕右側(cè)顯示結(jié)果的“預(yù)覽”,其中包含概要及其相關(guān)元信息。 如果用戶想要查看實際的Wikipedia結(jié)果,則可以在其中包含“閱讀更多”鏈接。 將其實現(xiàn)為小部件。

總結(jié)

現(xiàn)在您知道如何開發(fā)使用現(xiàn)代技術(shù)的Web應(yīng)用程序而不放棄響應(yīng)性理念。 本章提供了如何使用Observables和RxJS作為其他框架或應(yīng)用程序的內(nèi)部引擎的想法。 通過站在Observables的肩膀和活躍的生活方式,我們可以極大地簡化Web應(yīng)用程序并將狀態(tài)降低到最小的表達(dá),使我們的Web應(yīng)用程序不那么脆弱和易于維護(hù)。

感謝您閱讀本書。 我希望它能幫助您重新思考開發(fā)JavaScript應(yīng)用程序的方式,并挑戰(zhàn)一些有關(guān)編程的現(xiàn)有概念。 這是快速,強大和反應(yīng)性的軟件!

關(guān)注我的微信公眾號,更多優(yōu)質(zhì)文章定時推送

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/108196.html

相關(guān)文章

  • 響應(yīng)編程思維藝術(shù)】 (1)Rxjs專題學(xué)習(xí)計劃

    摘要:由于技術(shù)棧的學(xué)習(xí),筆者需要在原來函數(shù)式編程知識的基礎(chǔ)上,學(xué)習(xí)的使用。筆者在社區(qū)發(fā)現(xiàn)了一個非常高質(zhì)量的響應(yīng)式編程系列教程共篇,從基礎(chǔ)概念到實際應(yīng)用講解的非常詳細(xì),有大量直觀的大理石圖來輔助理解流的處理,對培養(yǎng)響應(yīng)式編程的思維方式有很大幫助。 showImg(https://segmentfault.com/img/bVus8n); [TOC] 一. 響應(yīng)式編程 響應(yīng)式編程,也稱為流式編程...

    lscho 評論0 收藏0
  • Rxjs 響應(yīng)編程-第五章 使用Schedulers管理時間

    摘要:響應(yīng)式編程第一章響應(yīng)式響應(yīng)式編程第二章序列的深入研究響應(yīng)式編程第三章構(gòu)建并發(fā)程序響應(yīng)式編程第四章構(gòu)建完整的應(yīng)用程序響應(yīng)式編程第五章使用管理時間響應(yīng)式編程第六章使用的響應(yīng)式應(yīng)用程序使用管理時間自從接觸,就開始在我的項目中使用它。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-第四章 構(gòu)建完...

    qingshanli1988 評論0 收藏0
  • Rxjs 響應(yīng)編程-第一章:響應(yīng)

    摘要:響應(yīng)式編程具有很強的表現(xiàn)力,舉個例子來說,限制鼠標(biāo)重復(fù)點擊的例子。在響應(yīng)式編程中,我把鼠標(biāo)點擊事件作為一個我們可以查詢和操作的持續(xù)的流事件。這在響應(yīng)式編程中尤其重要,因為我們隨著時間變換會產(chǎn)生很多狀態(tài)片段。迭代器模式的另一主要部分來自模式。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-...

    songze 評論0 收藏0
  • Rxjs 響應(yīng)編程-第四章 構(gòu)建完整Web應(yīng)用程序

    摘要:建立一個實時地震我們將為地震儀表板應(yīng)用程序構(gòu)建服務(wù)器和客戶端部件,實時記錄地震的位置并可視化顯示。添加地震列表新儀表板的第一個功能是顯示地震的實時列表,包括有關(guān)其位置,大小和日期的信息。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整的Web應(yīng)用程序Rxjs 響應(yīng)式編程-...

    BigTomato 評論0 收藏0
  • Rxjs 響應(yīng)編程-第二章:序列深入研究

    摘要:接下來,我們將實現(xiàn)一個真實的應(yīng)用程序,顯示幾乎實時發(fā)生的地震。得到的由表示,其中包含和的合并元素。如果不同同時傳出元素,合并序列中這些元素的順序是隨機的。是操作序列的強大操作符。但是的方法仍在運行,表明取消并不會取消關(guān)聯(lián)的。 Rxjs 響應(yīng)式編程-第一章:響應(yīng)式Rxjs 響應(yīng)式編程-第二章:序列的深入研究Rxjs 響應(yīng)式編程-第三章: 構(gòu)建并發(fā)程序Rxjs 響應(yīng)式編程-第四章 構(gòu)建完整...

    姘擱『 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<