如何优雅的绘制一棵省市区三级可选择的树?
開始
總結一下 開發過程中的思路想法 各位大佬們看看就好
首先你擁有的數據結構 所有省市區的信息列表 以及已經選中的信息 用的是element-ui的 el-tree
const cityStorage = {provinceList:[{id: 1, provinceId: "110000", name: "北京市"}],//所有省cityList:[{id: 1, cityId: "110100", name: "北京市", provinceId: "110000", zipCode: "102600"}],//所有市districtList:[{id: 1, districtId: "110101", name: "東城區", cityId: "110100"}],//所有區} const selectList = [{ provinceId: "110000",cityId: "110100",districtId: "110101"} ] // 所有選中的省市區 ID 保存的時候也是這個格式按需渲染
首先 作為有相對要求的開發人員 不會考慮說 直接的去渲染出整個樹 那整個省市區加載的速度絕對會是感人的
那么 可行的解決方法是 一開始 只展示 所有省的信息 點擊展開 時再去渲染下一層 數據
這個對應關系 相對還容易找 每次點擊展開能獲得當前的層級和id 根據層級和id去對應的city和district中過濾就行
這里分享一個小技巧 不通過判斷的方式去對應 而是通過數據的方式
//level , id const levelConfig = {1: {idLabel: 'cityId',fetchLabel: 'cityList',perIdLabel: 'provinceId'},2: {idLabel: 'districtId',fetchLabel: 'districtList',perIdLabel: 'cityId'} }// 那么過濾就可以這么寫 cityStorage[levelConfig[level].fetchLabel].filter(item => item[levelConfig[level].perIdLabel] == id)獲取數據 然后加載對應下一層 一切到現在為止 都還可以
賦值渲染
再往下 如果我有初始數據呢?
在只展示省信息的情況下 結合前面給的數據格式 怎么展示 這個省是 全選 半選(表示省中有選擇的市或者區但沒選全) 和 不選 ?
第一 你需要設法知道省份滿足全選的條件
第二 你需要設法知道已經選擇的情況
所以這個時候 需要做的 是計數 也就
遍歷一遍 cityStorage.provinceList 和 cityStorage.cityList
往Map中初始化 provinceId cityId 對應的計數
在遍歷 cityStorage.districtList 過程中往Map 對應provinceId cityId 增加計數
那么 有沒有什么別的基礎數據 是要在這個時候初始化的呢?
例如 只給你一個 districtId 你怎么才能最快的 找到他對應的 cityId 和 provinceId
或者 只給你一個 id 怎么最快找到他 對應的 name 呢
我們可以構建一個Map來記錄我們需要的信息
districtId:cityId
cityId:provinceId
那么 我可以通過 Map[districtId] 找到cityId Map[Map[districtId]] 找到 provinceId
id 和 name 的對應關系 也是如此
而這些 可以在 計數的 過程進行
接著 通過已經選擇地區 的 列表 獲取provinceId cityId的數據 的計數
兩份數據都有了
在渲染 省的時候 判斷 兩份Map中對應的計數 是否相同來渲染勾選
那半選的狀態怎么表示呢?el-tree并不支持設置半選的狀態,必須是通過數據的形式呢?
通過模擬子節點的方法 當滿足不全選的情況 模擬兩個子節點
var children = [{id:provinceId '111',label:name,type:'none'},{id:provinceId '222',label:name,type:'none'} ]然后選中 其中一個 父元素自然就是半選狀態
保存提交
最后是保存提交時候的數據處理
由于模擬了半選狀態 所以最后獲取到的選中的數據 會有兩種
一種常規的6位 還是一種是模擬的d{6}xxx
而且如果 是出現這種d{6}xxx的數據 代表的是它所在的一級有些被選中了 而這些數據還沒有出現在 渲染樹中
這是就 需要有一個數據結構記錄 這種情況
在已選擇的數據 初始化計數的時候 新構建一個Map 存儲 provinceId cityId出現的數據的下標(我這邊保存的是districtId)
provinceId:[districtId,districtId,districtId]
cityId:[districtId,districtId,districtId]
至此 我們最后能拿到的 選中的 id 有 [310000,410000111,510100,610101]
此時這份數據中 有provinceId cityId districtId 以及 模擬的半選數據 怎么盡可能的優雅的生成我們需要的格式呢?
首先是分類 可以發現 xx0000表示的是省 xxx000 xxxx00 表示的是市
let _zeo = item.match(/(0 )$/g),ype = _zeo ? _zeo[0] : '0' switch (type) {case '0':districtList.push(item)break;case '00':case '000':cityList.push(item)break;case '0000':provinceList.push(item)break;}而這種410000111 數據 可以通過 先前的 Map 將數據并入 districtList 中
接著就是凈化數據
省選擇了 不需要市的所有id 市選擇了 不需要區的所有id
總結 判斷條件
var sub = item.substr(0,2) var re =new RegExp('\^' sub '\\d{4}'); // 省 // var sub = item.substr(0,4) // var re =new RegExp('\^' sub '\\d{2}'); // 市 cityList.filter(code=>!code.match(re))最后 provinceList cityList districtList 都是有效的選中值
遍歷一遍 cityStorage.districtList 將其中在provinceList cityList中存在id的數據并入 districtList中
此時 districtList 是最終有效的所有選中的 districtId值
此時 cityId = Map[districtId] province=Map[cityId]
寫這個需求的時候 頭真的很大 考慮的再清楚 寫著寫著 還是會有讓人抓狂的問題
展示合并
等等 你以為就這么完了 還有一個展示需求 數據結構還是 保存的那份數據結構
希望展示成
當選擇了一個省份全部地區的時候展示省份名稱
當選擇了一個省份下的部分市時展示市的名稱
當選擇了一個市下的所有地區時,只展示市的名稱
當選擇了一個市下的部分地區時,括號內展示地區名稱
首先還是通過計數 獲取 已經選中的有效的 provinceList cityList districtList
數據格式{provinceId: "110000",cityId: "110100",districtId: "110101"}
構建一個存 selectNameList 用于存放已經選中的 name name可以通過前面的Map[id]獲取
provinceList 選擇的省沒問題 直接推入
cityList 遍歷 構建新的數據 格式 {provinceId: "110000",cityId: "110100",districtId: "1"}
并入 districtList 中
對districtList 根據 cityId 排序
最后 遍歷 districtList 通過標記判斷每次是否是重復的cityId 設置數組 indeterminateNameList 記錄不是全選的市的name
不重復 將標記記為當前cityId 如果上一個元素的 districtCode 是 1 將 indeterminateNameList 存入 selectNameList 中
selectNameList.push('(' indeterminateNameList.join(',') ')')
districtId == 1 全選 存入 selectNameList
districtId != 1 不是全選 存入 indeterminateNameList = [cityId]
在這個過程中 有需要 還可以記錄 cityId 和 indeterminateNameList的管理關系
最終 selectNameList.join(',')
結語
程序猿真的不容易啊 遇到開發時間緊 雜七雜八事情多 還毫無頭緒的時候 壓力真的是大啊
更多專業前端知識,請上 【猿2048】www.mk2048.com
總結
以上是生活随笔為你收集整理的如何优雅的绘制一棵省市区三级可选择的树?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用JavaScript控制台改进工
- 下一篇: 不一样的ZTree,权限树.js插件