高級vue組件模式5

NO IMAGE

05 使用 $refs 訪問子組件引用

目標

在之前的文章中,詳細闡述了子組件獲取父組件所提供屬性及方法的一些解決方案,如果我們想在父組件之中訪問子組件的一些方法和屬性怎麼辦呢?設想以下一個場景:

  • 當前的 custom-button 組件中,有一個 input 元素
  • 我們期望當 toggle 的開關狀態為時,顯示 input 元素並自動獲得焦點

這裡要想完成目標,需要獲取某個組件或者每個元素的引用,在不同的 mvvm 框架中,都提供了相關特性來完成這一點:

  • angularjs: 可以使用依賴注入的 $element 服務
  • Angular: 可以使用 ViewChild、ContentChild 或者 template ref 來獲取引用
  • react: 使用 ref 屬性聲明獲取引用的邏輯

在 vue 中,獲取引用的方法與 react 類似,通過聲明 ref 屬性來完成。

實現

首先,在 custom-button 組件中增加一個 input 元素,如下:

<input v-if="on" ref="input" type="text" placeholder="addtional messages">

注意這裡的 ref="input",這樣在組件內部,可以通過 this.$refs.input 獲得該元素的引用,為了實現目標中提及的需求,再添加一個新的方法 focus 來使 input 元素獲取焦點,如下:

focus() {
this.$nextTick(function() {
this.$refs.input.focus();
});
},

注意這裡的 this.$nextTick,正常情況下,直接調用 input 的 focus 方法是沒有問題的,然而卻不行。因為 input 的渲染邏輯取決於 prop 屬性 on 的狀態,如果直接調用 focus 方法,這時 input 元素的渲染工作很可能還未結束,這時 this.$refs.input 所指向的引用值為 undefined,繼續調用方法則會拋出異常,因此我們利用 this.$nextTick 方法,將調用的邏輯延遲至下次 DOM 更新循環之後執行。

同理,在 app 組件中,為 custom-button 添加一個 ref 屬性,如下:

<custom-button ref="customButton" :on="status.on" :toggle="toggle"></custom-button>

之後修改 onToggle 方法中的邏輯以滿足目標中的需求,當 toggle 組件狀態為開時,調用 custom-button 組件的 focus 方法,如下:

onToggle(on) {
if (on) this.$refs.customButton.focus();
console.log("toggle", on);
}

成果

點擊按鈕會發現,每當開關為開時,input 元素都會顯示,並會自動獲得焦點。

你可以下面的鏈接來看看這個組件的實現代碼以及演示:

總結

當期望獲得子元素或者子組件的引用時,切記使用 ref 和 $refs 來解決問題。文章中所舉例子的交互,在實際場景中很常見,比如:

  • 當通過一個 icon 觸發搜索框時,期望自動獲得焦點
  • 當表單校驗失敗時,期望自動獲得發生錯誤的表單項的焦點
  • 當複雜列表的篩選器展開時,期望第一個篩選單元獲得焦點

這幾種情況下,都可以使用該模式來高效地解決問題,而不是通過使用 DOM 中的 api 或者引入 jquery 獲取相關元素再進行操作。

目錄

github gist

相關文章

高級Vue組件模式(9)

高級Vue組件模式(8)

高級Vue組件模式(7)

高級vue組件模式6