本篇把Vue Nuxt 3頁面中的下拉選單抽出為元件/組件(Components)。
元件/組件是可被其他頁面複用的template,Nuxt約定統一放在components目錄,範例上方的導覽列compnents/Header.vue和左側功能選單components/Sidebar.vue即為元件,也就是layouts/default.vue中的<Header />和<Sidebar />。
和Composable的區別是,Composable是用來封裝可複用的邏輯,而元件則是可複用的模板(畫面),兩者的責任是分開的,例如可能多個元件使用同一個composable。
事前要求
參考「Vue Nuxt 3 抽取共用邏輯為組合式函式(Composables)」。
建立下拉選單元件
在Nuxt專案的components目錄下新增CountrySelect.vue,內容為國家代碼的下拉選單的模板及取得選單內容的邏輯。
使用defineModel(Vue 3.4開始支援)設定雙向綁定屬性modelValue,並在<select>的使用v-model="modelValue"實現雙向綁定。
所謂的雙向綁定(two-way binding),是指元件內部的值會與父組件的值同步,當元件內的值改變時,父組件也會跟著改變;雙向是指父組件傳入子組件的參數(props)和子組件異動這個屬性值時對父組件發出的事件通知(emits)。
components/CountrySelect.vue
<template>
<select v-model="modelValue" :disabled="pending">
<option value="">全部國家</option>
<option v-for="(name, code) in countryMap" :key="code" :value="code">
{{ name }} ({{ code }})
</option>
</select>
</template>
<script setup lang="ts">
import { useCountries } from '~/composables/useCountries'
const modelValue = defineModel();
const { countryMap, pending, loadCountries } = useCountries()
loadCountries()
</script>
使用下拉選單元件
把原本pages/home/export/index.vue的下拉選單改為<CountrySelect>。
要注意仍要保留loadCountries()來取得從後端獲取值的countryMap,你可能會想在<CountrySelect>中不是已經取過一次這個「跨元件的共享狀態」了嗎?問題是如果重新整理http://localhost:3000/home/export這個頁面,對Nuxt來說是初始整個應用程式,此時在渲染此頁面時會先於子組件<CountrySelect>去後端取countryMap的值,所以countryMap仍會是null,然後在父組件使用{{ countryMap[order.country] }}就發生錯誤。
pages/home/export/index.vue
<template>
<div>
<h1>出口業務</h1>
<!--...-->
<label>
出口國家:
<CountrySelect v-model="country" />
</label>
<br>
<!--...-->
<ul v-else>
<li v-for="order in orders" :key="order.id">
<NuxtLink :to="`/home/export/${order.id}`">
訂單 #{{ order.id }},
狀態: {{ order.status }},
出口國家:{{ countryMap[order.country] }}
</NuxtLink>
</li>
</ul>
</div>
</template>
<script setup>
// ...
const { countryMap, loadCountries } = useCountries()
loadCountries()
// ...
</script>
<!--...-->
接下來參考「Vue Nuxt 3 分頁」。
沒有留言:
張貼留言