Element?UI長(zhǎng)表單校驗(yàn)失敗后自動(dòng)展開(kāi)折疊面板并滾動(dòng)定位代碼實(shí)現(xiàn)
前言
在復(fù)雜的后臺(tái)管理系統(tǒng)中,長(zhǎng)表單常被拆分到多個(gè) el-collapse 折疊面板中以提升可讀性。但當(dāng)用戶提交后出現(xiàn)校驗(yàn)錯(cuò)誤,如果錯(cuò)誤字段藏在收起的面板里,僅靠 Element UI 默認(rèn)的高亮提示遠(yuǎn)遠(yuǎn)不夠——用戶根本看不到錯(cuò)誤在哪!
本文將介紹一種 無(wú)需額外維護(hù)字段-面板映射關(guān)系 的自動(dòng)化方案,實(shí)現(xiàn):自動(dòng)展開(kāi)包含錯(cuò)誤字段的折疊面板 + 平滑滾動(dòng)定位 + 自動(dòng)聚焦,大幅提升用戶體驗(yàn)。
問(wèn)題場(chǎng)景
你是否遇到過(guò)這樣的情況?
- 表單字段多達(dá) 200+,為了界面整潔,用
el-collapse或者其他技術(shù)分成「基本信息」「聯(lián)系方式」「權(quán)限配置」等幾個(gè)面板; - 用戶填寫(xiě)完前幾個(gè)字段,直接點(diǎn)「提交」;
- 后面面板中的必填項(xiàng)(如郵箱)校驗(yàn)失敗,Element UI 給對(duì)應(yīng)
el-form-item加了紅色邊框; - 但該面板處于收起狀態(tài),用戶完全看不到錯(cuò)誤提示,一臉懵……
此時(shí),理想的行為應(yīng)該是:
- 自動(dòng)展開(kāi)包含第一個(gè)校驗(yàn)錯(cuò)誤字段的折疊面板;
- 頁(yè)面平滑滾動(dòng)到該字段位置;
- (可選)讓輸入框獲得焦點(diǎn),方便用戶立即修正。
而很多開(kāi)發(fā)者會(huì)想到:我可以建一個(gè) field → panelName 的映射表?。?br />但現(xiàn)實(shí)是:字段一多、結(jié)構(gòu)一變、動(dòng)態(tài)表單一上,維護(hù)成本劇增,極易出錯(cuò)。
有沒(méi)有更聰明的辦法?
核心思路:利用 DOM 結(jié)構(gòu)自動(dòng)“溯源”
Element UI 的 el-collapse-item 渲染后是一個(gè)標(biāo)準(zhǔn)的 DOM 節(jié)點(diǎn)。如果我們能從 出錯(cuò)的表單項(xiàng) 向上遍歷父節(jié)點(diǎn),找到它所屬的折疊面板,就能知道該展開(kāi)哪個(gè)面板。
但有個(gè)小坑:el-collapse-item 的 name 屬性不會(huì)直接出現(xiàn)在 DOM 中,所以我們需要手動(dòng)加一個(gè)標(biāo)識(shí)。
解決方案三步走:
- 給每個(gè)
el-collapse-item添加data-panel-name屬性(值等于其name); - 校驗(yàn)失敗時(shí),找到第一個(gè)
.el-form-item.is-error元素; - 向上查找最近的
[data-panel-name]父元素,獲取面板名并展開(kāi); - 等待 DOM 更新后,滾動(dòng)并聚焦。
全程 無(wú)需任何字段映射表,完全基于 DOM 結(jié)構(gòu)自動(dòng)推斷!
代碼實(shí)現(xiàn)
1. 模板部分:添加data-panel-name
<template>
<el-form ref="formRef" :model="form" :rules="rules">
<el-collapse v-model="activePanels">
<!-- 注意:data-panel-name 的值必須和 name 一致 -->
<el-collapse-item
title="基本信息"
name="basic"
data-panel-name="basic"
>
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-collapse-item>
<el-collapse-item
title="聯(lián)系方式"
name="contact"
data-panel-name="contact"
>
<el-form-item label="郵箱" prop="email">
<el-input v-model="form.email" />
</el-form-item>
</el-collapse-item>
</el-collapse>
<el-button type="primary" @click="handleSubmit">提交</el-button>
</el-form>
</template>?? 關(guān)鍵點(diǎn):
data-panel-name是我們自定義的 DOM 標(biāo)識(shí),用于后續(xù)查找。
2. 邏輯部分:自動(dòng)展開(kāi) + 定位
export default {
data() {
return {
activePanels: ['basic'], // 初始展開(kāi)的面板
form: { name: '', email: '' },
rules: {
name: [{ required: true, message: '請(qǐng)輸入姓名' }],
email: [{ required: true, message: '請(qǐng)輸入郵箱', type: 'email' }]
}
};
},
methods: {
handleSubmit() {
this.$refs.formRef.validate((valid, invalidFields) => {
if (!valid) {
this.$nextTick(() => {
const firstErrorItem = this.$el.querySelector('.el-form-item.is-error');
if (!firstErrorItem) return;
// 向上查找所屬面板
let panelName = null;
let parent = firstErrorItem.parentElement;
while (parent && parent !== document.body) {
const nameAttr = parent.getAttribute?.('data-panel-name');
if (nameAttr) {
panelName = nameAttr;
break;
}
parent = parent.parentElement;
}
// 如果面板未展開(kāi),則展開(kāi)它
if (panelName && !this.activePanels.includes(panelName)) {
this.activePanels = [...this.activePanels, panelName];
// 等待面板展開(kāi)完成后再滾動(dòng)
this.$nextTick(() => {
this.scrollToErrorField(firstErrorItem);
});
} else {
// 面板已展開(kāi),直接滾動(dòng)
this.scrollToErrorField(firstErrorItem);
}
});
} else {
console.log('? 提交成功');
}
});
},
scrollToErrorField(el) {
if (!el) return;
// 平滑滾動(dòng)到視圖中央
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
// 自動(dòng)聚焦到輸入框(兼容 el-select 等組件)
const input = el.querySelector(
'input:not([type="hidden"]), textarea, .el-select__input'
);
input?.focus();
}
}
};方案優(yōu)勢(shì)
| 傳統(tǒng)方案 | 本文方案 |
|---|---|
| 需手動(dòng)維護(hù) 字段 → 面板 映射表 | ? 無(wú)需任何映射,全自動(dòng)推斷 |
| 動(dòng)態(tài)表單難以適配 | ? 支持 v-for、異步加載等場(chǎng)景 |
| 易出錯(cuò)、難維護(hù) | ? 基于 DOM 結(jié)構(gòu),穩(wěn)定可靠 |
| 僅支持單層折疊 | ? 可擴(kuò)展支持嵌套 Collapse |
擴(kuò)展建議
- 展開(kāi)所有出錯(cuò)面板:遍歷
invalidFields,收集所有錯(cuò)誤字段對(duì)應(yīng)的面板名,批量展開(kāi); - 支持自定義滾動(dòng)容器:若表單在
overflow: auto的 div 內(nèi),改用container.scrollTop = ...; - Vue 3 + Element Plus:邏輯完全一致,只需注意
ref和響應(yīng)式語(yǔ)法差異; - 封裝為通用方法:可抽離
autoScrollToError函數(shù),在多個(gè)表單中復(fù)用。
總結(jié)
長(zhǎng)表單 + 折疊面板是后臺(tái)系統(tǒng)的常見(jiàn)組合,但校驗(yàn)體驗(yàn)不能因此打折。通過(guò) 利用 DOM 結(jié)構(gòu)向上溯源 + 自定義 data 屬性,我們實(shí)現(xiàn)了 零配置、全自動(dòng)的錯(cuò)誤定位與面板展開(kāi),既優(yōu)雅又實(shí)用。
好的交互細(xì)節(jié),往往就藏在這些“用戶看不見(jiàn)但能感受到”的地方。
到此這篇關(guān)于Element UI長(zhǎng)表單校驗(yàn)失敗后自動(dòng)展開(kāi)折疊面板并滾動(dòng)定位的文章就介紹到這了,更多相關(guān)Element UI自動(dòng)展開(kāi)折疊面板滾動(dòng)定位內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript的設(shè)計(jì)模式經(jīng)典之建造者模式
建造者模式是設(shè)計(jì)模式的一種,將一個(gè)復(fù)雜對(duì)象的構(gòu)建與它的表示分離,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示。接下來(lái)通過(guò)本文給大家介紹JavaScript的設(shè)計(jì)模式經(jīng)典之建造者模式,感興趣的朋友一起學(xué)習(xí)吧2016-02-02
不使用JavaScript實(shí)現(xiàn)菜單的打開(kāi)和關(guān)閉效果demo
本文通過(guò)實(shí)例代碼給大家分享在不使用JavaScript實(shí)現(xiàn)菜單的打開(kāi)和關(guān)閉效果,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2018-05-05
javascript 計(jì)算兩個(gè)整數(shù)的百分比值
用來(lái)計(jì)算兩個(gè)整數(shù)的百分比值的代碼,需要的可以看看。2009-12-12
微信小程序?qū)崿F(xiàn)購(gòu)物頁(yè)面左右聯(lián)動(dòng)
這篇文章主要為大家詳細(xì)介紹了微信小程序?qū)崿F(xiàn)購(gòu)物頁(yè)面左右聯(lián)動(dòng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02
JS apply用法總結(jié)和使用場(chǎng)景實(shí)例分析
這篇文章主要介紹了JS apply用法總結(jié)和使用場(chǎng)景,結(jié)合實(shí)例形式分析了JS apply的基本功能、原理、使用方法及操作注意事項(xiàng),需要的朋友可以參考下2020-03-03
JScript中的"this"關(guān)鍵字使用方式補(bǔ)充材料
JScript中的"this"關(guān)鍵字使用方式補(bǔ)充材料...2007-03-03
基于Fixed定位的框選功能的實(shí)現(xiàn)代碼
這篇文章主要介紹了基于Fixed定位的框選功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

