AdSense

網頁

2026/1/7

Vue Nuxt 3 code mapping

本篇把Vue Nuxt 3頁面中的下拉選單改用code mapping的方式改寫。


原本訂單例表的出口國家是顯示代碼,但通常需要轉成較易讀的文字,例如US代表美國,這種代碼與文字的轉換就叫code mapping。


事前要求

參考「Vue Nuxt 3 useFetch 多查詢參數」中的下拉選單。


修改pages/home/export/index.vue

原本的下拉選單值和文字是寫死的,這邊抽出來為物件countryMap,然後在下拉選單的<option>用Vue的v-for迴圈渲染物件。

v-for="(name, code) in countryMap"語法中的name為value(例如"美國"),code為key(例如"US")。

在查詢出來訂單資料中使用{{ countryMap[order.country] }}來顯示對應的國家名稱。

pages/home/export/index.vue

<template>
  <div>
    <h1>出口業務</h1>

    <label>
      訂單狀態:
      <input v-model="status" placeholder="pending/done">
    </label>
    <br>
    <label>
      出口國家:
      <select v-model="country">
        <option value="">全部國家</option>
        <option v-for="(name, code) in countryMap" :key="code" :value="code">
          {{ name }} ({{ code }})
        </option>
      </select>
    </label>
    <br>

    <button @click="search">查詢</button>

    <!--省略-->

    <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>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const countryMap = {
  US: '美國',
  JP: '日本',
  CN: '中國',
  KR: '韓國',
  VN: '越南'
}

// 省略
</script>

<!--省略-->


選單資料移到後端API

通常代碼類的下拉選單很多地方都會用到,所以接著把countryMap的內容搬到後端API [GET] /api/countries統一取得國家代碼。

新增server/api/countries.get.js來模擬/api/countries

server/api/countries.get.js

export default defineEventHandler(async () => {
  await new Promise((r) => setTimeout(r, 1000)); // 模擬延遲

  const countryMap = {
    US: "美國",
    JP: "日本",
    CN: "中國",
    KR: "韓國",
    VN: "越南",
  };
  return countryMap;
});

則原本頁面的countryMap改由後端API/api/countries取得。當畫面同時有多個API(例如現在有訂單和國家代碼)時,可以各自設計loading和error效果,例如countryPendingorderPending

pages/home/export/index.vue

<template>
  <div>
    <h1>出口業務</h1>

    <label>
      訂單狀態:
      <input v-model="status" placeholder="pending/done">
    </label>
    <br>
    <label>
      出口國家:
      <select v-model="country" :disabled="countryPending">
        <option value="">全部國家</option>
        <option v-for="(name, code) in countryMap" :key="code" :value="code">
          {{ name }} ({{ code }})
        </option>
      </select>
    </label>
    <br>

    <button @click="search">查詢</button>

    <p v-if="orderPending">資料載入中...</p>
    <p v-else-if="error" class="error">資料載入失敗</p>
    <p v-else-if="orders.length === 0">沒有訂單資料</p>
    <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>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

const status = ref(route.query.status || '')
const queryStatus = ref(route.query.status || '')
const country = ref(route.query.country || '')
const queryCountry = ref(route.query.country || '')

const { data: orders, pending: orderPending, error, refresh } = useFetch('/api/orders', {
  query: {
    status: queryStatus,
    country: queryCountry,
  },
  default: () => [],
})

const { data: countryMap, pending: countryPending } = useFetch('/api/countries', {
  default: () => ({}), // default的型別要和API回傳的資料結構一致
})

// ...
</script>

<!-- ... -->

github


效果如下:



接著可以把取得國家代碼的邏輯抽離為Composables

沒有留言:

AdSense