🌐Vue 3 表格數值靠右對齊與 is not defined 錯誤完整解法(含 Excel 匯出)

 

摘要

在 Vue 3 專案中,我們想讓表格中的「數值欄位」在 UI 上靠右對齊,並在匯出 Excel 時維持數字格式(含千分位)。過程中遇到兩個常見錯誤:rightAlignColumns is not definednumericFields is not defined。本文用工程師角度、淺顯語言,帶你一步步修正「變數作用域(scope)」問題,並提供可直接貼上的程式碼範例與檢查清單。




什麼情境會遇到?

  • 你使用 Vue 3 + Composition API 建一個可篩選、可合併列的寬表格

  • 表格資料 keys 都被轉成大寫(例如 Material2 會變成 MATERIAL2

  • 想讓數值欄位在 UI 靠右,同時 Excel 匯出也保持數字型別與千分位格式

  • 在 template 使用 isNumericColumn(hdr) 判斷時,主控台卻噴:

    • ReferenceError: rightAlignColumns is not defined

    • ReferenceError: numericFields is not defined




問題根因:變數作用域(Scope)

  • 你在 exportToExcel() 函式裡面宣告 numericFields,所以只有那個函式看得到它。

  • 但 template 在 render 時會呼叫 isNumericColumn(),如果 isNumericColumn() 去用到 numericFields(或 rightAlignColumns)而 它不在同一個作用域,就會噴 is not defined

**重點:**把「數值欄位集合」提升到 檔案最頂層(module top-level),讓 UIExcel 共用同一組設定,錯誤自然消失。




解法總覽

  1. <script setup> 前半段建立一個大寫的欄位集合 NUMERIC_COLS(Set)。

  2. isNumericColumn(colKey):判斷欄位是否需靠右。

  3. 在 template 的 <td>:class,數值欄位套用 .text-right

  4. 在 CSS 新增 .text-right { text-align: right !important; }

  5. exportToExcel() 中用 const numericFields = [...NUMERIC_COLS] 共用同一組欄位,再設定 Excel 數字格式與千分位。




可直接貼用的程式碼片段

只列出與本主題相關的關鍵部分;其餘原程式維持不變即可。

1) <script setup>:統一的數值欄位集合與判斷函式

<script setup lang="js">
// === 數值欄位(統一大寫,UI靠右 + Excel數字格式共用) ===
const NUMERIC_COLS = new Set([
  'DEMAND_QTY', 'DEAL_QTY',
  'TFT2', 'TFT5',
  'LCM2', 'LCM5',
  'MATERIAL2', 'MATERIAL5' // 注意:用大寫 MATERIAL*
])

// 給 template 用:判斷欄位是否靠右
function isNumericColumn(colKey) {
  return NUMERIC_COLS.has(String(colKey).toUpperCase())
}
</script>

2) <template>:在 <td> 綁定靠右 class

<td
  v-if="rowSpans[rowIndex][hdr] > 0"
  :rowspan="rowSpans[rowIndex][hdr]"
  :class="{
    'material-multiline': hdr === 'MATERIAL1',
    'text-right': isNumericColumn(hdr)
  }"
>
  {{ row[hdr] }}
</td>

3) <style scoped>:定義靠右樣式

.text-right {
  text-align: right !important;
}

4) exportToExcel():共用同一組欄位並套用數字格式

