Vue 2升級 Vue 3初探小細節

Jeffcky發表於2021-07-30

前言

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

相關文章