Vue component 中 :bind
和 v-model
分別是「單向資料流」以及 「雙向綁定」,在單向資料流當中,有時候我們會需要將 Vue component 中的資料或狀態回傳出來,所以需要透過自訂事件的方式,通知上層的 component 接收。更進一步,有時候我們希望帶進 component 的參數可以像 <input>
一樣,只要有變動、大家都會跟著調整。因此接下來就會用「搜尋」逐一說明「自訂事件」和「客製 v-model
」。
常見的「搜尋」會包括「搜尋欄位」和「關鍵字」兩個部分,基本建置如下面步驟:
SearchBar.vue
,保留兩個通知,分別是「有搜尋資料要進行搜尋」以及「清除搜尋資料」:<template>
<div>
<select v-model="searchColumn">
<option v-for="(column, index) in searchColumns" :key="index"
:value="column['value']">
{{column['label']}}
</option>
</select>
<input v-model="keyword" @keyup.enter="search"/>
</div>
</template>
<script>
export default {
name: "SearchBar",
props: {
searchColumns: {
type: Array,
required: true,
},
},
data() {
return {
searchColumn: this.searchColumns[0].value,
keyword: undefined,
}
},
watch: {
searchColumn() {
this.search();
},
},
methods: {
search() {
if (this.validSearch()) {
// 通知上層 component 要搜尋,並回傳搜尋資訊
} else if (!this.keyword) {
// 通知上層 component 清除搜尋
}
},
validSearch() {
const hasSearchColumn = !!this.searchColumn;
const hasKeyword = !!this.keyword;
return hasSearchColumn && hasKeyword;
},
}
}
</script>
this.$emit(<事件名稱>, <回傳資料>)
: search() {
if (this.validSearch()) {
const searchData = {
column: this.searchColumn,
keyword: this.keyword
};
this.$emit('on-search', searchData);
} else if (!this.keyword) {
this.$emit('on-clear');
}
},
<template>
<search-bar :search-columns="user.searchColumns"></search-bar>
</template>
<script>
import SearchBar from "./SearchColumn";
export default {
name: "test4",
components: { SearchBar },
data() {
return {
user: {
searchColumns: [
{ value: 'id', label: 'ID' },
{ value: 'name', label: '姓名' },
{ value: 'email', label: '信箱' },
],
}
};
},
}
</script>
v-on
綁定要執行的方法、接收通知。可以注意到 toSearch
和 clearSearch
兩個方法,如果有回傳資料再建立參數、並由 Vue 框架自動注入:<template>
<search-bar
:search-columns="user.searchColumns"
@on-search="toSearch"
@on-clear="clearSearch">
</search-bar>
</template>
methods: {
// 有回傳資料再加上參數即可
toSearch(searchData) {
console.log(searchData);
},
clearSearch() {
console.log('search cleared');
}
}
小結上面的結果,只要透過 this.$emit
和 v-on:
兩者之間的搭配,就可以達到客製事件。
我們可以看到每次要進行搜尋時,都會回傳資料,所以其實可以透過 v-model
綁定整個 { column, keyword }
,這樣上層跟下層之間就可以直接連動。使用 v-model
的改寫步驟如下:
props
中加入 value
參數,注意就名稱是固定用法: props: {
value: {
type: Object,
required: true,
},
// ...
}
data
資料,順帶一提,props
的參數不可以綁在 v-model
,要改成 data
或是 computed
資料: data() {
return {
searchColumn: this.value.value || this.searchColumns[0].value,
keyword: this.value.keyword,
}
},
input
,注意!名稱是固定用法: search() {
if (this.validSearch()) {
const searchData = {
column: this.searchColumn,
keyword: this.keyword
};
// 從原本客製事件名稱改為「input」
this.$emit('input', searchData);
} else if (!this.keyword) {
this.$emit('on-clear');
}
},
v-model
綁定<template>
<search-bar
v-model="user.searchData"
:search-columns="user.searchColumns" @on-clear="clearSearch">
</search-bar>
</template>
<script>
import SearchBar from "./SearchColumn";
export default {
name: "test4",
components: { SearchBar },
data() {
return {
user: {
// ...
// 增加作為 v-model 使用的資料
searchData: {
column: 'name',
keyword: undefined,
}
}
};
},
}
</script>
改寫過後,當我們使用 watch
監控 user.searchData
,可以看到可以達到原本客製事件效果。 小結上面改寫結果,利用 value
參數 和 input
事件名稱就可以做到 v-model
!
無論是客製事件或是 v-model
雙向綁定,都讓 component 的使用更靈活也更方便。 Vue component 基本使用介紹完之後,接著我們就要來看 Nuxt 的 page
有哪些新功能啦!