亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專(zhuān)欄INFORMATION COLUMN

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

EastWoodYang / 2744人閱讀

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

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管理時(shí)間
Rxjs 響應(yīng)式編程-第六章 使用Cycle.js的響應(yīng)式Web應(yīng)用程序

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

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

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

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

Cycle.js

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

Cycle.js以反應(yīng)方式設(shè)計(jì),Cycle.js中的所有構(gòu)建塊都是Observables,這給我們帶來(lái)了巨大的優(yōu)勢(shì)。 它比其他框架更容易掌握,因?yàn)槔斫夂陀洃浀母拍钜俚枚唷?例如,與狀態(tài)相關(guān)的所有操作都不在路徑中,封裝在稱(chēng)為驅(qū)動(dòng)程序的函數(shù)中,我們很少需要?jiǎng)?chuàng)建新的操作。

什么是虛擬DOM?

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

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

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

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

安裝Cycle.js

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

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

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

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

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

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

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

cycle/index.html



    
        
        Wikipedia search
    
    
        
我們的項(xiàng)目:維基百科搜索

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

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

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

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ū)動(dòng)對(duì)象。 我們來(lái)看看這些步驟:

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

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

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

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

Cycle.js驅(qū)動(dòng)程序

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

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

用戶界面

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

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)
            ]);
        }))
    ]);
}

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

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

使用JSX

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

cycle/index.js

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

Wikipedia Search


{results}
; }

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

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

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

如果要使用JSX,則需要安裝Babel并在編譯項(xiàng)目時(shí)使用它。 幸運(yùn)的是,Babel有一個(gè)名為Babelify的Browserify適配器:

npm install babelify

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

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

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

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

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

我們需要一個(gè)函數(shù)來(lái)返回一個(gè)Observable of URL,它使用用戶輸入的搜索詞來(lái)查詢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ū)動(dòng)程序的響應(yīng)對(duì)象,并在DOM驅(qū)動(dòng)程序中使用get方法。select(element).event(type)的行為與fromEvent類(lèi)似:它采用DOM元素的選擇器和要監(jiān)聽(tīng)的事件類(lèi)型,并返回發(fā)出事件的Observable。

這時(shí),代碼的其余部分看起來(lái)應(yīng)該非常熟悉,因?yàn)樗ㄟ^(guò)我們常用的運(yùn)算符轉(zhuǎn)換Observable值:

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

提取輸入框的值。

僅采用長(zhǎng)度超過(guò)兩個(gè)字符的文本。

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

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

修改我們的主要功能

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

我們使用JSONP查詢Wikipedia,就像我們?cè)诘?章中所做的那樣。我們使用JSONP而不是HTTP來(lái)更容易在本地計(jì)算機(jī)上運(yùn)行此示例,因?yàn)槭褂肏TTP從不同的域檢索數(shù)據(jù)會(huì)導(dǎo)致某些瀏覽器因?yàn)榘踩蜃柚惯@些請(qǐng)求。 在幾乎任何其他情況下,尤其是在生產(chǎn)代碼中,使用HTTP來(lái)檢索遠(yuǎn)程數(shù)據(jù)。

無(wú)論如何,使用JSONP并不影響本章的要點(diǎn)。 Cycle有一個(gè)JSONP的實(shí)驗(yàn)?zāi)K,我們可以使用npm安裝它:

npm install @cycle/jsonp

然后我們?cè)谖覀兊膽?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方法中,這樣一旦用戶輸入搜索詞,我們就會(huì)用術(shù)語(yǔ)查詢Wikipedia。

為此,我們使用CycleJSONP.makeJSONPDriver創(chuàng)建一個(gè)新的JSONP,它將接收我們?cè)趍ain的返回對(duì)象中放置在屬性JSONP中的任何內(nèi)容。在這之后,當(dāng)我們?cè)谳斎肟蛑幸胨阉髟~時(shí),我們應(yīng)該已經(jīng)在查詢維基百科,但由于我們沒(méi)有將JSONP輸出連接到任何內(nèi)容,我們?cè)陧?yè)面上看不到任何更改。 讓我們改變一下:

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

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

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

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

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

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

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

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

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

Model-View-Intent

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

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

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

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

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

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

意圖是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()
});

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

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

它沒(méi)有那么多功能!

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

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

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

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

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

讓我們開(kāi)始構(gòu)建搜索框組件。 我們首先創(chuàng)建一個(gè)函數(shù),它接受一個(gè)響應(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接收的每個(gè)參數(shù)都是一個(gè)Observable。 在這種情況下,props $是一個(gè)Observable,它發(fā)出一個(gè)包含Wikipedia搜索框配置參數(shù)的JavaScript對(duì)象。

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

cycle/searchbox.js

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

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

現(xiàn)在,只要用戶在輸入字段中鍵入搜索詞,我們就需要搜索框來(lái)查詢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ū)動(dòng)程序的輸入。 我們就像在正常的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)在看起來(lái)像這樣:

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小部件,我們可以在另一個(gè)需要查詢URL API的搜索框的應(yīng)用程序中輕松地重用該小部件。 這些是主要的變化:

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

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

我們的wpSearchBox最終將從其DOMTree Observable中發(fā)出項(xiàng)目。 我們?cè)谶@里分配它以便在我們渲染實(shí)際DOM時(shí)使用它們。

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

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

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

改進(jìn)的想法

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

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

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

總結(jié)

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

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

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

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/108196.html

相關(guān)文章

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

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

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

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

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

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

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

    摘要:建立一個(gè)實(shí)時(shí)地震我們將為地震儀表板應(yīng)用程序構(gòu)建服務(wù)器和客戶端部件,實(shí)時(shí)記錄地震的位置并可視化顯示。添加地震列表新儀表板的第一個(gè)功能是顯示地震的實(shí)時(shí)列表,包括有關(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 評(píng)論0 收藏0
  • Rxjs 響應(yīng)編程-第二章:序列深入研究

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

    姘擱『 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<