目前我正在寫這篇文章以政,有很多方法來解決一個具體的問題。">目前我正在寫這篇文章伴找,有很多方法來解決一個具體的問題盈蛮。</trans>
在本文中,我想給您一個靈感技矮,它可能會改變您在應(yīng)用程序中使用的當(dāng)前方法抖誉。">在本文中,我想給您一個靈感衰倦,它可能會改變您在應(yīng)用程序中使用的當(dāng)前方法袒炉。</trans>
可能與非常復(fù)雜的實(shí)現(xiàn)、測試和維護(hù)相關(guān)樊零。">RxJS可能與非常復(fù)雜的實(shí)現(xiàn)我磁、測試和維護(hù)相關(guān)。
如果我告訴您驻襟,集成夺艰、實(shí)現(xiàn)和測試實(shí)際上非常容易,即使是在一個通用的(小型沉衣、中型郁副、大型)VueJS應(yīng)用程序中也是如此呢?(247, 238, 255);">如果我告訴您厢蒜,集成、實(shí)現(xiàn)和測試實(shí)際上非常容易烹植,即使是在一個通用的(小型斑鸦、中型、大型)VueJS應(yīng)用程序中也是如此呢草雕?
在本文中巷屿,我將演示如何將VueJS、type escript和RxJS結(jié)合起來墩虹。我真的相信這是一個很棒的組合嘱巾,還有一個插件憨琳,它真的很有用:">在本文中,我將演示如何將VueJS旬昭、type escript和RxJS結(jié)合起來篙螟。我真的相信這是一個很棒的組合,還有一個插件问拘,它真的很有用.
你為什么要安裝和使用這個插件遍略?">你為什么要安裝和使用這個插件?
因?yàn)樗卺尫拍愕膽?yīng)用程序的超能力骤坐,它正在創(chuàng)造整個體驗(yàn)绪杏。">因?yàn)樗卺尫拍愕膽?yīng)用程序的超能力,它正在創(chuàng)造整個體驗(yàn)纽绍。略顯更流暢蕾久,作為初級或高級開發(fā)人員。">更流暢拌夏,作為初級或高級開發(fā)人員僧著。
有了一個通用應(yīng)用程序,第一個開始的命令如下:">有了一個通用應(yīng)用程序辖佣,第一個開始的命令如下
npm install vue-rx rxjs --save</pre>
很明顯霹抛,這將Vue-Rx和RxJS安裝到項(xiàng)目的依賴項(xiàng)中。">很明顯卷谈,這將Vue-Rx和RxJS安裝到項(xiàng)目的依賴項(xiàng)中杯拐。
當(dāng)然,我們需要告訴VueJS安裝它(在全球范圍內(nèi)世蔗,是的):">當(dāng)然端逼,我們需要告訴VueJS安裝它(在全球范圍內(nèi),是的)
import Vue from 'vue'
import VueRx from 'vue-rx'
Vue.use(VueRx)</pre>
它導(dǎo)入最小數(shù)量的Rx操作符污淋,并確保小的包大小顶滩。">它導(dǎo)入最小數(shù)量的Rx操作符,并確保小的包大小寸爆。
我親自確認(rèn)礁鲁。">我親自確認(rèn)。
一旦所有的一切都設(shè)置好了赁豆,你就可以使用這個偉大的插件所暴露的任何東西了仅醇。如果我們深入研究類型記錄定義,您就可以快速看到將添加到VueJS中的內(nèi)容:">一旦所有的一切都設(shè)置好了魔种,你就可以使用這個偉大的插件所暴露的任何東西了析二。如果我們深入研究類型記錄定義,您就可以快速看到將添加到VueJS中的內(nèi)容:</trans>
declare module* "vue/types/vue" {
*interface* Vue {
$observables: Observables;
$watchAsObservable(expr: *string*, options?: WatchOptions): Observable<WatchObservable<*any*>>
$watchAsObservable<T>(fn: (*this*: *this*) => T, options?: WatchOptions): Observable<WatchObservable<T>>
$eventToObservable(event: *string*): Observable<{name: *string*, msg: *any*}>
$subscribeTo<T>(
observable: Observable<T>,
next: (t: T) => *void*,
error?: (e: *any*) => *void*,
complete?: () => *void*): *void* $fromDOMEvent(selector: *string* | *null*, event: *string*): Observable<Event>
$createObservableMethod(methodName: *string*): Observable<*any*>
}
}
這看起來可能有點(diǎn)奇怪,但我將很快突出這些特性:">這看起來可能有點(diǎn)奇怪叶摄,但我將很快突出這些特性:
美元可觀測值它將指出已登記的訂閱属韧;">它將指出已登記的訂閱;</trans>
例如蛤吓,一個可觀察的功能可以幫助應(yīng)用于該屬性的流更改宵喂,而不是讓一個泛型函數(shù)監(jiān)視一個反應(yīng)性屬性;">例如柱衔,一個可觀察的功能可以幫助應(yīng)用于該屬性的流更改樊破,而不是讓一個泛型函數(shù)監(jiān)視一個反應(yīng)性屬性;</trans>
可以將自定義事件處理程序或生命周期掛鉤轉(zhuǎn)換為可觀察的唆铐;">:可以將自定義事件處理程序或生命周期掛鉤轉(zhuǎn)換為可觀察的哲戚;</trans>
這是另一種很好的轉(zhuǎn)換DOM事件的方法(例如,鍵向上艾岂,輸入顺少,點(diǎn)擊等等)變成可觀察的;">:這是另一種很好的轉(zhuǎn)換DOM事件的方法(例如王浴,鍵向上脆炎,輸入,點(diǎn)擊等等)變成可觀察的
這也是一個很好的特性氓辣;如果將一個方法轉(zhuǎn)換為一個可觀察的值并將接收到的值處理為一個反應(yīng)流(例如回調(diào))秒裕,這將很有幫助;">*這也是一個很好的特性钞啸;如果將一個方法轉(zhuǎn)換為一個可觀察的值并將接收到的值處理為一個反應(yīng)流(例如回調(diào))几蜻,這將很有幫助;
它提供了手動注冊一個可觀察到的(聲明下一個錯誤体斩、完全回調(diào))的機(jī)會梭稚,VueRx將管理注冊并在不再有用的情況下處理它(例如已銷毀的組件)。">:它提供了手動注冊一個可觀察到的(聲明下一個錯誤絮吵、完全回調(diào))的機(jī)會弧烤,VueRx將管理注冊并在不再有用的情況下處理它(例如已銷毀的組件)。
在上面蹬敲,這個插件公開了一個">在上面暇昂,這個插件公開了一個=流指令">可與以下內(nèi)容相結(jié)合
DOM事件
很酷,但是如何正確地使用它呢伴嗡?">很酷急波,但是如何正確地使用它呢?
在很多情況下闹究,可以使用上述特性幔崖,在本文中食店,我將介紹一個簡單的案例:一個泛型輸入字段渣淤,它觸發(fā)對給定端點(diǎn)執(zhí)行搜索的請求赏寇。在這種情況下,有很多事情和特性需要考慮:">在很多情況下价认,可以使用上述特性嗅定,在本文中,我將介紹一個簡單的案例:一個泛型輸入字段用踩,它觸發(fā)對給定端點(diǎn)執(zhí)行搜索的請求渠退。在這種情況下,有很多事情和特性需要考慮:
它可以避免每次輸入新字符時發(fā)送大量請求脐彩;">它可以避免每次輸入新字符時發(fā)送大量請求碎乃;
并發(fā)請求呢?哪一個應(yīng)該優(yōu)先考慮惠奸?">并發(fā)請求呢梅誓?哪一個應(yīng)該優(yōu)先考慮?
如果響應(yīng)包含的數(shù)據(jù)可能不包含我們所需要的所有信息呢佛南?我們在哪里處理梗掰?">如果響應(yīng)包含的數(shù)據(jù)可能不包含我們所需要的所有信息呢?我們在哪里處理嗅回?
這是一個基本的場景及穗。在一個特定的項(xiàng)目中,你可能會有另外萬億的分?jǐn)?shù)绵载。你是如何組合/處理它們的埂陆?你如何確保所有的東西都是聲明性的和良好的閱讀?另外尘分,單元測試呢猜惋?">這是一個基本的場景堪遂。在一個特定的項(xiàng)目中昔榴,你可能會有另外萬億的分?jǐn)?shù)懈涛。你是如何組合/處理它們的软棺?你如何確保所有的東西都是聲明性的和良好的閱讀嫂沉?另外翩腐,單元測試呢纵揍?
讓我們開始為我們的組件實(shí)現(xiàn)基本代碼:">讓我們開始為我們的組件實(shí)現(xiàn)基本代碼
<label *for=*"search">Search for something:</label>
<input *type=*"text" *id=*"search" *class=*"input-field">
</div>
</template>
<script *lang=*"ts">
*import* { Component, Vue } *from* 'vue-property-decorator';
@Component
*export default class* Search *extends* Vue {}
</script>
<style *scoped*>
.input-field {
...
}
</style></pre>
因?yàn)槲覀円蕾嚧蜃指灏觯晕矣玫氖?>因?yàn)槲覀円蕾嚧蜃指逅焦桑慨a(chǎn)裝飾師這使我們能夠在組件聲明中使用裝飾器(例如組件摹察、Prop等,…)倡鲸。供嚎。">‘這使我們能夠在組件聲明中使用裝飾器(例如組件、Prop等,…)克滴。
在我們的例子中逼争,我們希望實(shí)現(xiàn)一個簡單的行為:鍵入某樣?xùn)|西并作為查詢進(jìn)行搜索。">在我們的例子中劝赔,我們希望實(shí)現(xiàn)一個簡單的行為:鍵入某樣?xùn)|西并作為查詢進(jìn)行搜索誓焦。</trans>
首先,我們需要創(chuàng)建一個可觀察的着帽,它將所有來自字段的輸入流杂伟。一種方法是依賴于輸入標(biāo)記中的keyup事件:">首先,我們需要創(chuàng)建一個可觀察的仍翰,它將所有來自字段的輸入流赫粥。一種方法是依賴于輸入標(biāo)記中的keyup事件
Component<Search>({
subscriptions() {
*return* ({
news: *this*.$fromDOMEvent('input', 'keyup')
});
}
})
*export default class* Search *extends* Vue {
news: any; // we will specifically type it later on
}</pre>
在使用類型記錄時,注冊對VueJS組件的訂閱的方法予借,就是上面聲明的方法傅是。">在使用類型記錄時,注冊對VueJS組件的訂閱的方法蕾羊,就是上面聲明的方法喧笔。</trans>
從“訂閱”函數(shù)返回的對象包含一個屬性“news”,該屬性是一個數(shù)據(jù)屬性龟再,它將與注冊的可觀測值相關(guān)聯(lián)(在本例中為.$fromDOMEVENT…)书闸。。">從“訂閱”函數(shù)返回的對象包含一個屬性“news”利凑,該屬性是一個數(shù)據(jù)屬性浆劲,它將與注冊的可觀測值相關(guān)聯(lián)
當(dāng)輸入字段中輸入某項(xiàng)內(nèi)容時,與“news”相關(guān)聯(lián)的可觀察到的事件將接收到DOM事件“С海現(xiàn)在牌借,讓我們稍微調(diào)整一下邏輯,轉(zhuǎn)而依賴一個字符串(例如割按,字段的值)膨报。">當(dāng)輸入字段中輸入某項(xiàng)內(nèi)容時,與“news”相關(guān)聯(lián)的可觀察到的事件將接收到DOM事件∈嗜伲現(xiàn)在现柠,讓我們稍微調(diào)整一下邏輯,轉(zhuǎn)而依賴一個字符串(例如弛矛,字段的值)够吩。
Component<Search>({
subscriptions() {
*return* ({
news: *this*.$fromDOMEvent('input', 'keyup').pipe(
pluck<Event, *string*>('target', 'value')
)
});
}
})
*export default class* Search *extends* Vue {
news: *string*;
}</pre>
為了從接收到的事件中檢索輸入的值,我們可以使用‘">為了從接收到的事件中檢索輸入的值丈氓,我們可以使用拔毛一個由RxJS公開的操作符周循,它允許我們從定義的對象中查看所需的屬性(即使是嵌套的路徑)强法。">一個由RxJS公開的操作符,它允許我們從定義的對象中查看所需的屬性(即使是嵌套的路徑)湾笛。</trans>
<figure style="display: block; margin: 0px 0px 1em; color: rgb(51, 51, 51); font-family: "Helvetica Neue", Helvetica, Tahoma, Arial, STXihei, "Microsoft YaHei", 微軟雅黑, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254); text-decoration-style: initial; text-decoration-color: initial;">
即使有一個字符串拟烫,它對我們也沒有太大的幫助,因?yàn)槲覀冃枰粋€結(jié)果列表迄本。下一步可能是一個簡單的請求,在HackerNewsAPI上搜索給定的查詢(我們的輸入字段值)课竣。">即使有一個字符串嘉赎,它對我們也沒有太大的幫助,因?yàn)槲覀冃枰粋€結(jié)果列表于樟。下一步可能是一個簡單的請求公条,在HackerNewsAPI上搜索給定的查詢(我們的輸入字段值)。</trans>
import* axios *from* 'axios';
*import* { Component, Vue } *from* 'vue-property-decorator';
*import* { *from* } *from* 'rxjs';
*import* { pluck, switchMap } *from* 'rxjs/operators';
*interface* HackerNewsResult {
objectID: *string*;
title?: *string*;
url?: *string*;
}
*interface* HackerNewsSearchResponse {
hits: Array<HackerNewsResult>
}
*const* hackerNewsEndpoint: *string* = 'http://hn.algolia.com/api/v1/search?query=';
@Component<Search>({
subscriptions() {
*return* ({
news: *this*.$fromDOMEvent('input', 'keyup').pipe(
pluck<Event, *string*>('target', 'value'),
switchMap(value => *from*(
axios.get<HackerNewsSearchResponse>(`${hackerNewsEndpoint}${value}`)
)
)
)
});
}
})
*export default class* Search *extends* Vue {
news: Array<HackerNewsResult>;
}</pre>
它開始采取一些實(shí)際的行為迂曲,從行中可以看到發(fā)生了什么:我們從呈現(xiàn)的輸入中流出DOM事件靶橱,我們選擇它的值,并使用來執(zhí)行針對端點(diǎn)的請求路捧。根據(jù)文檔关霸,它開始采取一些實(shí)際的行為,從行中可以看到發(fā)生了什么:我們從呈現(xiàn)的輸入中流出DOM事件杰扫,我們選擇它的值队寇,并使用SwitMap來執(zhí)行針對端點(diǎn)的請求。根據(jù)文檔將每個源值投影到可觀察的可觀測值章姓,該值合并到可觀測的輸出中佳遣,僅從最近預(yù)測的可觀測值中發(fā)出值。">將每個源值投影到可觀察的可觀測值凡伊,該值合并到可觀測的輸出中零渐,僅從最近預(yù)測的可觀測值中發(fā)出值。</trans>*<trans oldtip=" To clarify, the only latest promise will be tracked down till the end (resolved — rejected). Nice! " newtip="為了澄清系忙,唯一的最新承諾將被追查到最后(解決-拒絕)诵盼。好的,漂亮的">為了澄清银还,唯一的最新承諾將被追查到最后(解決-拒絕)拦耐。好的,漂亮的
<figure style="display: block; margin: 0px 0px 1em; color: rgb(51, 51, 51); font-family: "Helvetica Neue", Helvetica, Tahoma, Arial, STXihei, "Microsoft YaHei", 微軟雅黑, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254); text-decoration-style: initial; text-decoration-color: initial;">
現(xiàn)在见剩,最好只針對特定的時間窗口執(zhí)行請求杀糯,而不是每次用戶輸入時都執(zhí)行請求。為了完成這個案子苍苞,我們可以用">現(xiàn)在固翰,最好只針對特定的時間窗口執(zhí)行請求狼纬,而不是每次用戶輸入時都執(zhí)行請求。為了完成這個案子骂际,我們可以用借債時間,它從源發(fā)出一個值疗琉,只有在特定的時間跨度過去之后才能觀察到,而沒有另一個源發(fā)射歉铝。">它從源發(fā)出一個值盈简,只有在特定的時間跨度過去之后才能觀察到,而沒有另一個源發(fā)射太示。</trans>
<trans oldtip="If you have already worked with Lodash/Underscore, “debounce” might sound familiar." newtip="如果您已經(jīng)使用過Lodash/下劃線柠贤,那么“退出”可能聽起來很熟悉。">如果您已經(jīng)使用過Lodash/下劃線类缤,那么“退出”可能聽起來很熟悉臼勉。</trans>
import* { debounceTime, pluck, switchMap } *from* 'rxjs/operators';
@Component<Search>({
subscriptions() {
*return* ({
news: *this*.$fromDOMEvent('input', 'keyup').pipe(
**debounceTime(300),**
pluck<Event, *string*>('target', 'value'),
switchMap(value => *from*(
axios.get<HackerNewsSearchResponse>(`${hackerNewsEndpoint}${value}`)
)
)
)
});
}
})
*export default class* Search *extends* Vue {
news: Array<HackerNewsResult>;
}</pre>
為了解決上面提到的問題,向管道中添加了為了解決上面提到的問題餐弱,向管道中添加了
(dueTime: *number*, scheduler: SchedulerLike = async): MonoTypeOperatorFunction<T> {
*return* (source: Observable<T>) => source.lift(*new* DebounceTimeOperator(dueTime, scheduler));
}</pre>
作為參數(shù)傳遞給函數(shù)的數(shù)字表示時間窗口宴霸,以毫秒為單位。每次用戶輸入某項(xiàng)內(nèi)容時膏蚓,下一個值將在300 ms后發(fā)出(因此瓢谢,它將聚合下一個條目,以防萬一驮瞧,并在所需的時間之后觸發(fā)下一個值)">作為參數(shù)傳遞給函數(shù)的數(shù)字表示時間窗口恩闻,以毫秒為單位。每次用戶輸入某項(xiàng)內(nèi)容時剧董,下一個值將在300 ms后發(fā)出(因此幢尚,它將聚合下一個條目,以防萬一翅楼,并在所需的時間之后觸發(fā)下一個值)</trans>
<figure style="display: block; margin: 0px 0px 1em; color: rgb(51, 51, 51); font-family: "Helvetica Neue", Helvetica, Tahoma, Arial, STXihei, "Microsoft YaHei", 微軟雅黑, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(254, 254, 254); text-decoration-style: initial; text-decoration-color: initial;">
<figcaption style="display: block; margin: auto; text-align: center;">http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-debounceTime</figcaption>
</figure>
快好了∥臼#現(xiàn)在,我們需要接受響應(yīng)毅臊,使用有效的信息過濾結(jié)果并將其呈現(xiàn)給用戶理茎。">快好了。現(xiàn)在管嬉,我們需要接受響應(yīng)皂林,使用有效的信息過濾結(jié)果并將其呈現(xiàn)給用戶。
<template>
<div>
<label *for=*"search">Search for something:</label>
<input *type=*"text" *id=*"search" *class=*"input-field">
** <ul *v-for=*"item in news">
<li *:key=*"item.objectID">
<a *:href=*"item.url">{{ item.title }}</a>
</li>
</ul>**
</div>
</template>
<script *lang=*"ts">
...</pre>
*import* { debounceTime, map, pluck, switchMap } *from* 'rxjs/operators';
@Component<Search>({
subscriptions(*this*: Vue) {
*return* ({
news: *this*.$fromDOMEvent('input', 'keyup').pipe(
debounceTime(300),
pluck<Event, *string*>('target', 'value'),
switchMap(value => *from*(
axios.get<HackerNewsSearchResponse>(`${hackerNewsEndpoint}${value}`)
)
),
**pluck<AxiosResponse, Array<HackerNewsResult>>('data', 'hits'),
map((results: Array<HackerNewsResult>) => results.filter((news: HackerNewsResult) => Boolean(news.title && news.url)))**
)
});
}
})
*export default class* Search *extends* Vue {
news: Array<HackerNewsResult> = [];
}
首先蚯撩,我在管道中增加了兩個額外的步驟:">首先础倍,我在管道中增加了兩個額外的步驟
考慮到來自Axios承諾的成功響應(yīng),我們從JSON“data”中選擇“HITS”(這包含基于查詢的結(jié)果)胎挎;">考慮到來自Axios承諾的成功響應(yīng)沟启,我們從JSON“data”中選擇“HITS”(這包含基于查詢的結(jié)果)忆家;后來,我介紹了">后來德迹,我介紹了地圖遍歷流中的每個值(包含結(jié)果的數(shù)組)芽卿,只過濾包含有效標(biāo)題和URL的有效值;">遍歷流中的每個值(包含結(jié)果的數(shù)組)胳搞,只過濾包含有效標(biāo)題和URL的有效值卸例;</trans>
為了呈現(xiàn)數(shù)組,我在模板中創(chuàng)建了一個簡單的列表肌毅,它迭代新聞數(shù)組筷转,并呈現(xiàn)一個簡單的鏈接,顯示新聞標(biāo)題并在href中實(shí)現(xiàn)URL芽腾。">為了呈現(xiàn)數(shù)組,我在模板中創(chuàng)建了一個簡單的列表页衙,它迭代新聞數(shù)組摊滔,并呈現(xiàn)一個簡單的鏈接,顯示新聞標(biāo)題并在href中實(shí)現(xiàn)URL店乐。
就這樣IMHO艰躺,它看起來非常整潔和“容易”閱讀。我知道這可能不是簡單的眨八,但是一旦熟悉了RxJS和反應(yīng)性方法腺兴,維護(hù)/測試就變得更加容易了。現(xiàn)在停下來好好想想廉侧。傳統(tǒng)的聲明式方法很容易出錯页响,而可維護(hù)性/測試將處于邊緣。">就這樣IMHO段誊,它看起來非常整潔和“容易”閱讀闰蚕。我知道這可能不是簡單的,但是一旦熟悉了RxJS和反應(yīng)性方法连舍,維護(hù)/測試就變得更加容易了。現(xiàn)在停下來好好想想索赏。傳統(tǒng)的聲明式方法很容易出錯盼玄,而可維護(hù)性/測試將處于邊緣。</trans>
您還可以添加額外的步驟潜腻,例如">現(xiàn)在埃儿,感謝RxJS,您還可以添加額外的步驟融涣,"如果出現(xiàn)錯誤和許多其他特性蝌箍。此外青灼,如果您熱衷于測試流,我建議您使用">如果出現(xiàn)錯誤和許多其他特性妓盲。此外杂拨,如果您熱衷于測試流,我建議您使用大理石測試并對所觀察到的結(jié)果進(jìn)行測試悯衬,得到一定的結(jié)果弹沽。">并對所觀察到的結(jié)果進(jìn)行測試,得到一定的結(jié)果筋粗。
interface* HandleObservableOptions {
time?: *number*;
scheduler?: SchedulerLike;
}
*export const* handleObservable = *function* (observable: Observable<Event>, options: HandleObservableOptions = {}): Observable<Array<HackerNewsResult>> {
*const* { time = 300, scheduler } = options;
*return* observable.pipe(
debounceTime(time, scheduler),
...
);
};</pre>
[https://github.com/ReactiveX/rxjs/blob/master/doc/marble-testing.md](https://github.com/ReactiveX/rxjs/blob/master/doc/marble-testing.md)</pre>
// This test will actually run *synchronously*
it('generate the stream correctly', () => {
scheduler.run(helpers => {
const { cold, expectObservable, expectSubscriptions } = helpers;
const obs = handleObservable(cold('-a--b--c---|'), {
time: 300,
scheduler
});
const subs = '^----------!';
const expected = '-a-----c---|';
expectObservable(obs).toBe(expected);
expectSubscriptions(obs.subscriptions).toBe(subs);
});
上面的片段僅僅是測試看起來的一個例子(注意:根據(jù)您的環(huán)境策橘,真正的測試可能略有不同)。多虧了大理石策略娜亿,才有可能測試你能想到的所有可能的路徑丽已。也許這是下一篇()文章的一個有效主題,因?yàn)橛泻芏嗍虑橐懻摗?>上面的片段僅僅是測試看起來的一個例子(注意:根據(jù)您的環(huán)境买决,真正的測試可能略有不同)沛婴。多虧了大理石策略,才有可能測試你能想到的所有可能的路徑督赤。也許這是下一篇()文章的一個有效主題嘁灯,因?yàn)橛泻芏嗍虑橐懻摗?lt;/trans>
<trans oldtip="Anyway, the complete solution might look like this." newtip="無論如何,完整的解決方案可能是這樣的躲舌。">無論如何丑婿,完整的解決方案可能是這樣的。</trans>
<template>
<div>
<label *for=*"search">Search for something:</label>
<input *type=*"text" *id=*"search" *class=*"input-field">
<ul *v-for=*"item in news">
<li *:key=*"item.objectID">
<a *:href=*"item.url">{{ item.title }}</a>
</li>
</ul>
</div>
</template>
<script *lang=*"ts">
*import* axios, { AxiosResponse } *from* 'axios';
*import* { Component, Vue } *from* 'vue-property-decorator';
*import* { *from*, Observable, SchedulerLike } *from* 'rxjs';
*import* { debounceTime, map, pluck, switchMap } *from* 'rxjs/operators';
*interface* HackerNewsResult {
objectID: *string*;
title?: *string*;
url?: *string*;
}
*interface* HackerNewsSearchResponse {
hits: Array<HackerNewsResult>
}
*interface* HandleObservableOptions {
time?: *number*;
scheduler?: SchedulerLike;
}
*const* hackerNewsEndpoint: *string* = 'http://hn.algolia.com/api/v1/search?query=';
*export const* handleObservable = *function* (observable: Observable<Event>, options: HandleObservableOptions = {}): Observable<Array<HackerNewsResult>> {
*const* { time = 300, scheduler } = options;
*return* observable.pipe(
debounceTime(time, scheduler),
pluck<Event, *string*>('target', 'value'),
switchMap(value => *from*(
axios.get<HackerNewsSearchResponse>(`${hackerNewsEndpoint}${value}`)
)
),
pluck<AxiosResponse, Array<HackerNewsResult>>('data', 'hits'),
map((results: Array<HackerNewsResult>) => results.filter((news: HackerNewsResult) => Boolean(news.title && news.url)))
);
};
@Component<Search>({
subscriptions(*this*: Vue) {
*return* ({
news: handleObservable(*this*.$fromDOMEvent('input', 'keyup'))
});
}
})
*export default class* Search *extends* Vue {
news: Array<HackerNewsResult> = [];
}
<style *scoped*>
.input-field {
width: 50%;
}
這可能是一個起點(diǎn)没卸,許多東西可能會得到增強(qiáng)羹奉,但我建議您在應(yīng)用程序中考慮這個策略,并在代碼中替換瘋狂的流约计。">這可能是一個起點(diǎn)尘奏,許多東西可能會得到增強(qiáng),但我建議您在應(yīng)用程序中考慮這個策略病蛉,并在代碼中替換瘋狂的流炫加。
干杯