在Vue3+ElementPlus前端中,使用watch監控對象變化,實現字典列表的級聯更新處理
在Vue3+ElementPlus前端中,有時候一些字典的關聯顯示,需要使用級聯,因此一般使用watch監控對象變化,實現字典列表的級聯更新。本篇隨筆介紹基于實際案例來實現多級關聯的處理操作,以供參考。
1、省市區的級聯案例
在很多實際業務項目中,往往都可能涉及到級聯顯示的場景。比如有 省份 -> 城市 -> 區縣 的字典數據,用戶在選擇“省份”時,自動更新“城市”選項;選擇“城市”時,自動更新“區縣”選項。基本的處理過程如下所示。
-
使用
ref/reactive保存選擇值和字典數據。 -
使用
watch監聽上級字段變化,動態更新下級字典數據。 -
下級值要 清空/重置,避免殘留無效值。
對于省市區簡單例子的Vue3模板界面,如下代碼所示。
<template> <div> <label>省份:</label> <select v-model="province"> <option :value="null">請選擇</option> <option v-for="p in provinces" :key="p.code" :value="p.code">{{ p.name }}</option> </select> <label>城市:</label> <select v-model="city"> <option :value="null">請選擇</option> <option v-for="c in cities" :key="c.code" :value="c.code">{{ c.name }}</option> </select> <label>區縣:</label> <select v-model="area"> <option :value="null">請選擇</option> <option v-for="a in areas" :key="a.code" :value="a.code">{{ a.name }}</option> </select> </div> </template>
在其script腳本代碼的操作中,使用watch來處理界面代碼邏輯如下所示。
<script setup lang="ts"> import { ref, watch } from 'vue' // 模擬字典數據 const provinces = ref([ { code: 'gd', name: '廣東' }, { code: 'bj', name: '北京' } ]) const citiesDict: Record<string, { code: string; name: string }[]> = { gd: [ { code: 'gz', name: '廣州' }, { code: 'sz', name: '深圳' } ], bj: [ { code: 'dc', name: '東城' }, { code: 'xc', name: '西城' } ] } const areasDict: Record<string, { code: string; name: string }[]> = { gz: [{ code: 'tianhe', name: '天河區' }, { code: 'yuexiu', name: '越秀區' }], sz: [{ code: 'nanshan', name: '南山區' }, { code: 'futian', name: '福田區' }], dc: [{ code: 'xx', name: '東城區示例' }], xc: [{ code: 'yy', name: '西城區示例' }] } // 當前選擇 const province = ref<string | null>(null) const city = ref<string | null>(null) const area = ref<string | null>(null) // 下級字典 const cities = ref<{ code: string; name: string }[]>([]) const areas = ref<{ code: string; name: string }[]>([]) // 監聽省份變化 → 更新城市 watch(province, (newVal) => { if (newVal) { cities.value = citiesDict[newVal] || [] } else { cities.value = [] } city.value = null // 清空下級選擇 area.value = null areas.value = [] }) // 監聽城市變化 → 更新區縣 watch(city, (newVal) => { if (newVal) { areas.value = areasDict[newVal] || [] } else { areas.value = [] } area.value = null // 清空下級選擇 }) </script>
有時候,對于字段的處理順序,我們可能需要引入nextick來處理。
nextTick 在 Vue3 里非常適合用來 等 DOM 和響應式更新完成再執行邏輯。
在「編輯場景級聯字典」這種情況里,nextTick 可以解決 字典更新和已有值賦值的時序問題。
// 監聽省份變化 → 更新城市字典 watch( () => form.province, async (newVal) => { if (!newVal) { cities.value = [] form.city = null form.area = null return } cities.value = await fetchCities(newVal) // ? 用 nextTick 等 cities 更新后再校驗 await nextTick() if (!cities.value.find(c => c.code === form.city)) { form.city = null form.area = null } }, { immediate: true } )
2、電力記錄業務的處理案例
在我們的一個項目案例中,對于電力的一些級聯處理,也有類似的參考價值,如對于電力記錄的處理中,我們需要根據地區進行一級、二級、三級能耗的下拉列表級聯更新,方便在錄入的時候進行關聯顯示。下面是數據列表的顯示部分界面截圖。

