原創文章,轉載請注明出處
使用vue-rx插件將vue和rxjs聯系起來
在main.js中將vue-rx注入vue中
import Vue from 'vue'
import App from './App'
import router from './router'
import VueRx from 'vue-rx'
// Vue.config.productionTip = false
Vue.use(VueRx)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
components: { App },
template: '<App/>'
})
例子一
使用 observableMethods 選項聲明observable,也可以使用this.$createObservableMethod('muchMore')創建
調用注冊的observable方法muchMore(500),相當於nextx(500)
merge是將多個observable合並起來,統一監聽處理
scan是累計處理
<template>
<div>
<div>{{ count }}</div>
<button v-on:click="muchMore(500)">Add 500</button>
<button v-on:click="minus(minusDelta1)">Minus on Click</button>
<pre>{{ $data }}</pre>
</div>
</template>
<script>
import { merge } from 'rxjs'
import { startWith, scan } from 'rxjs/operators'
// 使用 observableMethods 選項聲明observable,也可以使用this.$createObservableMethod('muchMore')創建
// 調用注冊的observable方法muchMore(500),相當於nextx(500)
// merge是將多個observable合並起來,統一監聽處理
// scan是累計處理
export default {
name: 'HelloWorld',
data() {
return {
minusDelta1: -1,
minusDelta2: -1
}
},
observableMethods: {
muchMore: 'muchMore$',
minus: 'minus$'
}, // equivalent of above: ['muchMore','minus']
subscriptions() {
return {
count: merge(this.muchMore$, this.minus$).pipe(
startWith(0),
scan((total, change) => total + change)
)
}
}
}
</script>
例子二
vue-rx 提供 v-stream讓你向一個 Rx Subject 流式發送 DOM 事件
渲染發生之前你需要在vm實例上提前注冊數據,比如plus\( 傳遞額外參數<button v-stream:click="{ subject: plus\), data: someData }">+ 傳遞參數
<template>
<div>
<div>{{ count }}</div>
<button v-stream:click="plus$">+</button>
<button v-stream:click="minus$">-</button>
</div>
</template>
<script>
import { merge } from 'rxjs'
import { map,startWith, scan } from 'rxjs/operators'
export default {
domStreams: ['plus$', 'minus$'],
subscriptions() {
return {
count: merge(
this.plus$.pipe(map(() => 1)),
this.minus$.pipe(map(() => -1))
).pipe(
startWith(0),
scan((total, change) => total + change)
)
}
}
}
</script>
例子三
組件觸發父組件流事件
pluck操作符抽取特定的屬性流傳下去
<template>
<div>
<div>{{ count }}</div>
<!-- simple usage -->
<button v-stream:click="plus$">Add on Click</button>
<button
v-stream:click="{ subject: plus$, data: minusDelta1, options:{once:true} }"
>Add on Click (Option once:true)</button>
<!-- you can also stream to the same subject with different events/data -->
<button
v-stream:click="{ subject: minus$, data: minusDelta1 }"
v-stream:mousemove="{ subject: minus$, data: minusDelta2 }"
>Minus on Click & Mousemove</button>
<pre>{{ $data }}</pre>
<my-button v-stream:click="plus$"></my-button>
</div>
</template>
<script>
// import { Observable, Subject, ReplaySubject, from, of, range } from 'rxjs';
// import { map, filter, switchMap } from 'rxjs/operators';
import { merge } from 'rxjs'
import { map, pluck, startWith, scan } from 'rxjs/operators'
export default {
data() {
return {
minusDelta1: -1,
minusDelta2: -1
}
},
components: {
myButton: {
template: `<button @click="$emit('click')">MyButton</button>`
}
},
created() {
//Speed up mousemove minus delta after 5s
setTimeout(() => {
this.minusDelta2 = -5
}, 5000)
},
// declare dom stream Subjects
domStreams: ['plus$', 'minus$'],
subscriptions() {
return {
count: merge(
this.plus$.pipe(map(() => 1)),
this.minus$.pipe(pluck('data'))
).pipe(
startWith(0),
scan((total, change) => total + change)
)
}
}
}
</script>
異步請求
from 從一個數組、類數組對象、Promise、迭代器對象或者類 Observable 對象創建一個 Observable
pluck 將每個源值(對象)映射成它指定的嵌套屬性。
filter 類似於大家所熟知的 Array.prototype.filter 方法,此操作符從源 Observable 中 接收值,將值傳遞給 predicate 函數並且只發出返回 true 的這些值
debounceTime 只有在特定的一段時間經過后並且沒有發出另一個源值,才從源 Observable 中發出一個值
distinctUntilChanged 返回 Observable,它發出源 Observable 發出的所有與前一項不相同的項
switchMap 將每個源值投射成 Observable,該 Observable 會合並到輸出 Observable 中, 並且只使用最新投射的Observable中的獲取的值。
<template>
<div>
<input v-model="search">
<div v-if="results">
<ul v-if="results.length">
<li :key="match.title" v-for="match in results">
<p>{{ match.title }}</p>
<p>{{ match.description }}</p>
</li>
</ul>
<p v-else>No matches found.</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
import { from } from 'rxjs'
import {
pluck,
filter,
debounceTime,
distinctUntilChanged,
switchMap,
map
} from 'rxjs/operators'
let a = 1
//模仿異步返回請求數據
//a=1時,代表第一個返回,5秒之后返回
//a=2時,代表第一個返回,2秒之后返回
//(故意制造,先請求的數據后返回的場景)
function fetchTerm(term) {
console.log(term, '--')
let fetchdata = new Promise((resolve, reject) => {
let i = a
console.log('發起請求' + i)
if (i == 1) {
setTimeout(() => {
console.log('獲取請求' + i)
resolve([
{
description: 'description1',
title: '第一次的請求' + term + '第' + i + '次'
},
{
description: 'description2',
title: '第一次的請求p' + term + '第' + i + '次'
}
])
}, 5000)
} else {
setTimeout(() => {
console.log('獲取請求' + i)
resolve([
{
description: 'description1',
title: '第二次的請求' + term + '第' + i + '次'
},
{
description: 'description2',
title: '第二次的請求p' + term + '第' + i + '次'
}
])
a = 0
}, 2000)
}
})
a = a + 1
console.log('ppp')
return from(fetchdata)
}
function formatResult(res) {
console.log(res)
return res.map(obj => {
return {
title: obj.title + 'ooo',
description: obj.description + 'ppp'
}
})
}
export default {
data() {
return {
search: ''
}
},
subscriptions() {
return {
// this is the example in RxJS's readme.
results: this.$watchAsObservable('search').pipe(
pluck('newValue'),
map(a => {
console.log(a)
return a
}),
filter(text => text.length > 2),
debounceTime(500),
distinctUntilChanged(),
switchMap(fetchTerm), //異步請求,先請求的可能后到。解決這個問題
map(formatResult)
)
}
}
}
</script>