Vue3.0來襲,你想學的都在這裏(二)

日日加班日日忙,需求襲來如虎狼。 測試問題堆如山,萬念俱灰歸故鄉。javascript

最近在工做之餘一直學習Vue3.0相關知識,雖然Vue3.0至今仍是rc版,但這並不影響咱們去學習。今天這篇文章是我關於Vue3.0的第四篇文章。在前文中咱們講解了如何經過vitevuecli搭建Vue3.0開發環境,而後介紹了Vue3.0中的setup,reactive,ref等,今天這篇文章主要講解了如下內容:前端

  1. Vue3.0中使用watch
  2. Vue3.0中使用計算屬性
  3. Vue3.0中使用vue-router
  4. Vue3.0中使用vuex

開始本文前,小編提供了一個Vue3.0開發環境,倉庫地址爲 gitee.com/f_zijun/vue…,歡迎使用。本文首發於公衆號【前端有的玩】,這是一個專一於Vue面試相關的公衆號,提高本身的市場競爭力,就在【前端有的玩】。同時點擊如下連接便可訪問小編關於Vue3.0的其餘相關文章vue

學習Vue3.0,先來了解一下Proxyjava

使用vite搭建一個Vue3.0學習環境react

使用Vue3.0,我收穫了哪些知識點(一)ios

Vue3.0中使用watch

watchVue3.0中並非一個新的概念,在使用Vue2.x的時候,咱們常常會使用watch來監聽Vue實例上面的一個表達式或者一個函數計算結果的變化。git

回顧Vue2.0中的watch

Vue2.0中,咱們使用watch能夠經過下面多種方式去監聽Vue實例上面的表達式或者函數計算結果的變化,以下羅列了其中的幾種面試

  1. 最常規使用方式vue-router

    export default {
      data() {
        return {
          name: '子君',
          info: {
            gzh: '前端有的玩'
          }
        }
      },
      watch: {
        name(newValue, oldValue) {
          console.log(newValue, oldValue)
        },
        'info.gzh': {
          handler(newValue, oldValue) {
            console.log(newValue, oldValue)
          },
          // 配置immediate會在watch以後當即執行
          immediate: true
        }
      }
    }
    複製代碼

    咱們能夠在watch屬性裏面配置要監聽的Vue實例上面的屬性,也能夠經過.鍵路徑去監聽對象中的某一個屬性的變化,也能夠經過配置immediate在監聽後當即觸發,配置deep去深度監聽對象裏面的屬性,不論嵌套層級有多深。vuex

  2. 使用$watch監聽

    除了常規的watch對象寫法以外,Vue實例上面提供了$watch方法,能夠經過$watch更靈活的去監聽某一個屬性的變化。好比這樣一個場景,咱們有一個表單,而後但願在用戶修改表單以後能夠監聽到表單的數據變化。可是有一個特殊的場景,就是表單的回填數據是異步請求過來的,這時候咱們但願在後臺請求完數據以後再去監聽變化,這時候就可使用$watch。以下代碼所示:

    export default {
      methods: {
        loadData() {
          fetch().then(data => {
            this.formData = data
            this.$watch(
              'formData',
              () => {
                // formData數據發生變化後會進入此回調函數
              },
              {
                deep: true
              }
            )
          })
        }
      }
    }
    複製代碼
  3. 監聽函數表達式

    除了監聽字符串以外,$watch的第一個參數也能夠是一個函數,當函數的返回值發生變化以後,觸發回調函數

    this.$watch(() => this.name, () => {
      // 函數的返回值發生變化,進入此回調函數
    })
    複製代碼

上文中就是Vue2.0中咱們使用watch的一些經常使用寫法,對於Vue3.0,由於其對Vue2.0作了部分的向下兼容,因此上面的用法在Vue3.0中基本均可以使用,可是Vue3.0一個很大的亮點就是composition API,因此除了Vue2.0中的寫法以外,也可使用componsition api中提供的watch

