Vue3中無法為el-tree-select設定反選問題分析

默卿發表於2023-04-10

  好久沒有寫部落格了,剛好上週遇到一個難纏問題,這裡記錄一下。

  環境:Vue3.2、Element Plus

  問題:子元件 setting.vue => 彈窗元件 Dialog => 樹選擇元件el-tree-select ,無法設定預設選中項 default-checked-keys

  場景:在一個後臺系統的列表頁,選中一行資料,點選設定按鈕,分配一些功能。這裡的做法是把設定頁封裝在一個子元件裡了,並且子元件裡使用了Element Plus的Dialog元件

               然後Dialog裡有個el-tree-select需要初始化賦值,因為在分配之前,可能之前分配過,需要設定反選

  最開始是直接寫死,如下:

<template>
  <el-tree-select 
    :data="store().UserMenus"
    :default-expanded-keys="['xxxxxxxx']" 
  />
</template>

  然後發現不生效,週五的時候也能猜到原因,data繫結的pinia全域性狀態裡的值,元件被例項化時這個值可能還未被載入,所以設定default-expanded-keys時它就找不到節點資料,等元件被建立後,data有值了,但是default-expanded-keys又不會再重新設定了,就造成元件有下拉資料,但是沒有反選效果。

  起初以為是個簡單問題,於是動了動腦子,既然和順序有關,那自然考慮到生命週期了,於是在setting.vue里加上onMounted,並在這裡重新賦值:

// script ts
const list = ref()
const selectArr = ref<string[]>([])
onMounted(() => {
  list.value = store().UserMenus
  selectArr.value = ['xxxxxxxx']
})
 
// setting.vue
<template>
  <el-tree-select 
    :data="list"
    :default-expanded-keys="selectArr" 
  />
</template>

  data繫結list這個變數,default-expanded-keys繫結selectArr。嗯,以為可以了,結果還是沒有反選成功。就.....離譜~

  正常來講onMounted函式已經是元件建立完畢並建立Dom了,這個時候我應該可以設定list的值,再設定selectArr。但實際依然沒有反選成功。

  這說明載入依然存在問題,抱著研究的心態,於是我又想起一種方法,我可以透過呼叫el-tree-select的API來透過方法設定它的預設值,也就是setCheckedKeys方法!

  透過模板引用,獲取到el-tree-select,命名為tree,然後回到onMounted裡列印:console.log(tree.value),好傢伙,居然是個undefined,這說明在settting.vue的onMounted根本就無法設定選中的keys。然後詭異的是,在我反覆修改程式碼的時候,由於熱過載,Vue頁面會隨之更新,居然能反選上了!但是我一重新整理,反選立刻失效。enmmmm ..... 基本能定位到問題的所在了,onMounted是無法獲取到元件的,後面試了一下onUnmounted,這個可以,但是我這是初始化邏輯,不可能寫在onUnmounted裡。

  這裡面還存在一個因素導致該問題的產生,就是Dialog預設是不顯示的,透過v-model="dialogVisible"繫結的變數控制顯示隱藏,初始化值為false也是導致失效的一個原因,如我初始時設定dialogVisible.value = true ,那麼反選是OK的,只不過我依然不可能設定為true,哪有彈窗一開始就顯示的。

  週五下午基本卡在這個地方了,經過週末的放空自我(峽谷Timi),週一早上上班的路上覆盤了一下,考慮從Dialog本身尋找答案,嘿,果不其然,它的API裡有個opened方法,Dialog 開啟動畫結束時的回撥,我在這裡做初始化,問題就解決了:

// Dialog
@opened="opened"

// script ts 
const opened = () => {
     selectArr.value = ['xxxxxxxx']
}

  之所以能找到這個思路,還有一個原因是也試了一下表單,之前表單的提交事件裡一直可以獲取到表單物件,然後試了一下onMounted裡能不能獲取到,結果也是類似的情況。放個按鈕,在按鈕的點選事件裡是可以獲取到元件的,因為等你可以點選按鈕時,頁面什麼東西都載入完畢了,同樣的,Dialog 開啟動畫結束時的回撥裡,頁面肯定早載入完畢了,該有的值都有了,那麼這個時候做初始化就不會存在找不到key的問題了。

 

  這個問題看似簡單,最後opened方法搞定了,但實際很考驗Vue的功底,什麼時候元件被建立,什麼時候資料被載入,每個屬性之間資料的聯動以及先後順序,如果你寫個固定值放在data和keys那裡,肯定沒這個問題,Element Plus官方檔案大把的案例拿過來直接就有效果,但是呢,實際的專案開發中,經常是多個技術點綜合在一起,你基本不可能把一個下拉框的值寫死了,也許你和我一樣從pinia裡取的值,也許你透過axios讀的資料,也許是別的路子,但是多少會遇到一些和預期不符的時候,因此這裡以這個案例分享一下,自己也做個記錄,如果有人遇到了類似的問題可以參考一二,有更好的方案也可以提出來一起交流交流。

  以上。

相關文章