Vue一個案例引起的動態組件與全局事件綁定總結

技術這東西真的不能光靠看,看是沒有的,你必需要動手實踐,只有在實戰項目中才能發現問題,才能發現咱們沒有掌握的知識點,而後發現問題解決問題,咱們的能力才能得以提高,要否則就有點眼高手低了。緩存

基於這個想法因而就開始本身去擼了一個旅遊網站,旅遊網站嘛避免不了城市的選擇,因此在實現城市選擇列表的時候碰到的一些問題,以及解決辦法今天就記錄下來作一個總結。函數

城市列表選擇組件

首先說說咱們要實現一個什麼樣的城市選擇組件:性能

  1. 輸入框獲取焦點時,顯示組件
  2. 點擊城市列表更新輸入框的城市顯示
  3. 點擊其餘空白處組件隱藏
  4. 在切換到其餘組件時,選擇的城市保留而不是被重置

下面咱們就一步一步的來拆解優化

第一步

輸入框獲取焦點後顯示組件很簡單,咱們給輸入框綁定焦點事件而後給組件傳入一個顯示的狀態便可,咱們把 isShowCityList 傳遞給城市選擇組件控制行爲。網站

<el-input 
    @focus="isShowCityList=true"
    placeholder="請輸入目的地">
</el-input>

第二步

咱們也不作過多的表述本文想更多的是介紹動態組件與全局事件的綁定,利用的是子組件給父組件利用自定義事件 $emit 傳給父組件。this

第三步

須要咱們去點擊其餘地方城市組件被隱藏,有些同窗的第一印象多是利用 input 的 blur 事件(就是失去焦點事件),只要咱們的 input 失去焦點時,咱們就隱藏。spa

其實個人第一印象也是如此,可是咱們綁定的是 input 的失去焦點事件之後,當咱們選擇城市列表的時候也是 input 失去焦點的時候,因此咱們就沒法選取城市。顯然這種思路是不行的。code

因此這裏咱們只能去用到 Vue 的全局事件的綁定,而後去進行一個判斷咱們點擊的節點是哪裏,若是是城市組件之外咱們就進行隱藏操做。component

咱們在 mounted 鉤子函數中,進行以下操做。blog

mounted() {
    document.addEventListener("click", e => {
        console.log('全局事件被觸發');
        if (!this.$refs.searchCity.contains(e.target)) {
            this.isLoadCityList = false;
        }
    });
}

OK,進行這一步以後,咱們的問題獲得瞭解決,只要咱們點擊這個容器之外的地方就會隱藏城市列表組件,我覺得算是結束了,不過那是不可能的,仍是我太年輕了,這樣作的後果就是無論咱們點擊任何一個地方它都會觸發這個事件,即便是咱們切換到其餘組件時,事件照樣會被觸發,顯然這個不是咱們想要的,由於當前事件會被無限觸發,無疑會給咱們帶來不可預見的問題。

咱們須要的最好效果確定是當前的全局事件就在當前的組件下產生做用,當咱們切換到其餘組件時,事件自動刪除,因而我可能想到的就是利用 beforeDestroy 鉤子函數去刪除這個全局事件。也就是當咱們切換到其餘組件時,去刪除這個全局事件。

beforeDestroy() {
    document.removeEventListener("click", () => {
      //...
    });
}

你覺得這樣我還就能解決問題了嗎?顯然仍是不能,仍是太年輕,只是這樣咱們是解除不了綁定的事件,那咱們該怎麼辦呢?其實這裏面有一個坑,大坑,由於這個大坑本身不知道,差了許多資料也沒查出來,由於差的思路錯了,最後在一個羣裏問了一個大佬,才得出答案,不得不說與前輩交流很重要啊,能幫你少踩不少坑。

這裏若是想要解除綁定,解除和綁定的兩個回調函數必須一致,什麼意思呢?看代碼你就明白。若是不這麼操做,你是解除不掉事件的,至於更深的緣由我也不怎麼明白了,之後再去查閱一些資料。

methods: {
  isSearchCityNode(e) {
    if (!this.$refs.searchCity.contains(e.target)) {
      console.log("全局事件被觸發");
      this.isLoadCityList = false;
    }
  }  
},
mounted() {
    document.addEventListener("click", this.isSearchCityNode);
},
beforeDestroy() {
    document.removeEventListener("click", this.isSearchCityNode);
}

第四步

須要咱們在切換組件的時候保留咱們選擇的城市,若是不保留咱們每次切換到其餘組件時,咱們選擇的城市都會被重置爲默認值,這個體驗確定是肯差的,也不是咱們想要的。

被重置的緣由則是咱們在每次在不一樣的組件進行切換的時候,組件都會進行新建與銷燬,這也會致使重複渲染問題對性能也是不友好的。

那麼咱們該如何去處理這個問題呢? 我這裏使用了 keep-alive 去解決這個問題,那麼 keep-alive 該如何使用以及做用是什麼呢?

<keep-alive>
  <component v-bind:is="currentTabComponent"></component>
</keep-alive>

包裹動態組件時,會緩存不活動的組件實例,而不是銷燬它們,它自身不會渲染一個 DOM 元素,也不會出如今父組件鏈中。

可是當咱們使用 的時候,咱們的 beforeDestroy 鉤子函數就會失效,致使咱們第三步的全局事件的解綁就不能執行了,緣由是咱們的組件是被緩存起來,並無被銷燬。天然會失效,可是咱們並不慌,當咱們使用 時,activated 和 deactivated 兩個鉤子函數被觸發。

activated:keep-alive 組件激活時調用。

deactivated:keep-alive 組件停用時調用。

因此咱們不難發現,咱們徹底可使用這兩個鉤子去實現咱們全局事件的綁定與解綁,簡直完美。

activated() {
    document.addEventListener("click", this.isSearchCityNode);
},
deactivated() {
    document.removeEventListener("click", this.isSearchCityNode);
}

總結

經過一個城市列表組件的案例,介紹了咱們在 Vue 中如何綁定全局事件以及進行優化,必定要記住事件的綁定與解除哪裏有一個大坑。

咱們經過 能夠建立一個能夠緩存的組件,並且會新增兩個鉤子函數提供咱們使用

文中若有不足之處,歡迎大神拍磚!

原文連接:https://www.jianshu.com/p/e7c...

相關文章
相關標籤/搜索