實戰技巧,Vue原來還可以這樣寫

逐夢song 發表於 2020-06-29
Vue

hookEvent,原來可以這樣監聽元件生命週期

1. 內部監聽生命週期函式

<template>
  <div class="echarts"></div>
</template>
<script>
export default {
  mounted() {
    this.chart = echarts.init(this.$el)
    // 請求資料,賦值資料 等等一系列操作...
    // 監聽視窗發生變化,resize元件
    window.addEventListener('resize', this.$_handleResizeChart)
  },
  updated() {
    // 幹了一堆活
  },
  created() {
    // 幹了一堆活
  },
  beforeDestroy() {
    // 元件銷燬時,銷燬監聽事件
    window.removeEventListener('resize', this.$_handleResizeChart)
  },
  methods: {
    $_handleResizeChart() {
      this.chart.resize()
    },
    // 其他一堆方法
  }
}
</script>

這樣寫不是很好,應該將監聽resize事件與銷燬resize事件放到一起,現在兩段程式碼分開而且相隔幾百行程式碼,可讀性比較差

export default {
  mounted() {
    this.chart = echarts.init(this.$el)
    // 請求資料,賦值資料 等等一系列操作...
    
    // 監聽視窗發生變化,resize元件
    window.addEventListener('resize', this.$_handleResizeChart)
    // 通過hook監聽元件銷燬鉤子函式,並取消監聽事件
    this.$once('hook:beforeDestroy', () => {
      window.removeEventListener('resize', this.$_handleResizeChart)
    })
  },
  updated() {},
  created() {},
  methods: {
    $_handleResizeChart() {
      // this.chart.resize()
    }
  }
}

Vue元件中,可以用過$on,$once去監聽所有的生命週期鉤子函式,如監聽元件的updated鉤子函式可以寫成 this.$on('hook:updated', () => {})

2. 外部監聽生命週期函式

<template>
  <!--通過@hook:updated監聽元件的updated生命鉤子函式-->
  <!--元件的所有生命週期鉤子都可以通過@hook:鉤子函式名 來監聽觸發-->
  <custom-select @hook:updated="$_handleSelectUpdated" />
</template>
<script>
import CustomSelect from '../components/custom-select'
export default {
  components: {
    CustomSelect
  },
  methods: {
    $_handleSelectUpdated() {
      console.log('custom-select元件的updated鉤子函式被觸發')
    }
  }
}
</script>

小專案還用Vuex?用Vue.observable手寫一個狀態管理吧

在前端專案中,有許多資料需要在各個元件之間進行傳遞共享,這時候就需要有一個狀態管理工具,一般情況下,我們都會使用Vuex,但對於小型專案來說,就像Vuex官網所說:“如果您不打算開發大型單頁應用,使用 Vuex 可能是繁瑣冗餘的。確實是如此——如果您的應用夠簡單,您最好不要使用 Vuex”。這時候我們就可以使用Vue2.6提供的新API Vue.observable手動打造一個Vuex

建立 store

import Vue from 'vue'

// 通過Vue.observable建立一個可響應的物件
export const store = Vue.observable({
  userInfo: {},
  roleIds: []
})

// 定義 mutations, 修改屬性
export const mutations = {
  setUserInfo(userInfo) {
    store.userInfo = userInfo
  },
  setRoleIds(roleIds) {
    store.roleIds = roleIds
  }
}


在元件中引用

<template>
  <div>
    {{ userInfo.name }}
  </div>
</template>
<script>
import { store, mutations } from '../store'
export default {
  computed: {
    userInfo() {
      return store.userInfo
    }
  },
  created() {
    mutations.setUserInfo({
      name: '逐夢'
    })
  }
}
</script>

深度watchwatch立即觸發回撥,我可以監聽到你的一舉一動

Vue.extend是一個全域性Api,平時我們在開發業務的時候很少會用到它,但有時候我們希望可以開發一些全域性元件比如Loading,Notify,Message等元件時,這時候就可以使用Vue.extend

