透過 Props 可以讓子元件接收來自父元件的「資料」,相對地,父元件則可以接收來自子元件的「事件」,雙方互相傳遞內容,最終可讓子元件變成單純處理畫面樣式的 pure component,而父元件則掌握所有控制權,再次以集中管理的方式讓複雜程序的執行侷限在父元件身上,同時也能加速除錯時不用反覆查找資料出錯的位置。
那麼就來嘗試應用在解決新需求上,首先需要在頁面內新增一個搜尋欄,不同於 Navbar 針對全站的關鍵字查詢功能(預先假設),該搜尋欄位只會針對頁面資料範圍內的書本名稱進行比對。
vm.$emit( eventName, […args] )
:定義需要接收來自子元件的事件先在子元件使用 v-on
監聽事件,並定義好事件名稱 searchBook
及所需傳遞的參數 $event
,再將事件 $emit
傳給父元件。
<div class="BookList">
<h1>{{ navTitle }}</h1>
<p>共計 {{ bookList.length }} 本書</p>
<label>搜尋書本:
<input
type="text"
:value="inputText"
@input="$emit('searchBook', $event)" />
</label>
<div class="bookshelf">
<!-- 略 -->
</div>
</div>
input 需要顯示的 value 值則再次透過 prop
取自於父元件傳入的資料。
props: {
inputText: {
type: String,
required: false,
},
},
在父元件監聽該事件名稱 searchText
,獲得即時輸入的結果為 $event.target.value
,因為沒有需要執行其他動作,因此直接在 <template> 將結果賦值給 inputText
,讓其透過 prop
傳入子元件中的 input 顯示出來。
<BookList
navTitle="All"
:bookList="books"
:inputText="searchText"
@searchBook="searchText = $event.target.value"
/>
接著可透過簡單的正規表達式進行比對,從原本的 API 書單資料中篩選出符合搜尋欄位輸入值的書本名稱,books
陣列資料因此經過變動,而 inputText
則因為動態綁定而能同步更新資料再傳入到子元件中。
computed: {
books() {
const regex = new RegExp(this.searchText, "gi");
return this.$store.getters["allBooks"].filter((book) =>
book.name.match(regex)
);
},
},
試著在全部書單頁面中搜尋書本名包含「IT邦」的列表,根據輸入值即時判斷書單結果;循序漸進地先輸入「IT」兩個字,即時出現書單變化。
最後搜尋「IT邦」顯示共有 19 本書。
與 IT邦幫忙的導覽項目頁面結果相符,正確無誤!