vue3.0 Composition API上手初體驗

vue3.0 對比 vue2.0 優點

  • vue3.0 相比 vue2.0 性能提高了近 50%,框架內部作了大量性能優化,包括:虛擬dom,編譯模板,Proxy 的新數據監聽,更小的打包文件等
  • vue3.0 新的組合式 API(即 Composition API)根據邏輯相關性組織代碼,相比於 vue2.0 的 Options API,提升了代碼的可讀性和可維護性,更適合大型項目的編寫方式
  • vue3.0 對 Typescript 支持更好,去除了繁瑣的 this 操做,更強大的類型推導

vue3.0 對比 vue2.0 語法區別

  • vue3.0 支持組件中使用多個根節點,能夠減小節點層級深度,也但願開發者可以明確語義javascript

  • vue3.0 刪除了過濾器(filters),將不在支持,官方建議使用計算屬性(computed)替換過濾器html

  • vue3.0 暴露出不少 API 供開發者使用,能夠根據需求,將所須要的 API 從 Vue 中導入。考慮到 tree-shaking,利用了 import 和 export 的語法,實現了按需打包模塊的功能vue

  • vue3.0 中新增了一個新的全局 API createApp,調用 createApp 返回一個應用實例,該應用實例暴露出來全局 API(vue3.0 將能夠全局改變 Vue 行爲的 API 從原來的 Vue 構造函數上轉移到了實例上了)java

    //vue2.0建立import Vue from 'vue'import App from './App.vue'
      Vue.config.productionTip = false
      new Vue({  render: h => h(App),
    }).$mount('#app')  
      
    //vue3.0建立import { createApp } from 'vue'import App from './App.vue'
      createApp(App).mount('#app');複製代碼

vue3.0 對比 vue2.0 響應式

Object.defineProperty 只能監聽到屬性的讀寫,而 Proxy 除讀寫外還能夠監聽屬性的刪除,方法的調用等react

  • vue2.0 數據響應式的原理是經過遍歷 data 屬性,利用 Object.definePrototype 將其轉化成 setter/getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調,因爲 js 的限制,vue 不能檢測數組和對象屬性的添加和刪除
  • vue3.0 基於 Proxy 來作數據的劫持代理,能夠原生支持到數組的響應式,不須要重寫數組的原型,還能夠直接檢測數組和對象屬性的新增和刪除(解決了 vue2.0 不能檢測數組和對象屬性的添加和刪除的問題)

vue3.0 對 Typescript 支持更好

  • Typescript 是 javascript 類型的超集,它能夠編譯成純的 javascript
  • Typescript 能夠在任何瀏覽器、任何計算機和任何操做系統上運行,而且是開源的
  • Typescript 能夠提供靜態類型檢查,規範團隊的編碼及使用方式,適合大型項目的開發
  • IDE 的友好提示,也是適合大型項目的開發

vue3.0 經常使用 API

Vue 組合式 API:composition-api.vuejs.org/zh/api.html…git

setup

setup 函數是一個新的組件選項,做爲在組件內使用 Composition API 的入口函數,變量、方法都定義在該函數中github

  • setup 函數代替了 beforeCreate 和 created 兩個生命週期函數,在生命週期 beforeCreate 以前被調用
  • this 在 setup() 中不可用,直接使用聲明的變量名來訪問數據(因爲 setup() 在解析 2.x 選項前被調用,setup() 中的 this 將與 2.x 選項中的 this 徹底不一樣。同時在 setup() 和 2.x 選項中使用 this 時將形成混亂)
  • setup 函數有兩個參數:props 和 context:
    • props 對象爲當前組件容許外界傳遞過來的參數名稱以及對應的響應式的值
    • context 是一個上下文對象,暴露出三個屬性:attrs 、slots、emit
  • setup 函數內定義的變量使用 return 暴露出去,供 template 中使用
<template>   <div>  {{ count }}
      {{ obj.count }}   </div></template><script>//引入須要的APIimport { ref, reactive } from 'vue'export default {   name: 'home',   setup() {      const count = ref(0)      export let obj = reactive({ count: 0 })      
      //經過return暴露出去,供template中使用  return {
         count,
         obj
      }
   }
}</script><style scoped>
  </style>複製代碼

使用 <script setup>vue-router

  • < script> 標籤具備 setup 屬性時,組件在編譯的過程當中代碼運行的上下文是 setup() 函數中
  • 定義的變量使用 export 暴露出去,供 template 中使用
<template>   <div>  {{ count }}
      {{ obj.count }}   </div></template><script setup>//引入須要的APIimport { ref, reactive } from 'vue'//經過export暴露出去,供template中使用export let num = ref(0)export let obj = reactive({ count: 0 })</script><style scoped>
  </style>複製代碼

reactive

reactive 接收一個普通對象而後返回該普通對象的響應式代理,建立一個響應式的數據對象vue-cli