基礎用法

比如一個列表頁,我們希望使用者在搜尋框輸入搜尋關鍵字的時候,可以自動觸發搜尋,此時除了監聽搜尋框的change事件之外,我們也可以通過watch監聽搜尋關鍵字的變化

<template>
  <!--此處示例使用了element-ui-->
  <div>
    <div>
      <span>搜尋</span>
      <input v-model="searchValue" />
    </div>
    <!--列表,程式碼省略-->
  </div>
</template>
<script>
export default {
  data() {
    return {
      searchValue: ''
    }
  },
  watch: {
    // 在值發生變化之後,重新載入資料
    searchValue(newValue, oldValue) {
      // 判斷搜尋
      if (newValue !== oldValue) {
        this.$_loadData()
      }
    }
  },
  methods: {
    $_loadData() {
      // 重新載入資料,此處需要通過函式防抖
    }
  }
}
</script>

立即觸發

通過上面的程式碼,現在已經可以在值發生變化的時候觸發載入資料了,但是如果要在頁面初始化時候載入資料,我們還需要在created或者mounted生命週期鉤子裡面再次呼叫$_loadData方法。不過,現在可以不用這樣寫了,通過配置watch的立即觸發屬性,就可以滿足需求了

// 改造watch
export default {
  watch: {
    // 在值發生變化之後,重新載入資料
    searchValue: {
    // 通過handler來監聽屬性變化, 初次呼叫 newValue為""空字串, oldValue為 undefined
      handler(newValue, oldValue) {
        if (newValue !== oldValue) {
          this.$_loadData()
        }
      },
      // 配置立即執行屬性
      immediate: true
    }
  }
}

深度監聽(我可以看到你內心的一舉一動)

一個表單頁面,需求希望使用者在修改表單的任意一項之後,表單頁面就需要變更為被修改狀態。如果按照上例中watch的寫法,那麼我們就需要去監聽表單每一個屬性,太麻煩了,這時候就需要用到watch的深度監聽deep

export default {
  data() {
    return {
      formData: {
        name: '',
        sex: '',
        age: 0,
        deptId: ''
      }
    }
  },
  watch: {
    // 在值發生變化之後,重新載入資料
    formData: {
      // 需要注意,因為物件引用的原因, newValue和oldValue的值一直相等
      handler(newValue, oldValue) {
        // 在這裡標記頁面編輯狀態
      },
      // 通過指定deep屬性為true, watch會監聽物件裡面每一個值的變化
      deep: true
    }
  }
}

隨時監聽,隨時取消,瞭解一下$watch

有這樣一個需求,有一個表單,在編輯的時候需要監聽表單的變化,如果發生變化則儲存按鈕啟用,否則儲存按鈕禁用。這時候對於新增表單來說,可以直接通過watch去監聽表單資料(假設是formData),如上例所述,但對於編輯表單來說,表單需要回填資料,這時候會修改formData的值,會觸發watch,無法準確的判斷是否啟用儲存按鈕。現在你就需要了解一下$watch

export default {
  data() {
    return {
      formData: {
        name: '',
        age: 0
      }
    }
  },
  created() {
    this.$_loadData()
  },
  methods: {
    // 模擬非同步請求資料
    $_loadData() {
      setTimeout(() => {
        // 先賦值
        this.formData = {
          name: '子君',
          age: 18
        }
        // 等表單資料回填之後,監聽資料是否發生變化
        const unwatch = this.$watch(
          'formData',
          () => {
            console.log('資料發生了變化')
          },
          {
            deep: true
          }
        )
        // 模擬資料發生了變化
        setTimeout(() => {
          this.formData.name = '張三'
        }, 1000)
      }, 1000)
    }
  }
}

根據上例可以看到,我們可以在需要的時候通過this.$watch來監聽資料變化。那麼如何取消監聽呢,上例中this.$watch返回了一個值unwatch,是一個函式,在需要取消的時候,執行 unwatch()即可取消