前言

嗯,偶爾看看學習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>&nbsp;&nbsp;</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>&nbsp;&nbsp;&nbsp;&nbsp;</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遇到的問題,特此記錄下,其他倒沒什麼可以說的了,再會~~~~