摘要:項(xiàng)目簡(jiǎn)介本次使用了和開(kāi)發(fā)了一個(gè)地址輸入框,主要實(shí)現(xiàn)的功能有限制輸入符合條件的字符并每隔兩位可以自動(dòng)添加用于分割的冒號(hào)。項(xiàng)目屏蔽了的事件處理,同時(shí)使用來(lái)手動(dòng)控制光標(biāo)。繼承于和因此同時(shí)具有和兩者的方法。后面的和都是需要利用最新的來(lái)進(jìn)行判斷的。
項(xiàng)目簡(jiǎn)介
本次使用了RxJS和react開(kāi)發(fā)了一個(gè)mac地址輸入框,主要實(shí)現(xiàn)的功能有限制輸入符合條件的字符1-9,a-f,并每隔兩位可以自動(dòng)添加用于分割的冒號(hào)。項(xiàng)目屏蔽了react的事件處理,同時(shí)使用setSelectionRange來(lái)手動(dòng)控制光標(biāo)。可以查看項(xiàng)目的demo,項(xiàng)目地址
RxJS簡(jiǎn)介RxJS 是 Reactive Extensions 在 JavaScript 上的實(shí)現(xiàn),具體來(lái)說(shuō)是一系列工具庫(kù),包括事件處理,函數(shù)節(jié)流,延時(shí)等函數(shù),RxJS應(yīng)用了’流‘的思想,同時(shí)具有事件和時(shí)間的概念。RxJS也可以用于處理異步流程,比起Promise具有可取消和可延遲,重試等優(yōu)點(diǎn)。Promise vs Observable
RxJS中有兩個(gè)比較重要的概念,分別是Observable和observer。Observable可以使用create,of,from,fromEvent等方法來(lái)產(chǎn)生流,而Observer可以對(duì)流進(jìn)行觀察。最后兩者通過(guò)subscribe來(lái)結(jié)合,例子如下:
var Observable = Rx.Observable.create(observer => { observer.next(2); observer.complete(); return () => console.log("disposed"); }); var Observer = Rx.Observer.create( x => console.log("Next:", x), err => console.log("Error:", err), () => console.log("Completed") ); var subscription = Observable.subscribe(Observer);
來(lái)自構(gòu)建流式應(yīng)用—RxJS詳解
更多關(guān)于RxJS,可以閱讀Introduction | RxJS - Javascript library for functional reactive programming.
項(xiàng)目結(jié)構(gòu)// 監(jiān)聽(tīng)事件,發(fā)起流和處理流 componentDidMount () { this.t = ReactDOM.findDOMNode(this.refs.t) let keydownValue = Rx.Observable.fromEvent(this.t,"keydown").map(e => e.key.toUpperCase()) this.sa = keydownValue.filter(value => value.length === 1 && value.match(/[0-9A-F]/)).subscribe(value => {this.setColon("before");this.insertValue(value); this.setColon();this.setDomValue()}) // 省略類(lèi)似的部分 } // 取消訂閱 componentWillUnmount() this.sa.dispose() // 類(lèi)似的部分省略 } // 一些用到的方法,這里省略 // 取消原生的事件監(jiān)聽(tīng) render() { return (項(xiàng)目詳解e.preventDefault()} ref="t"/>); }
首先使用Rx.Observable.fromEvent來(lái)監(jiān)聽(tīng)輸入框的按鍵事件,并獲取按鍵的key值,保存為keydownValue
let keydownValue = Rx.Observable.fromEvent(this.t,"keydown") .map(e => e.key.toUpperCase())
接著首先考慮輸入字符的情況,在這里,顯示篩選出按鍵符合要求的情況,接著在subscribe中對(duì)數(shù)據(jù)進(jìn)行處理。在插入新的字符之前和之后,都需要判斷是否在前面加上冒號(hào),最后使用setDomValue來(lái)讓保存在state中的value顯示到輸入框上。
this.sa = keydownValue .filter(value => value.length === 1 && value.match(/[0-9A-F]/)) .subscribe(value => { this.setColon("before"); this.insertValue(value); this.setColon(); this.setDomValue() })
判斷是否需要插入冒號(hào)的函數(shù)setColon,需要排除前面沒(méi)有字符和周?chē)呀?jīng)有冒號(hào)的情況。
setColon = type => this.state.value.length && (type !== "before" ? !this.isNearColon() : !this.isLastColon()) && !(this.state.value.slice(0, this.state.pos).replace(/:/g, "").length%2) && this.insertValue(":")
插入新字符的函數(shù)。在記錄的光標(biāo)位置pos值上插入新的字符,然后改變光標(biāo)位置。如果在字符末尾有未完成的字符對(duì)(即1f:的形式)又在中間插入新的字符串且字符對(duì)已經(jīng)到達(dá)六個(gè),則刪掉最后一個(gè)字符對(duì)。
insertValue = value => { if (this.state.value.length !== 17) { this.setState({ ...this.state, value: this.state.value.slice(0, this.state.pos) + value + this.state.value.slice(this.state.pos, this.state.value.length) }) this.setPos(this.state.pos + 1) if (this.state.value.split(":").length === 7) { this.setState({ ...this.state, value: this.state.value.slice(0, this.state.value.lastIndexOf(":")) }) } }}
接著是講解關(guān)于刪除的流,篩選按鍵值為"BACKSPACE"的流,執(zhí)行deleteValue方法和setDomValue
this.sb = keydownValue.filter(value => value === "BACKSPACE") .subscribe(() => { this.deleteValue() this.setDomValue() })
deleteValue,在value和位置都大于零時(shí)才執(zhí)行,如果刪除后字符后,新的最后一個(gè)字符是冒號(hào),則自動(dòng)刪掉該冒號(hào)。
deleteValue = () => { if (this.state.value.length && this.state.pos) { this.setState({ ...this.state, value: this.state.value.slice(0, this.state.pos - 1) + this.state.value.slice(this.state.pos, this.state.value.length) }) this.setPos(this.state.pos - 1) if (this.isLastColon()) { this.deleteValue() } } }
接著是訂閱了左右方向鍵移動(dòng)的流,比較簡(jiǎn)單,就不詳細(xì)解釋了。
this.sc = keydownValue .filter(value => value === "ARROWLEFT") .subscribe(() => this.moveLeft()) this.sd = keydownValue .filter(value => value === "ARROWRIGHT") .subscribe(() => this.moveRight()) moveLeft = () => this.state.pos > 0 && this.setState({...this.state, pos: this.state.pos - 1}) moveRight = () => this.state.pos !== this.state.value.length && this.setState({...this.state, pos: this.state.pos + 1})
最后是讓光標(biāo)跳到pos的處理,setSelectionRange本用于文字的選擇,但如果前兩個(gè)參數(shù)為一樣的數(shù)值,可以達(dá)到讓光標(biāo)跳到指定位置的效果。
this.se = keydownValue.subscribe(() => this.goPos()) goPos = () => this.t.setSelectionRange(this.state.pos, this.state.pos)170624更新
原本的模式跟react關(guān)系較少,因此修改調(diào)整了一下,主要的變化是啟用了Subject,setStateAsync,在這里先介紹一下。
Subject繼承于Obserable和Observer,因此同時(shí)具有Obserable和Observer兩者的方法。通過(guò)來(lái)自于Observable的multicast方法可以掛載subject,并得到擁有相同執(zhí)行環(huán)境的多路的新的Observable,關(guān)于他的訂閱實(shí)際上是掛載在subject上。最后需要手動(dòng)connect。 RxJS 核心概念之Subject,30 天精通 RxJS(24): Observable operators - multicast, refCount, publish, share
var source = Rx.Observable.from([1, 2, 3]); var multicasted = source.multicast(new Rx.Subject()) // 通過(guò)`subject.subscribe({...})`訂閱Subject的Observer: multicasted.subscribe({ next: (v) => console.log("observerA: " + v) }); multicasted.subscribe({ next: (v) => console.log("observerB: " + v) }); // 讓Subject從數(shù)據(jù)源訂閱開(kāi)始生效: multicasted.connect();
其實(shí)可以用refCount來(lái)避免connect,用publish來(lái)代替 multicast(new Rx.Subject()),最后用share代替publish 和 refCount,因此代碼可以寫(xiě)成
var multicasted = source.share()
組件改為受控組件之后,setState中的異步特性展示了出來(lái),setState后的下一步獲取setState并不是最新的state,影響了程序的正常使用。
例如之前的新增函數(shù)的訂閱。后面的inserValue和setColon都是需要利用最新的state來(lái)進(jìn)行判斷的。
this.sa = keydownValue .filter(value => value.length === 1 && value.match(/[0-9A-F]/)) .subscribe(value => { this.setColon("before"); this.insertValue(value); this.setColon(); this.setDomValue() })
可以在setState的第二個(gè)參數(shù)中傳入回調(diào)函數(shù)來(lái)解決這個(gè)問(wèn)題,于是函數(shù)變成了這樣,一層又一層的回調(diào),十分不美觀
this.sa = keydownValue .filter(value => value.length === 1 && value.match(/[0-9A-F]/)) .subscribe(value => { this.setColon("before", () => { this.insertValue(value, () => { this.setColon() }) }) })
接著在網(wǎng)上找到了setStateAsync的函數(shù),原理就是將setState轉(zhuǎn)換成promise的形式,接著就能愉快的使用async await的語(yǔ)法來(lái)修改state了。React中setState同步更新策略
setStateAsync = state => new Promise(resolve => this.setState(state,resolve))
在componentDidMount中把keydownValue設(shè)置為同時(shí)具有Observable和Observe的方法的Subject,他一方面可以使用Observer的onNext方法來(lái)添加新的數(shù)據(jù),另一方面可以繼續(xù)使用Observable的操作符來(lái)對(duì)數(shù)據(jù)進(jìn)行處理。
this.keydownValue = new Rx.Subject() let multicasted = this.keydownValue.map(e => e.key.toUpperCase()).share() this.sa = multicasted .filter(value => value.length === 1 && value.match(/[0-9A-F]/)) .subscribe(async value => { await this.setColon("before") await this.insertValue(value) await this.setColon() this.goPos() }) //下略
組件的render函數(shù)修改為
handleE函數(shù)繼續(xù)禁止默認(rèn)事件,調(diào)用了新設(shè)置的Subject(keydownValue)的onNext方法,可以使得綁定在keydownValue上的訂閱獲得數(shù)據(jù)
handleE = e => {e.preventDefault();this.keydownValue.onNext(e)}
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/94223.html
摘要:我們將使用,這是一個(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)建完整的We...
摘要:面試流程如果你時(shí)間緊張或是在職,大部分大公司是支持第一輪電話面試的,而騰訊,阿里的面試基本前兩輪都是電話面。組員面總體來(lái)說(shuō)考察的東西較基礎(chǔ)。也有會(huì)問(wèn)你設(shè)計(jì)模式,各種繼承方法的對(duì)于大廠的面試來(lái)說(shuō),重要性可能比還要高。 背景 我最近一個(gè)月面試了20來(lái)個(gè)公司,其中有你們應(yīng)該都聽(tīng)過(guò)的bat,今日頭條,京東,網(wǎng)易,大疆,oppo,還有shopee,招商金科,有贊等比較不錯(cuò)的公司,收獲了六個(gè)off...
摘要:?jiǎn)卧獪y(cè)試,測(cè)試一個(gè)簡(jiǎn)單的組件。接口測(cè)試,用戶(hù)信息接口測(cè)試。學(xué)習(xí)借鑒,一些使用做測(cè)試的開(kāi)源項(xiàng)目。這里使用到的內(nèi)置斷言斷言結(jié)果值等于我們想要的預(yù)期值,則測(cè)試通過(guò)。在里放入一個(gè)函數(shù),函數(shù)自動(dòng)執(zhí)行,里面執(zhí)行的結(jié)果必須拋出錯(cuò)誤,則測(cè)試通過(guò)。 目錄 1、為什么選擇 AVA ?2、API 概覽。3、準(zhǔn)備工作。4、單元測(cè)試,測(cè)試一個(gè)簡(jiǎn)單的工具函數(shù)。5、使用 Promise、Async/await、Ob...
摘要:正式發(fā)布已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在中的運(yùn)行速度問(wèn)題。文章內(nèi)容包括什么是內(nèi)存,內(nèi)存生命周期,中的內(nèi)存分配,內(nèi)存釋放,垃圾收集,種常見(jiàn)的內(nèi)存泄漏以及如何處理內(nèi)存泄漏的技巧。 1. Angular 6 正式發(fā)布 Angular 6.0.0 已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在 Angular 中的運(yùn)行速度問(wèn)題。Angular v6 是統(tǒng)一整體框架、Material ...
摘要:正式發(fā)布已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在中的運(yùn)行速度問(wèn)題。文章內(nèi)容包括什么是內(nèi)存,內(nèi)存生命周期,中的內(nèi)存分配,內(nèi)存釋放,垃圾收集,種常見(jiàn)的內(nèi)存泄漏以及如何處理內(nèi)存泄漏的技巧。 1. Angular 6 正式發(fā)布 Angular 6.0.0 已正式發(fā)布,新版本重點(diǎn)關(guān)注工具鏈以及工具鏈在 Angular 中的運(yùn)行速度問(wèn)題。Angular v6 是統(tǒng)一整體框架、Material ...
閱讀 1493·2021-11-24 11:16
閱讀 2700·2021-07-28 12:32
閱讀 2309·2019-08-30 11:22
閱讀 1448·2019-08-30 11:01
閱讀 605·2019-08-29 16:24
閱讀 3553·2019-08-29 12:52
閱讀 1633·2019-08-29 12:15
閱讀 1340·2019-08-29 11:18