作者|Sunil Sandhu 譯者|無明 在工作中使用了 Vue 之后,我已經(jīng)對(duì)它有了相當(dāng)深入的了解。同時(shí),我也對(duì) React 感到好奇。我閱讀了 React 的文檔,也看了一些教程視頻,雖然它們很棒,但我真正想知道的是 React 與 Vue 有哪些區(qū)別。這里所說的區(qū)別,并不是指它們是否都具有虛擬 DOM 或者它們?nèi)绾武秩卷撁妗N艺嬲胍龅氖菍?duì)它們的代碼進(jìn)行并排比較,并搞清楚在使用這兩個(gè)框架開發(fā)應(yīng)用時(shí)究竟有哪些差別。 我決定構(gòu)建一個(gè)標(biāo)準(zhǔn)的待辦事項(xiàng)應(yīng)用程序,用戶可以添加和刪除待辦事項(xiàng)。我分別使用它們默認(rèn)的 CLI(React 的 create-react-app 和 Vue 的 vue-cli)來創(chuàng)建這個(gè)應(yīng)用。先讓我們看一下這兩個(gè)應(yīng)用的外觀: 兩個(gè)應(yīng)用程序的 CSS 代碼幾乎完全相同,但代碼存放的位置存在差別。 它們的結(jié)構(gòu)也幾乎完全相同,唯一的區(qū)別是 React 有三個(gè) CSS 文件,而 Vue 則沒有。這是因?yàn)?React 組件需要一個(gè)附帶的文件來保存樣式,而 Vue 采用包含的方式,將樣式聲明在組件文件中。 從理論上講,你可以使用老式的 style.css 文件來保存整個(gè)頁面的樣式,這完全取決于你自己。不管怎樣,還是展示一下.vue 文件中的 CSS 代碼長(zhǎng)什么樣: 看完樣式方面的問題,現(xiàn)在讓我們深入了解其他細(xì)節(jié)! 如何改變數(shù)據(jù)? 我們說“改變數(shù)據(jù)”(mutate data),實(shí)際上就是指修改已經(jīng)保存好的數(shù)據(jù)。比如,如果我們想將一個(gè)人的名字從 John 改成 Mark,我們就要“改變數(shù)據(jù)”。這就是 React 和 Vue 的關(guān)鍵區(qū)別之一。Vue 創(chuàng)建了一個(gè)數(shù)據(jù)對(duì)象,我們可以自由地更新數(shù)據(jù)對(duì)象,而 React 創(chuàng)建了一個(gè)狀態(tài)對(duì)象,要更新狀態(tài)對(duì)象,需要做更多瑣碎的工作。下面是 React 的狀態(tài)對(duì)象和 Vue 的數(shù)據(jù)對(duì)象之間的對(duì)比: React 的狀態(tài)對(duì)象: Vue 的數(shù)據(jù)對(duì)象: 從圖中可以看到,我們傳入的是相同的數(shù)據(jù),它們只是標(biāo)記的方式不一樣。但它們?cè)谌绾胃淖冞@些數(shù)據(jù)方面卻有很大的區(qū)別。 假設(shè)我們有一個(gè)數(shù)據(jù)元素 name:'Sunil'。 在 Vue 中,我們通過 this.name 來引用它。我們也可以通過 this.name='John'來更新它,這樣會(huì)把名字改成 John。 在 React 中,我們通過 this.state.name 來引用它。關(guān)鍵的區(qū)別在于,我們不能簡(jiǎn)單地通過 this.state.name='John'來更新它,因?yàn)?React 對(duì)此做出了限制。在 React 中,我們需要使用 this.setState({name:'John'}) 的方式來更新數(shù)據(jù)。 在了解了如何修改數(shù)據(jù)之后,接下來讓我們通過研究如何在待辦事項(xiàng)應(yīng)用中添加新項(xiàng)目來深入了解其他細(xì)節(jié)。 如何創(chuàng)建新待辦事項(xiàng)? React: createNewToDoItem = () => { this.setState( ({ list, todo }) => ({ list: [ ...list, { todo } ], todo: '' }) ); }; Vue: createNewToDoItem() { this.list.push( { 'todo': this.todo } ); this.todo = ''; } React 是怎么做到的? 在 React 中,input 有一個(gè)叫作 value 的屬性。我們通過幾個(gè)與創(chuàng)建雙向綁定相關(guān)的函數(shù)來自動(dòng)更新 value。React 通過為 input 附加 onChange 函數(shù)來處理雙向綁定。 value={this.state.todo} onChange={this.handleInput}/> 只要 input 的值發(fā)生變化,就會(huì)執(zhí)行 handleInput 函數(shù)。這個(gè)函數(shù)會(huì)將狀態(tài)對(duì)象中 todo 字段的值改為 input 中的值。這個(gè)函數(shù)看起來像這樣: handleInput = e => { this.setState({ todo: e.target.value }); }; 現(xiàn)在,只要用戶按下頁面上的 + 按鈕,createNewToDoItem 就會(huì)調(diào)用 this.setState,并傳入一個(gè)函數(shù)。這個(gè)函數(shù)有兩個(gè)參數(shù),第一個(gè)是狀態(tài)對(duì)象的 list 數(shù)組,第二個(gè)是 todo(由 handleInput 函數(shù)更新)。然后函數(shù)會(huì)返回一個(gè)新對(duì)象,這個(gè)對(duì)象包含之前的整個(gè) list,然后將 todo 添加到 list 的末尾。 最后,我們將 todo 設(shè)置為空字符串,它也會(huì)自動(dòng)更新 input 中的值。 Vue 是怎么做到的? 在 Vue 中,input 有一個(gè)叫作 v-model 的屬性。我們可以用它來實(shí)現(xiàn)雙向綁定。 v-model 將 input 綁定到數(shù)據(jù)對(duì)象 toDoItem 的一個(gè) key 上。在加載頁面時(shí),我們將 toDoItem 設(shè)置為空字符串,比如 todo:’’。如果 todo 不為空,例如 todo:’add some text here',那么 input 就會(huì)顯示這個(gè)字符串。我們?cè)?input 中輸入的任何文本都會(huì)綁定到 todo。這實(shí)際上就是雙向綁定(input 可以更新數(shù)據(jù)對(duì)象,數(shù)據(jù)對(duì)象也可以更新 input)。 因此,回看之前的 createNewToDoItem() 代碼塊,我們將 todo 的內(nèi)容放到 list 數(shù)組中,然后將 todo 更新為空字符串。 如何刪除待辦事項(xiàng)? React: deleteItem = indexToDelete => { this.setState(({ list }) => ({ list: list.filter((toDo, index) => index !== indexToDelete) })); }; React 是怎么做到的? 雖然 deleteItem 函數(shù)位于 ToDo.js 中,我仍然可以在 ToDoItem.js 中引用它,就是將 deleteItem() 函數(shù)作為的 prop 傳入: 這樣可以讓子組件訪問傳入的函數(shù)。我們還綁定了 this 和參數(shù) key,傳入的函數(shù)需要通過 key 來判斷要?jiǎng)h除哪個(gè) ToDoItem。在 ToDoItem 組件內(nèi)部,我們執(zhí)行以下操作: 我使用 this.props.deleteItem 來引用父組件中的函數(shù)。 Vue: this.$on(‘delete’, (event) => { this.list = this.list.filter(item => item.todo !== event) }) Vue 是怎么做到的? Vue 的方式稍微有點(diǎn)不同,我們基本上要做三件事。 首先,我們需要在元素上調(diào)用函數(shù): - 然后我們必須創(chuàng)建一個(gè) emit 函數(shù)作為子組件內(nèi)部的一個(gè)方法(在本例中為 ToDoItem.vue),如下所示: deleteItem(todo) { this.$parent.$emit(‘delete’, todo) } 然后我們的父函數(shù),也就是 this.$on(’delete’) 事件監(jiān)聽器會(huì)在它被調(diào)用時(shí)觸發(fā)過濾器函數(shù)。 簡(jiǎn)單地說,React 中的子組件可以通過 this.props 訪問父函數(shù),而在 Vue 中,必須從子組件中向父組件發(fā)送事件,然后父組件需要監(jiān)聽這些事件,并在它被調(diào)用時(shí)執(zhí)行函數(shù)。 這里值得注意的是,在 Vue 示例中,我也可以直接將 $emit 部分的內(nèi)容寫在 @click 監(jiān)聽器中,如下所示: - 這樣可以減少一些代碼,不過也取決于個(gè)人偏好。 如何傳遞事件監(jiān)聽器? React: 簡(jiǎn)單事件(如點(diǎn)擊事件)的事件監(jiān)聽器很簡(jiǎn)單。以下是我們?yōu)樘砑有麓k事項(xiàng)的按鈕創(chuàng)建 click 事件的示例: + 非常簡(jiǎn)單,看起來很像是使用純 JS 處理內(nèi)聯(lián)的 onClick 事件。而在 Vue 中,需要花費(fèi)更長(zhǎng)的時(shí)間來設(shè)置事件監(jiān)聽器。input 標(biāo)簽需要處理 onKeyPress 事件,如下所示: 只要用戶按下了'enter'鍵,這個(gè)函數(shù)就會(huì)觸發(fā) createNewToDoItem 函數(shù),如下所示: handleKeyPress = (e) => { if (e.key === ‘Enter’) { this.createNewToDoItem(); } }; Vue: 在 Vue 中,要實(shí)現(xiàn)這個(gè)功能非常簡(jiǎn)單。我們只需要使用 @符號(hào)和事件監(jiān)聽器的類型。例如,要添加 click 事件偵聽器,我們可以這樣寫: + 注意:@click 實(shí)際上是寫 v-on:click 的簡(jiǎn)寫。在 Vue 中,我們可以將很多東西鏈接到事件監(jiān)聽器上,例如.once 可以防止事件監(jiān)聽器被多次觸發(fā)。在編寫用于處理按鍵特定事件偵聽器時(shí),還可以使用一些快捷方式。我發(fā)現(xiàn),在 React 中為添加待辦事項(xiàng)按鈕創(chuàng)建一個(gè)事件監(jiān)聽器需要花費(fèi)更長(zhǎng)的時(shí)間。而在 Vue 中,我可以簡(jiǎn)單地寫成: 如何將數(shù)據(jù)傳給子組件? React: 在 React 中,當(dāng)創(chuàng)建子組件時(shí),我們將 props 傳給它。 我們將 todo props 傳給了 ToDoItem 組件。從現(xiàn)在開始,我們可以在子組件中通過 this.props 引用它們。因此,要訪問 item.todo,我們只需調(diào)用 this.props.todo。 Vue: 在 Vue 中,當(dāng)創(chuàng)建子組件時(shí),我們將 props 傳給它。 :todo='item.todo' :key='list.indexOf(item)' :id='list.indexOf(item)' > 然后,我們將它們加入到子組件的 props 數(shù)組,如:props:[‘id’,'todo']。然后可以在子組件中通過名字來引用它們,入'id'和'todo'。 如何將數(shù)據(jù)發(fā)送回父組件? React: 我們?cè)谡{(diào)用子組件時(shí)將函數(shù)作為 prop 傳給子組件,然后通過任意方式調(diào)用子組件的函數(shù),這將觸發(fā)位于父組件中的函數(shù)。我們可以在“如何刪除待辦事項(xiàng)”一節(jié)中看到整個(gè)過程的示例。 Vue: 在我們的子組件中,我們只需寫一個(gè)函數(shù),讓它向父函數(shù)發(fā)回一個(gè)值。在父組件中,我們寫了一個(gè)函數(shù)來監(jiān)聽這個(gè)值,然后觸發(fā)函數(shù)調(diào)用。我們可以在“如何刪除待辦事項(xiàng)”一節(jié)中看到整個(gè)過程的示例。 |
|