前言
嗯,偶爾看看學習Vue 3技能啦,此前用過Vue 2做過一點東西,Vue 3已面世一段時間,於是乎,我來看看所遇到的問題是否在Vue 3中得到解決,首先,我們來講講一個例子在Vue 2中的實現,舉個例子吧,開發過程中我們只會用到省、市、區,這裡的區也可以看做是三、四線城市中的縣,若我們想要基於縣動態建立鎮、村,更有甚者,在全國各地在鎮下還劃分不同的區域,我們通過Vue結合ElementUI來實現此例子
Vue 2 + ElementUI
由於示例程式碼比較多,這裡我們首先直接看效果,如下:
具體程式碼如下所示,太多?忽略不看,我們只講解核心問題
<el-dialog :modal="dialogModal" :title="townTitle" @close="closeDialog" :visible.sync="dialogVisible" :close-on-click-modal="false" width="800px" top="10vh" center> <el-row> <el-form label-width="40px" ref="form" size="mini"> <el-form-item> <el-button size="small" @click="createMultipleTown" icon="el-icon-plus">新增鎮</el-button> </el-form-item> <el-form-item v-for="(town, tindex) in form.towns" :key="tindex" style="border: 1px dashed #AAAAAA;margin:10px 0 20px 0;"> <el-row style="margin:20px 0 20px 0;"> <el-col :span="19"> <el-button type="danger" size="small" icon="el-icon-delete" @click="removeTown(tindex)">移除鎮</el-button> </el-col> </el-row> <el-row style="margin:20px 0 20px 0;"> <el-col :span="4"> 鎮名稱 </el-col> <el-col :span="19"> <el-input maxlength="30" v-model="town.townName" placeholder="請輸入鎮名稱"></el-input> </el-col> </el-row> <el-row style="margin-bottom:20px;"> <el-col :span="4"> 區域、村 </el-col> <el-col :span="20"> <el-radio-group v-model="town.option"> <el-radio @change="dynamicAddRegion(tindex)" label="新增區域"></el-radio> <el-radio label="新增村" @change="dynamicAddVillage(tindex)"></el-radio> </el-radio-group> </el-col> </el-row> <el-row v-for="(region, rindex) in town.regions" :key="rindex" style="margin-bottom:20px;"> <el-row> <el-col :span="4"> {{region.regionTitle}} </el-col> <el-col :span="5" style="margin-right:20px;" v-show="town.townRegionVisible"> <el-input size="small" maxlength="30" v-model="region.regionName" placeholder="請輸入區域名稱"></el-input> </el-col> <el-col :span="5" style="margin-right:20px;"> <el-tooltip class="item" effect="dark" content="輸入村名稱並回車,即可連續新增" placement="top"> <el-input size="small" maxlength="30" v-model="region.villageName" @keyup.enter.native="getVillage(tindex, rindex)" placeholder="請輸入村名稱"></el-input> </el-tooltip> </el-col> <el-col :span="5" v-show="!town.townRegionVillageVisible"> <el-button size="small" icon="el-icon-plus" @click="continueAddRegion(tindex)">追加區域</el-button> </el-col> <el-col :span="3" v-show="!town.townRegionVillageVisible" style="width:100px;"> <el-button size="small" type="danger" icon="el-icon-delete" @click="removeRegion(tindex, rindex)">移除區域</el-button> </el-col> </el-row> <el-row> <el-col :span="4"> <span> </span> </el-col> <el-col :span="20"> <el-tag :key="tagindex" v-for="(tag, tagindex) in region.tags" closable :disable-transitions="false" style="margin:10px 10px 0 0;" @close="handleClose(tindex, rindex, tagindex)"> {{tag}} </el-tag> </el-col> </el-row> </el-row> </el-form-item> </el-form> </el-row> <el-row v-show="saveButtonVisible"> <el-col :span="20"> <span> </span> </el-col> <el-col :span="2"> <el-button @click="save" type="primary">確定</el-button> </el-col> <el-col :span="1"> <el-button @click="cancel">取消</el-button> </el-col> </el-row> </el-dialog>
直接看如下定義資料結構可得知,存在三層遍歷,第一層遍歷從鎮開始,第二層遍歷從鎮下區域開始,最後一層遍歷則是區域下的村(即上述標籤)
form: { areaId: 0, towns: [ { townName: '', regions: [{ regionTitle: '', regionName: '', villageName: '', tags: [] }] } ]}
在Vue 2中一直存在的問題則是無法監聽陣列,若我沒記錯的話,Vue 2是通過Object.defineProperty()來監聽物件,也就是後臺語言中對應的屬性get和set方法。結合上述示例圖和程式碼,當我們輸入村名稱時,然後回車,則將村名稱新增到村陣列中去,然後通過el-tag標籤進行遍歷渲染
接下來問題來了,此時我們想要刪除村,所以點選村標籤的刪除圖示,毫無疑問直接將區域下的村陣列通過索引將其移除即可,但是,但是,根本無法移除,因為此時區域下的村是一個陣列,Vue 2無法監聽得到,也就是我們在陣列中給對應村移除時,但頁面上無法同步刪除,移除方法如下:
handleClose (tindex, rindex, tagindex) { let self = this let region = self.form.towns[tindex].regions[rindex] region.tags.splice(tagindex, 1) }
那麼在Vue 2中如何解決這個問題呢?根據我們的示例來看,我們將輸入的村名稱即文字框繫結回車事件,然後將文字框繫結的模型資料新增到村陣列中去,所以此時我們假裝先再次在文字框上繫結一個“佔位符”,然後緊接著將其置空,給Vue 2一種“錯覺”剛才的資料沒繫結上,所以上述刪除標籤方法,變成如下即可解決:
handleClose (tindex, rindex, tagindex) { let self = this let region = self.form.towns[tindex].regions[rindex] region.tags.splice(tagindex, 1) // 新增文字準備新增“一個佔位符”,以便於頁面上能刪除標籤 region.villageName = '佔位符' region.villageName = '' }
Vue 3 + ElementPlus
空閒之餘,試了試Vue 3結合ElementPlus,這個問題得到了解決,在Vue 3中通過proxy(代理)方式監聽所有屬性,當然也就包括陣列,然後在Vue 3中相關鍵盤事件等,比如回車,都已通過v-on:key.enter來繫結事件實現
總結
本文也是做做小demo遇到的問題,特此記錄下,其他倒沒什麼可以說的了,再會~~~~