🌐Vue 表格篩選視窗被遮住怎麼辦?一次看懂表格空白列高度、下拉篩選框顯示問題與修正方式
Vue 表格篩選視窗被遮住怎麼辦?新手也能看懂的完整教學
在做後台系統、報表頁面或資料查詢頁時,最常見的一種畫面就是「大表格」。
像是生產資料、訂單資料、客戶資料、排程結果,通常都會做成可以搜尋、可以篩選、可以匯出的表格。
但很多人在實作這種功能時,常常會遇到兩個很煩的問題:
- 點開欄位篩選時,下拉視窗被切掉,看不到完整內容
- 當篩選後沒有資料時,提示訊息那一列太矮,看起來很空、很怪
這篇文章會用完全新手也能理解的方式,帶你一步一步看懂:
- 為什麼表格篩選框會被遮住
- 為什麼「查無資料」那一列看起來很醜
- 怎麼用 Vue + CSS 修正
- 怎麼讓畫面更像正式商業系統
一、什麼是「表格篩選框被遮住」?
想像你在 Excel 裡面按欄位篩選,會跳出一個可以勾選資料的清單。
在網頁中,我們也常常會做類似的功能,例如:
- 點「客戶」欄位的小按鈕
- 跳出所有客戶名稱
- 勾選你想保留的資料
- 表格只顯示符合條件的列
問題是,很多人把這個篩選框放在表格容器裡後,因為外層區塊設定了
overflow,所以超出邊界的部分就直接被裁掉了。
你看到的現象通常會像這樣:
- 篩選框明明有打開
- 但只露出一小部分
- 想看完整內容還要拖旁邊的捲軸
- 使用者會以為功能壞掉
這其實不是 Vue 壞掉,也不是資料沒出來,通常只是 CSS 顯示層級與容器裁切設定 的問題。
二、另一個常見問題:篩選後沒資料,提示列太矮
很多頁面在篩選之後,如果沒有符合條件的資料,會顯示一行字,例如:
符合篩選的資料為空
但是如果這一列只是普通
<td>,就會變成:
- 高度很小
- 只有一條細細的訊息
- 下方大片空白
- 看起來不像完整介面
對使用者來說,這種畫面很容易造成誤解,會以為:
- 是資料沒載入完成
- 是頁面壞掉
- 是自己操作錯誤
所以實務上,我們通常會把這一列做成比較高的提示區塊,讓使用者一眼就知道:
「不是壞掉,是目前篩選條件下沒有資料。」
三、先用白話文理解問題本質
這類問題,核心其實只有兩件事。
1. 下拉篩選框屬於「浮出來的元件」
它不是表格內正常排版的一部分,而是有點像浮在上面的視窗。
如果外層容器說:「超出我的範圍不准顯示」,那它就會被切掉。
2. 查無資料提示列,本質上只是普通表格儲存格
如果你沒有額外幫它設定高度、置中、背景或版面,它就只會是一個很普通的小格子。
所以要修正這兩個問題,方向也很簡單:
- 讓篩選框不要被容器裁切
- 讓空白提示列有足夠高度與視覺重心
四、範例情境:一個可以搜尋與篩選的資料表格
以下是一個重新改寫過的示意範例。
這不是原始對話裡的程式,而是全新整理過、適合教學用途的版本。
這個範例包含:
- 關鍵字搜尋
- 欄位篩選按鈕
- 無資料提示
- 表格區塊顯示修正
範例模板(Vue)
<template>
<section class="report-page">
<div class="toolbar">
<input
v-model="keyword"
class="keyword-input"
type="text"
placeholder="請輸入關鍵字"
/>
</div>
<div class="grid-wrapper">
<table class="data-grid">
<thead>
<tr>
<th>
編號
<button class="mini-filter" @click="togglePanel('code')">篩選</button>
<div v-if="openedPanel === 'code'" class="filter-panel">
<div class="filter-actions">
<button @click="pickAll('code')">全選</button>
<button @click="clearAll('code')">清空</button>
</div>
<label v-for="item in distinct.code" :key="item" class="option-item">
<input type="checkbox" v-model="selected.code" :value="item" />
{{ item }}
</label>
</div>
</th>
<th>品名</th>
<th>分類</th>
<th>數量</th>
</tr>
</thead>
<tbody>
<tr v-if="visibleRows.length === 0" class="no-data-row">
<td colspan="4">
<div class="no-data-box">
目前沒有符合條件的資料
</div>
</td>
</tr>
<tr v-for="row in visibleRows" :key="row.id">
<td>{{ row.code }}</td>
<td>{{ row.name }}</td>
<td>{{ row.group }}</td>
<td>{{ row.qty }}</td>
</tr>
</tbody>
</table>
</div>
</section>
</template>
範例邏輯(Vue script)
<script setup>
import { ref, computed } from 'vue'
const keyword = ref('')
const openedPanel = ref(null)
const rows = ref([
{ id: 1, code: 'A101', name: '螺絲', group: '五金', qty: 35 },
{ id: 2, code: 'A102', name: '螺帽', group: '五金', qty: 12 },
{ id: 3, code: 'B201', name: '電容', group: '電子', qty: 7 },
])
const distinct = {
code: [...new Set(rows.value.map(x => x.code))]
}
const selected = ref({
code: [...distinct.code]
})
function togglePanel(field) {
openedPanel.value = openedPanel.value === field ? null : field
}
function pickAll(field) {
selected.value[field] = [...distinct[field]]
}
function clearAll(field) {
selected.value[field] = []
}
const visibleRows = computed(() => {
const text = keyword.value.trim().toLowerCase()
return rows.value.filter(item => {
const matchKeyword =
!text ||
Object.values(item).join(' ').toLowerCase().includes(text)
const matchCode = selected.value.code.includes(item.code)
return matchKeyword && matchCode
})
})
</script>
範例樣式(CSS)
<style scoped>
.report-page {
background: #ffffff;
padding: 20px;
}
.toolbar {
margin-bottom: 12px;
}
.keyword-input {
width: 240px;
padding: 8px 10px;
border: 1px solid #cfcfcf;
border-radius: 6px;
}
.grid-wrapper {
position: relative;
overflow-x: auto;
overflow-y: visible;
border: 1px solid #d8d8d8;
}
.data-grid {
width: 100%;
min-width: 900px;
border-collapse: collapse;
}
.data-grid th,
.data-grid td {
border: 1px solid #e1e1e1;
padding: 10px;
text-align: center;
white-space: nowrap;
}
.data-grid th {
background: #f4d000;
position: relative;
}
.mini-filter {
margin-left: 8px;
padding: 2px 6px;
border: 1px solid #d1b400;
border-radius: 4px;
background: #ffef8a;
cursor: pointer;
}
.filter-panel {
position: absolute;
top: calc(100% + 6px);
left: 0;
width: 180px;
max-height: 260px;
overflow-y: auto;
background: #fff;
border: 1px solid #cccccc;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
border-radius: 8px;
padding: 10px;
z-index: 30;
}
.filter-actions {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.option-item {
display: flex;
align-items: center;
gap: 6px;
margin: 6px 0;
}
.no-data-row td {
height: 280px;
padding: 0;
vertical-align: middle;
background: #fafafa;
}
.no-data-box {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #1f5fbf;
font-size: 18px;
font-weight: 700;
}
</style>
五、這段修正到底改了什麼?
很多剛接觸前端的人會想:「不就是一行訊息而已,為什麼還要多包一層 div?」
這裡其實有兩個關鍵。
1. 讓空白列變高
這一段:
.no-data-row td {
height: 280px;
}
意思是:
只要表格出現「沒有資料」那一列,就把它撐高到 280px。
這樣畫面就不會只剩下短短一行字,而是會像一個完整的提示區塊。
2. 讓提示文字水平與垂直都置中
這一段:
.no-data-box {
display: flex;
align-items: center;
justify-content: center;
}
意思是:
-
align-items: center:上下置中 -
justify-content: center:左右置中
所以不管這個提示區塊有多高,文字都會穩穩地出現在正中間,視覺上比較專業。
六、為什麼篩選框會被裁掉?
這通常跟下面這種寫法有關:
overflow: hidden;
它的意思很像:
超出我邊界的東西都不准顯示
但篩選框通常是展開在表頭外面的,所以只要超過邊界,就會直接消失一部分。
因此像這種表格篩選元件,外層容器比較常見的做法會是:
overflow-x: auto;
overflow-y: visible;
這樣的好處是:
- 水平太寬時,仍然可以捲動
- 篩選下拉視窗在垂直方向可以正常展開
- 不會一打開就被切掉
七、為什麼商業系統很常遇到這種問題?
因為企業系統的表格通常都有這些特性:
- 欄位很多
- 表頭可能有兩層甚至三層
- 每欄都有篩選
- 還要固定表頭
- 還要支援匯出 Excel
- 還要記住使用者篩選條件
功能一多,畫面上的元素就會彼此影響。
例如:
-
固定表頭會用
position: sticky -
篩選框會用
position: absolute -
外層容器又會有
overflow - 再加上 z-index 沒設定好
最後就會出現:
- 篩選框被切掉
- 篩選框被表頭蓋住
- 篩選框顯示在奇怪的位置
- 查無資料訊息太扁太小
這些都不是少見問題,反而是很多工程師都遇過的典型 UI 細節。
八、如果想讓畫面更像正式系統,還能再優化什麼?
除了修正顯示問題,還可以順手加強幾個地方。
1. 空白提示加上背景色
讓使用者一看就知道這是狀態訊息區,而不是表格壞掉。
例如:
.no-data-row td {
background-color: #f8fbff;
}
2. 加上 icon 或提示說明
例如:
- 查無符合條件的資料
- 請調整篩選條件後重新查詢
這樣使用者會更知道下一步該怎麼做。
3. 篩選框加入最大高度與捲動
如果選項很多,不要讓下拉視窗一直變長。
例如:
.filter-panel {
max-height: 260px;
overflow-y: auto;
}
4. 按鈕文案更清楚
像「全選」「清空」「套用」這些文字,可以比只放圖示更容易理解。
九、給完全沒寫過前端的人:你可以怎麼理解這件事?
你可以把整個頁面想成一個辦公桌。
- 表格容器 就像桌子的範圍
- 篩選框 就像桌上臨時打開的資料夾
- 如果桌子規定「超出桌邊的東西都算不見」
- 那資料夾只要稍微超出去,就會被切掉
而「沒有資料」那一列,就像你在桌子中間貼一張便利貼。
如果便利貼很小,整個桌面看起來就會很空。
所以我們會故意把它放進一個比較大的提示板裡,讓整體看起來更清楚。
十、實務建議:這類頁面開發時要先注意什麼?
如果你未來也要做 Vue 表格頁面,建議一開始就先檢查這幾件事:
畫面層面
- 表格是否會超寬
- 篩選框是否需要浮出顯示
- 空資料狀態是否有良好提示
- 表頭是否固定
CSS 層面
-
外層容器有沒有
overflow: hidden -
Dropdown 有沒有
position: absolute - z-index 是否足夠
- 空白提示列是否有固定高度
使用者體驗層面
- 沒資料時是否能一眼看懂
- 篩選選項是否容易操作
- 是否支援全選與清空
- 畫面是否需要保留上次篩選結果
十一、簡單總結
這次的問題表面上看起來只是:
- 篩選框看不到
- 沒資料那列太矮
但背後其實是前端開發裡非常常見的兩種 UI 細節:
- 浮動元件被容器裁切
- 空狀態畫面沒有被好好設計
只要掌握這兩個原理,之後不管是 Vue、React,甚至純 HTML/CSS/JavaScript,其實都能用一樣的思路去處理。
如果你正在使用 Vue 3 製作查詢頁、報表頁或企業內部系統,遇到表格篩選框被遮住、查無資料畫面太難看、固定表頭與 dropdown 衝突等問題,這篇教學提供的思路會很實用。重點不是死背某一段程式碼,而是理解 overflow、position、table 高度與空狀態設計 之間的關係。只要搞懂這些觀念,之後在處理大型表格 UI 時就會輕鬆很多。
留言
張貼留言