Vue3.0中使用watch

Vue3.0中,除了Vue2.0的寫法以外,有兩個api能夠對數據變化進行監聽,第一種是watch,第二種是watchEffect。對於watch,其與Vue2.0中的$watch用法基本是如出一轍的,而watchEffectVue3.0新提供的api

watch的用法

下面的示例演示瞭如何使用watch

import { watch, ref, reactive } from 'vue'
export default {
  setup() {
    const name = ref('子君')
    const otherName = reactive({
      firstName: '王',
      lastName: '二狗'
    })
    watch(name, (newValue, oldValue) => {
      // 輸出 前端有的玩 子君
      console.log(newValue, oldValue)
    })
    // watch 能夠監聽一個函數的返回值
    watch(
      () => {
        return otherName.firstName + otherName.lastName
      },
      value => {
        // 當otherName中的 firstName或者lastName發生變化時,都會進入這個函數
        console.log(`我叫${value}`)
      }
    )

    setTimeout(() => {
      name.value = '前端有的玩'
      otherName.firstName = '李'
    }, 3000)
  }
}
複製代碼

watch除了能夠監聽單個值或者函數返回值以外,也能夠同時監聽多個數據源,好比下面代碼所示:

export default {
  setup() {
    const name = ref('子君')
    const gzh = ref('前端有的玩')
    watch([name, gzh], ([name, gzh], [prevName, prevGzh]) => {
      console.log(prevName, name)
      console.log(prevGzh, gzh)
    })

    setTimeout(() => {
      name.value = '前端有的玩'
      gzh.value = '關注我,一塊兒玩前端'
    }, 3000)
  }
}
複製代碼
watchEffect的用法

watchEffect的用法與watch有所不一樣,watchEffect會傳入一個函數,而後當即執行這個函數,對於函數裏面的響應式依賴會進行監聽,而後當依賴發生變化時,會從新調用傳入的函數,以下代碼所示:

import { ref, watchEffect } from 'vue'
export default {
  setup() {
    const id = ref('0')
    watchEffect(() => {
      // 先輸出 0 而後兩秒後輸出 1
      console.log(id.value)
    })

    setTimeout(() => {
      id.value = '1'
    }, 2000)
  }
}
複製代碼
  1. 中止執行

    Vue2.0中的$watch會在調用的時候返回一個函數,執行這個函數能夠中止watch,以下代碼所示

    const unwatch = this.$watch('name',() => {})
    // 兩秒後中止監聽
    setTimeout(()=> {
      unwatch()
    }, 2000)
    複製代碼

    Vue3.0中,watchwatchEffect一樣也會返回一個unwatch函數,用於取消執行,好比下面代碼所示

    export default {
      setup() {
        const id = ref('0')
        const unwatch = watchEffect(() => {
          // 僅僅輸出0
          console.log(id.value)
        })
    
        setTimeout(() => {
          id.value = '1'
        }, 2000)
        // 1秒後取消watch,因此上面的代碼只會輸出0
        setTimeout(() => {
          unwatch()
        }, 1000)
      }
    }
    複製代碼
    1. 清除反作用

      想象一下這樣的一個場景,界面上面有兩個下拉框,第二個下拉框的數據是根據第一個下拉框的數據聯動的,當第一個下拉框數據發生變化後,第二個下拉框的數據會經過發送一個網絡請求進行獲取。這時候咱們能夠經過watchEffect來實現這個功能,好比像下面代碼這樣

      import { ref, watchEffect } from 'vue'
      
      function loadData(id) {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve(
              new Array(10).fill(0).map(() => {
                return id.value + Math.random()
              })
            )
          }, 2000)
        })
      }
      
      export default {
        setup() {
          // 下拉框1 選中的數據
          const select1Id = ref(0)
          // 下拉框2的數據
          const select2List = ref([])
          watchEffect(() => {
            // 模擬請求
            loadData(select1Id).then(data => {
              select2List.value = data
              console.log(data)
            })
          })
          
          // 模擬數據發生變化
          setInterval(() => {
            select1Id.value = 1
          }, 3000)
        }
      }
      複製代碼

      如今假如我切換了一下第一個下拉框的數據以後,這時候數據請求已經發出,而後我將這個頁面切換到另外一個頁面,由於請求已經發出,因此我但願在頁面離開的時候,能夠結束這個請求,防止數據返回後出現異常,這時候就可使用watchEffect爲第一個回調函數傳入的入參來處理這個狀況,以下代碼所示

      function loadData(id, cb) {
        return new Promise(resolve => {
          const timer = setTimeout(() => {
            resolve(
              new Array(10).fill(0).map(() => {
                return id.value + Math.random()
              })
            )
          }, 2000)
          cb(() => {
            clearTimeout(timer)
          })
        })
      }
      
      export default {
        setup() {
          // 下拉框1 選中的數據
          const select1Id = ref(0)
          // 下拉框2的數據
          const select2List = ref([])
          watchEffect(onInvalidate => {
            // 模擬請求
            let cancel = undefined
            // 第一個參數是一個回調函數,用於模擬取消請求,關於取消請求,能夠了解axios的CancelToken
            loadData(select1Id, cb => {
              cancel = cb
            }).then(data => {
              select2List.value = data
              console.log(data)
            })
            onInvalidate(() => {
              cancel && cancel()
            })
          })
        }
      }
      複製代碼