function exportToExcel() {

  // 與 UI 共用的欄位集合,轉成陣列以便 .includes()
  const numericFields = [...NUMERIC_COLS];

  // 將字串千分位轉回數字,避免 Excel 變文字
  const bodyRows = dataToExport.map((row) =>
    tableHeaders.value.map((key) => {
      let v = row[key] ?? ''
      if (numericFields.includes(key) && typeof v === 'string') {
        v = parseFloat(v.replace(/,/g, '')) || 0
      }
      return v
    })
  )

  // 生成工作表
  const ws = XLSX.utils.aoa_to_sheet([groupRow, subHeaderRow, ...bodyRows])
  ws['!merges'] = merges

  // 套用 Excel 數字格式(含千分位)
  tableHeaders.value.forEach((k, colIdx) => {
    if (!numericFields.includes(k)) return
    const colLetter = XLSX.utils.encode_col(colIdx)
    for (let row = 2; row <= bodyRows.length + 1; row++) {
      const addr = `${colLetter}${row}`
      const cell = ws[addr]
      if (cell && typeof cell.v === 'number') {
        cell.t = 'n'
        cell.z = '#,##0'
      }
    }
  })
}


為什麼要「全部大寫」?

你的流程中有這行:

function normalizeKey(key) { return key.toUpperCase() }

也就是說,所有欄位鍵(例如 Material2)最後在表格資料與表頭都會變成 MATERIAL2
因此:

  • NUMERIC_COLS 請使用 大寫 欄位名。

  • 在 Excel 的 numericFields.includes(key) 判斷也要用 大寫的 key 才會命中。




常見錯誤與排除

1) ReferenceError: rightAlignColumns is not defined

原因rightAlignColumns 沒在檔案頂層宣告,或變數名稱更改但 template 未更新。
解法:用本文的 NUMERIC_COLS 寫法,並確認 template 使用 isNumericColumn(hdr)

2) ReferenceError: numericFields is not defined

原因numericFields 宣告在 exportToExcel() 函式裡,但 isNumericColumn()(template 用)也拿它來判斷。
解法:把欄位集合拉到檔案頂層(NUMERIC_COLS),UI 與 Excel 共同使用;在 exportToExcel() 內以 const numericFields = [...NUMERIC_COLS] 取得陣列版本即可。

3) 為什麼我有些欄位沒靠右?

原因:欄位名大小寫不一致,或 NUMERIC_COLS 未包含該欄位。
解法:確定你的 tableHeaders 與資料鍵都是 大寫,並把需要靠右的欄位加入 NUMERIC_COLS




檢查清單(快速自查)

  • NUMERIC_COLS 是否在 檔案最頂層 宣告?

  • NUMERIC_COLS 的欄位名是否為 大寫?(例如 MATERIAL2 而非 Material2

  • template 是否使用 isNumericColumn(hdr) 並在 CSS 有 .text-right

  • exportToExcel() 是否用 const numericFields = [...NUMERIC_COLS] 取得同一組欄位?

  • Excel 內有設定 cell.t = 'n'cell.z = '#,##0' 嗎?




延伸:想自動判斷「像數字的字串」也靠右?

可以把 isNumericColumn() 改成帶值參考的版本,讓「數字字串」也靠右:

function cellShouldRightAlign(colKey, value) {
  if (NUMERIC_COLS.has(String(colKey).toUpperCase())) return true
  return typeof value === 'string' && /^[\d,]+(\.\d+)?$/.test(value)
}

template 改為:

:text-right="cellShouldRightAlign(hdr, row[hdr])"

(這是可選加強版,基本需求用 isNumericColumn 已足夠。)




結語

這個案例的關鍵在於統一管理「數值欄位集合」並放在正確的作用域

  • UI 的靠右對齊與 Excel 的數字格式處理都應該共用同一份設定

  • 一次定義,雙處使用,避免「某處改了、另一處忘了」的錯誤。

留言

這個網誌中的熱門文章

🛠【ASP.NET Core + Oracle】解決 ORA-00904 "FALSE": 無效的 ID 錯誤與資料欄位動態插入顯示問題

🛠【實戰排除教學】從 VS Code 的 _logger 錯誤,到 PowerShell 找不到 npm/serve,再到 Oracle ORA-03135 連線中斷——一次搞懂!

🔎如何在 Oracle PL/SQL 儲存過程中為文字欄位加入換行符號(CHR(10))——以 Updlcmremark 為例