在數據編輯或者新增的情況下,我們需要根據這些內容進行級聯的顯示處理,那么界面如下所示。

我們看到,以上幾個了下拉列表的字典內容,都存在一定的級聯關系,如選擇區域后,需要更新一級列表、選擇一級列表后,需要更新二級列表、選擇二級列表后,需要更新三級列表等等。
我們使用watch來跟蹤對象的變化,并及時進行字典數據的更新,如下邏輯代碼所示。
const area = ref([]); // 能源區域 const level1 = ref([]); // 一級能耗計量 const level2 = ref([]); // 二級能耗計量 const level3 = ref([]); // 三級能耗計量 const initArea = () => { electrecord.GetFieldDict('area').then(data => { // console.log(data); area.value = data; }); }; // 判斷下拉框的值是否有改變 watch( () => editForm.area, (newValue) => { if (!newValue) { editForm.level1 = ''; editForm.level2 = ''; editForm.level3 = ''; } if (newValue) { const whereStr = `area='${newValue}'`; electmerter.GetFieldDict('level1', whereStr).then(data => { // console.log(data); level1.value = data; }); } }, { immediate: true } ); watch( () => editForm.level1, (newValue) => { if (!newValue) { editForm.level2 = ''; editForm.level3 = ''; editForm.devicename = ''; editForm.devicecode = ''; editForm.lastnumber = 0; } if (newValue) { const whereStr = `level1='${newValue}' and area='${editForm.area}'`; electmerter.GetFieldDict('level2', whereStr).then(data => { // console.log(data); level2.value = data; }); } }, { immediate: true } ); watch( () => editForm.level2, (newValue) => { if (!newValue) { editForm.level3 = ''; editForm.devicename = ''; editForm.devicecode = ''; editForm.lastnumber = 0; } if (newValue) { const whereStr = `level2='${newValue}' and area='${editForm.area}' and level1='${editForm.level1}'`; electmerter.GetFieldDict('level3', whereStr).then(data => { // console.log(data); level3.value = data; }); } }, { immediate: true } ); watch( () => editForm.level3, (newValue) => { if (!newValue) { editForm.devicename = ''; editForm.devicecode = ''; editForm.lastnumber = 0; } }, { immediate: true } );
其中 electmerter.GetFieldDict 是ES6類中的API調用函數,主要對標后端代碼里面,通用處理的獲取對應表的關聯字段列表。
后端通用的處理代碼如下C#代碼所示。
/// <summary> /// 根據字段名稱,獲取對應的字典列表 /// </summary> /// <param name="fieldName">字段名稱</param> /// <param name="whereStr">條件字符串,如Age > 20 AND IsActive = true</param> /// <returns></returns> public virtual async Task<List<CListItem>> GetFieldDict(string fieldName, string whereStr) { var list = new List<CListItem>(); if (!fieldName.IsNullOrEmpty()) { //var sql = $"Select distinct {fieldName} from Table"; var query = this.EntityDb.AsQueryable(); if (!string.IsNullOrWhiteSpace(whereStr)) { query = query.Where(whereStr); } var fieldList = await query.Distinct().Select<string>(fieldName).ToListAsync(); if(fieldList != null && fieldList.Count >0) { var sortedList = fieldList .OrderBy(name => GetSortIndex(name)) // 主排序:數字前綴 .ThenBy(name => name) // 次排序:中文拼音順序 .ToList(); list = sortedList.Select(s => new CListItem(s)).ToList(); } } return list; }
以上就是一些簡單案例上對于watch的使用,用于處理多級關聯更新的情況下的功能實現。
專注于代碼生成工具、.Net/Python 框架架構及軟件開發,以及各種Vue.js的前端技術應用。著有Winform開發框架/混合式開發框架、微信開發框架、Bootstrap開發框架、ABP開發框架、SqlSugar開發框架、Python開發框架等框架產品。
??轉載請注明出處:撰寫人:伍華聰??http://www.iqidi.com?
????
浙公網安備 33010602011771號