<template>   <div>  {{ obj.count }}   </div></template><script>//引入須要的APIimport { reactive } from 'vue'export default {   name: 'home',   setup() {      //經過reactive定義響應式對象  const obj = reactive({ count: 0 }) 

      //經過return暴露出去,供template中使用  return {
         obj
      }
   }
}</script>複製代碼

ref

ref 接受一個參數值並返回一個響應式且可改變的 ref 對象。ref 對象擁有一個指向內部值的單一屬性 .valuenpm

  • 能夠簡單地把 ref(obj) 理解爲 reactive({ value: obj })
  • 在 setup 函數中訪問 ref 包裝後的對象時才須要使用 .value,在 template 模板中訪問會自動識別其是否爲 ref 包裝過,無需在模板內額外書寫 .value
<template>   <div>  {{ count }}   </div></template><script>//引入須要的APIimport { ref } from 'vue'export default {   name: 'home',   setup() {      //經過ref定義響應式對象  const count = ref(0) 

      //經過value屬性訪問值  console.log(count.value)   //0  //經過return暴露出去,供template中使用  return {
         count
      }
   }
}</script>複製代碼

toRef

toRef 能夠用來爲一個 reactive 對象的屬性建立一個 ref,這個 ref 能夠被傳遞而且可以保持響應性(將 reactive 對象中的某個值轉化爲響應式數據)

與 ref 的區別:

  • ref 是對傳入數據的拷貝,toRef 是對傳入數據的引用
  • ref 的值改變會更新視圖,toRef 的值改變不會更新視圖
<script>//引入須要的APIimport { reactive, toRef  } from 'vue'export default {   name: 'home',   setup() {      //經過reactive定義響應式對象  const obj = reactive({ count: 0, name: '廊坊吳彥祖' }) 

      //經過toRef將obj中的count屬性建立爲ref  const count = toRef(obj, 'count')      //經過return暴露出去,供template中使用  return {
         obj,
         count
      }
   }
}
</script>複製代碼

toRefs

toRefs 把一個響應式對象轉換成普通對象,該普通對象的每一個屬性都是一個 ref ,和響應式對象屬性一一對應(將 reactive 對象中的全部值轉化爲響應式數據)

<script>//引入須要的APIimport { reactive, toRefs  } from 'vue'export default {   name: 'home',   setup() {      //經過reactive定義響應式對象  const obj = reactive({ count: 0, name: '廊坊吳彥祖' }) 

      //經過toRefs將obj中的全部屬性建立爲ref  const refObj = toRefs(obj)      console.log(refObj)      //經過return暴露出去,供template中使用  return {
         obj,
         refObj
      }
   }
}
</script>複製代碼

console.log(refObj):在這裏插入圖片描述

readonly

readonly 傳入一個對象(響應式或普通)或 ref,返回一個原始對象的只讀代理(沒法修改)

  • 只讀的代理是「深層的」,對象內部任何嵌套的屬性也都是隻讀的
<template>   <div>  {{ count }}   </div></template><script>//引入須要的APIimport { readonly } from 'vue'export default {   name: 'home',   setup() {      //經過readonly定義只讀對象  const count = readonly(0) 

      count.value++   //修改報錯!Cannot create property 'value' on number '0'  
      //經過return暴露出去,供template中使用  return {
         count
      }
   }
}</script>複製代碼

computed

computed(計算屬性)傳入一個 getter 函數,返回一個默認不可手動修改的 ref 對象,使用和 vue 2.0 區別不大

<template>   <div>  {{ count }}
      {{ addCount }}   </div></template><script>//引入須要的APIimport { ref, computed } from 'vue'export default {   name: 'home',   setup() {      //經過ref定義響應式對象  const count = ref(0) 

      //經過computed方法實現計算屬性  const addCount = computed(() => count.value + 1)      console.log(addCount.value)   //1          //經過return暴露出去,供template中使用  return {
         count,
         addCount
      }
   }
}</script>複製代碼

watch

watch(偵聽器)須要偵聽特定的數據源,並在回調函數中執行反作用,使用和 vue 2.0 區別不大

  • 默認狀況是懶執行的,僅在偵聽的源變動時才執行回調
<script>//引入須要的APIimport { ref, reactive, watch } from 'vue'export default {   name: 'home',   setup() {      //經過ref定義響應式對象  const count = ref(0) 

      //經過watch方法實現對count的數據偵聽  watch(count, (newVal, oldVal) => {         console.log('newVal:' + newVal)         console.log('oldVal:' + oldVal)
      })      //經過reactive定義響應式對象  const obj = reactive({ count: 0 }) 
      
      //經過watch方法實現對obj.count的數據偵聽  watch(() => obj.count, (newVal, oldVal) => {         console.log('newVal:' + newVal)         console.log('oldVal:' + oldVal)
      })	  //經過watch方法實現同時對count和obj.count的數據偵聽  watch([count, () => obj.count], ([newVal1, oldVal1], [newVal2, oldVal2]) => {         console.log('newVal1:' + newVal1)         console.log('oldVal1:' + oldVal1)         console.log('newVal2:' + newVal2)         console.log('oldVal3:' + oldVal2)
      })      
      //經過return暴露出去,供template中使用  return {
         count,
         obj
      }
   }
}
</script>複製代碼

