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