Vue3.0中使用計算屬性

想想在Vue2.0中咱們通常會用計算屬性作什麼操做呢?我想最多見的就是當模板中有一個複雜計算的時候,能夠先使用計算屬性進行計算,而後再在模板中使用,實際上,Vue3.0中的計算屬性的做用和Vue2.0的做用基本是同樣的。

  1. Vue2.0中使用計算屬性

    computed: {
        getName() {
          const { firstName, lastName } = this.info
          return firstName + lastName
        }
      },
    複製代碼
  2. Vue3.0中使用計算屬性

    <template>
      <div class="about"> <h1>{{ name }}</h1> </div>
    </template>
    <script> import { computed, reactive } from 'vue' export default { setup() { const info = reactive({ firstName: '王', lastName: '二狗' }) const name = computed(() => info.firstName + info.lastName) return { name } } } </script>
    
    複製代碼

    Vue2.0同樣,Vue3.0的計算屬性也能夠設置gettersetter,好比上面代碼中的計算屬性,只設置了getter,即加入cumputed傳入的參數是一個函數,那麼這個就是getter,假如要設置setter,須要像下面這樣去寫

    export default {
      setup() {
        const info = reactive({
          firstName: '王',
          lastName: '二狗'
        })
    
        const name = computed({
          get: () => info.firstName + '-' + info.lastName,
          set(val) {
            const names = val.split('-')
            info.firstName = names[0]
            info.lastName = names[1]
          }
        })
    
        return {
          name
        }
      }
    }
    複製代碼

Vue3.0中使用vue-router

初始化vue-router

Vue2.0中咱們使用vue-router的時候,會經過new VueRouter的方式去實現一個VueRouter實例,就像下面代碼這樣

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)
const router = new VueRouter({
  mode: 'history',
  routes: []
})
export default router
複製代碼

但到了Vue3.0,咱們建立VueRouter的實例發生了一點點變化,就像Vue3.0main.js中初始化Vue實例須要像下面寫法同樣

import { createApp } from 'vue'
createApp(App).$mount('#app')
複製代碼

vue-router也修改成了這種函數的聲明方式

import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
  // vue-router有hash和history兩種路由模式,能夠經過createWebHashHistory和createWebHistory來指定
  history: createWebHashHistory(),
  routes
})

router.beforeEach(() => {
  
})

router.afterEach(() => {
  
})
export default router

複製代碼

而後在main.js中,經過

createApp(App).use(router)
複製代碼