watchEffect

watchEffect 當即執行傳入的一個函數,並響應式追蹤其依賴,並在其依賴變動時從新運行該函數

  • 當 watchEffect 在組件的 setup() 函數或生命週期鉤子被調用時, 偵聽器會被連接到該組件的生命週期,並在組件卸載時自動中止(也能夠顯式調用返回值以中止偵聽)
    //watchEffect方法返回stop方法,執行該方法中止偵聽const stop = watchEffect(() => {
      ......
    })  
    //中止偵聽stop()複製代碼

與 watch 的區別:

  • 不須要手動傳入依賴(不須要手動指定偵聽對象)
  • 每次初始化時會執行一次回調函數來自動獲取依賴
  • 只能獲得變化後的值,沒法獲得原值(變化前的值)
<script>//引入須要的APIimport { ref, reactive, watchEffect } from 'vue'export default {   name: 'home',   setup() {      //經過ref定義響應式對象  const count = ref(0) 

      //經過reactive定義響應式對象  const obj = reactive({ count: 0 }) 
      
      //經過watchEffect方法實現數據偵聽(只能獲得變化後的值)  watchEffect(() => {         console.log(count.value)         console.log(obj.name)
      })      
      //經過return暴露出去,供template中使用  return {
         count,
         obj
      }
   }
}
</script>複製代碼

模板 Refs

使用組合式 API 時,reactive refs 和 template refs 的概念已是統一的。爲了得到對模板內元素或組件實例的引用,須要在 setup() 中聲明一個值爲 null 的 ref 並返回它

  • 變量名必須和元素 ref 屬性設置的名相同(獲取 ref = box 的元素:const box = ref(null) )
<template>   <div ref="box"></div></template><script>//引入須要的APIimport { ref, onMounted } from 'vue'export default {   name: 'home',   setup() {      //經過ref(null)獲取指定元素  const box = ref(null) 

      onMounted(() => {         console.log(box.value)   //<div></div>  })      
      //經過return暴露出去,供template中使用  return {
         box
      }
   }
}</script>複製代碼

vue3.0 生命週期

  • vue3.0 生命週期部分有所變化(setup 函數代替了 beforeCreate 和 created 兩個生命週期函數,在生命週期 beforeCreate 以前被調用)

    vue 2.0 vue3.0
    beforeCreate setup
    created setup
    beforeMount onBeforeMount
    mounted onMounted
    beforeUpdate onBeforeUpdate
    updated onUpdated
    beforeDestory onBeforeUnmount
    destoryed onUnmounted
  • 使用 vue3.0 的生命週期,一樣須要先從 vue 中導入,再在 setup 函數中使用

    <script>//引入生命週期import { onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, unMounted } from 'vue'
      export default {   name: 'home',   setup() {      //組件掛載前  onBeforeMount(() => {
             ......
          }) 
          //組件掛載先後  onMounted(() => {
             ......
          })      //組件更新前  onBeforeUpdate(() => {
             ......   
          })      //組件更新後  onUpdated(() => {
     	     ......
          })      //組件銷燬前  onBeforeUnmount(() => {
             ......  
          })      //組件銷燬後  unMounted(() => {
             ......  
          })        
          return {
             ......
          }
       }
    }
    </script>複製代碼

vue2.0 項目中使用 vue3.0 新語法

安裝 @vue/composition-api:

npm install @vue/composition-api --save

main.js:
import Vue from 'vue'import App from './App.vue'//引入@vue/composition-apiimport VueCompositionAPI from '@vue/composition-api'Vue.use(VueCompositionAPI)

Vue.config.productionTip = falsenew Vue({  render: h => h(App),
}).$mount('#app')複製代碼

vue-cli4 建立 vue3.0 項目

  • 腳手架要求:vue-cli4.0 以上
使用 vuecli4 腳手架建立 vue3.0 項目:

vue create vue3.0-demo

選擇 Vue 3在這裏插入圖片描述

路由配置:

vue3.0 下 vue-router4.0 相關 API:

  • createRouter:建立路由實例
  • createWebHashHistory:建立 hash 路由模式
  • createWebHistory:建立 history 路由模式
路由文件 router.js:
//引入路由相關APIimport { createRouter, createWebHashHistory } from 'vue-router'import Home from '../views/home/index.vue'import About from '../views/about/index.vue'//建立hash路由模式const routerHashHistory = createWebHashHistory()//建立路由實例const router = createRouter({history: routerHashHistory,routes: [
      {name: 'home',path: '/',component: Home
      },
      {name: 'about',path: '/about',component: About
      }
    ]
})export default router複製代碼
main.js:
import { createApp } from 'vue'import App from './App.vue'//引入路由實例import router from './router'//將路由實例注入到vue根實例中createApp(App).use(router).mount('#app')複製代碼
相關文章
相關標籤/搜索