來引用到Vue

setup中使用vue-router

Vue2.0中,咱們經過this.$route能夠獲取到當前的路由,而後經過this.$router來獲取到路由實例來進行路由跳轉,可是在setup中,咱們是沒法拿到this的,這也意味着咱們不能像Vue2.0那樣去使用vue-router, 此時就須要像下面這樣去使用

import { useRoute, useRouter } from 'vue-router'

export default {
  setup() {
    // 獲取當前路由
    const route = useRoute()
    // 獲取路由實例
    const router = useRouter()
    // 噹噹前路由發生變化時,調用回調函數
    watch(() => route, () => {
      // 回調函數
    }, {
      immediate: true,
      deep: true
    })
    
    // 路由跳轉
    function getHome() {
      router.push({
        path: '/home'
      })
    }
    
    return {
      getHome()
    }
  }
}
複製代碼

上面代碼咱們使用watch來監聽路由是否發生變化,除了watch以外,咱們也可使用vue-router提供的生命週期函數

import { onBeforeRouteUpdate, useRoute } from 'vue-router'
export default {
  setup() {
    onBeforeRouteUpdate(() => {
      // 噹噹前路由發生變化時,調用回調函數
    })
  }
}
複製代碼

除了onBeforeRouteUpdate以外,vue-router在路由離開的時候也提供了一個生命週期鉤子函數

onBeforeRouteLeave(() => {
   console.log('噹噹前頁面路由離開的時候調用')
})
複製代碼

Vue3.0中使用vuex

其實vuexVue3.0中的使用方式和vue-router基本是一致的

初始化vuex

首先新建store/index.js,而後添加以下代碼

import { createStore } from 'vuex'

export default createStore({
  state: {},
  mutations: {},
  actions: {}
})
複製代碼

而後在main.js中,經過如下方式使用

createApp(App).use(store)
複製代碼

setup中使用vuex

useRouter同樣,vuex也提供了useStore供調用時使用,好比下面這段代碼

import { useStore } from 'vuex'
export default {
  setup() {
    const store = useStore()
    const roleMenus = store.getters['roleMenus']
    return {
      roleMenus
    }
  }
}
複製代碼

其他的使用方式基本和Vue2.0中的用法是一致的,你們具體能夠參考vuex官方文檔

Vue3.0中的生命週期鉤子函數

在前文中,咱們說到Vue3.0是兼容一部分Vue2.0的,因此對於Vue2.0的組件寫法,生命週期鉤子函數並未發生變化,可是假如你使用的是componsition api,那麼就須要作一部分調整

  1. 取消beforeCreatecreated

    在使用componsition api的時候,其實setup就代替了beforeCreatecreated,由於setup就是組件的實際入口函數。

  2. beforeDestroydestroyed 更名了

    setup中,beforeDestroy改名爲onBeforeUnmount,destroyed改名爲onUnmounted

  3. 將生命週期函數名稱變爲on+XXX,好比mounted變成了onMounted,updated變成了onUpdated

setup中使用生命週期函數的方式

setup() {
    onMounted(() => {
      console.log('mounted!')
    })
    onUpdated(() => {
      console.log('updated!')
    })
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }
複製代碼

實際用法與Vue2.0基本是一致的,只是寫法發生了變化,因此學習成本是很低的。

總結

這是小編關於Vue3.0的第四篇文章,每一篇文章都是本身在學習中作的一些總結。小編整理了一個vue3.0的開發環境,倉庫地址爲 gitee.com/f_zijun/vue…,內部集成了typescript,eslint,vue-router,vuex,ant desigin vue等,但願能夠幫到正在學習Vue3.0的你,同時關注公衆號【前端有的玩】,帶給你不同的驚喜。喜歡本文,能夠給小編一個贊哦。

結語

不要吹滅你的靈感和你的想象力; 不要成爲你的模型的奴隸。 ——文森特・梵高

相關文章
相關標籤/搜索