1. 程式人生 > 其它 >vue3 學習筆記 -- 尚矽谷張天禹視訊

vue3 學習筆記 -- 尚矽谷張天禹視訊

vue3 工程結構

  1. vue3,元件中的模版結構可以沒有根標籤div
// 引入的不再是Vue建構函式(通常大寫),引入的是一個名為createApp的工廠函式
import { createApp } from 'vue'
import App from './App.vue'

// 直接呼叫工廠函式,傳入外殼元件App 
// createApp(App).mount('#app')

// 建立應用例項物件app,(類似於之前的Vue2的vm,但app比vm更輕 )
const app=createApp(App)

// 掛載
app.mount('#app')

// 解除安裝
setTimeout(()=>{
  app.unmount('#app')
},1000)


// 以前的寫法。vue3不相容之前的寫法
// const vm=new Vue (
//   {
//     render:h=>h(App)
//   }
// )
// vm.$mount('#app')

拉開序幕的setup

  1. 是vue3中一個新的配置項(data,methods,computed等),值是一個函式
  2. 是所有composition api (組合api)的表演舞臺
  3. data,methods等都要配置再setup中
  4. 兩種返回值
  • 若返回一個物件,則物件中的屬性,方法,在模版中均可以直接使用
  • 弱返回一個渲染函式,則可以自定義渲染內容
  1. 儘量不要和vue2配置混合使用
  • vue2 配置中可以訪問到setup中的屬性和方法
  • 在setup中不能訪問到vue2配置(data,methods等)
  • 如果有重名,setup優先
  1. setup不能是一個async函式,因為返回值不再是return物件了,而是promise,模版看不到return物件中的屬性。後期可以返回一個promise例項,但是需要suspense和非同步元件的配合。

ref函式

  1. 作用:定義一個響應式的資料
  2. 語法: const a=ref(b)
  3. 建立一個包含響應式資料引用物件(reference物件)
  4. js操作資料,a.value
  5. 模版中讀取資料,不需要.vule,直接使用變數名
  6. 接受的資料(b),可以是基本型別,可以是物件型別
  7. 基本型別的資料,響應式依然是依靠Object.defineProperty()的get和set完成的
  8. 物件型別的資料,內部求助了vue3的一個新函式,reactive函式

reactive函式

  1. 作用:定義一個物件型別的響應式資料(基本型別不要用它,要用ref函式)
  2. 語法:const 代理物件=reactive(源物件)接收一個物件(陣列),返回一個代理物件(Proxy的例項物件,簡稱proxy物件)
  3. reactive定義的響應式資料是深層次的
  4. 內部基於ES6的Proxy實現,通過代理物件操作源物件內部資料進行操作

vue2的響應式原理

  1. 實現原理
  • 物件型別:通過Object.defineProperty()對屬性的讀取,修改進行攔截(資料劫持)
    Object.defineProperty(data,'count',{
    有人讀取時呼叫
    get(){
    return
    },
    有人修改時呼叫
    set(){
    return
    }
    })
  • 陣列型別:通過重寫更新陣列的一系列方法來實現攔截。(對陣列的變更方法進行了包裹)
  1. 存在問題:
  • 新增屬性,刪除屬性,介面不會更新。(set可以解決)
  • 直接通過下標修改陣列,介面不會自動更新(set,splice可以解決)

vue3的響應式原理

  • 通過Proxy(代理),攔截物件中任意屬性的變化,包括:屬性值的讀寫,屬性的新增,屬性的刪除

  • 通過reflect(反射):對源物件的屬性進行操作

  • 模擬vue3中實現響應式
    const p=new Proxy(person,{
    // 有人讀取p的某個屬性時呼叫
    get(target,propName){
    console.log(有人讀取了p身上的${propName}屬性,我要去更新介面了)
    // return target[propName]

    // 使用reflect方式
    return Reflect.get(target,prop)
    

    },

    // 有人修改p的某個屬性,或者增加一個屬性,跳用
    set(target,propName,value){
    console.log(有人修改了p身上的${propName}屬性,我要去更新介面了)
    // target[propName]=value

    return Reflect.set(target,prop,value)
    

    },

    // 有人刪除的某個屬性時呼叫
    deleteProperty(target,propName){
    console.log(有人刪除了p身上的${propName}屬性,我要去更新介面了)
    // return delete target[propName]

    return Reflect.deleteProperty(target,prop)
    

    }
    })

    reactive 對比ref

    1. 從定義資料角度
    • ref用來定義,基本資料型別
    • reactive用來定義,物件和陣列資料型別
    • ref也可以用來定義物件和陣列,它內部會自動通過reactive轉為代理物件
    1. 從原理角度對比
    • ref通過Object.defineProperty()的get和set來實現響應式(資料劫持)
    • reactive通過使用Proxy來實現響應式(資料劫持),並且通過Reflect操作源物件內部的資料
    1. 從使用角度對比
    • ref定義的資料:操作資料需要.value,模版中直接讀取不需要.value
    • reactive定義的資料:操作資料和讀取資料都不要.value

    setup的注意點

    1. setup執行的時機,在beforeCreate之前執行一次,this是undefined
    2. setup的引數
    • props:值是物件,包含元件外部傳進來的同時元件內部接收了的屬性
    • context:上下文物件
      • attrs:值是物件,包含元件外部傳遞過來,但沒有在props配置中宣告的屬性,相當於this.$attrs
      • slots:收到的插槽內容,相當於this.$slots
      • emit:分發自定義事件的函式,相當於this.$emit

    computed

    1. 和vue2配置功能一致
    2. 寫法
    import { reactive,computed } from 'vue'
    // 簡寫
      person.fullName=computed(()=>{
        return person.firstName+'-'+person.lastName
      })
    
    // 完整寫法
    person.fullName=computed({
      get(){
        return person.firstName+'-'+person.lastName
      },
      set(value){
        let nameArr=value.split('-')
        person.firstName=nameArr[0]
        person.lastName=nameArr[1]
      }
    })
    

    watch函式

    1. 和vue2配置功能一致
    2. 寫法
      // 監視一個ref資料
      watch(sum,(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true})
    
      // 監視多個ref資料
      watch([sum,msg],(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true})
    
      // 監視reactive資料,全部屬性。無法正確的獲取oldvalue。強制開啟了深度監視,deep配置無效
      watch(person,(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true})
    
      // 監視reactive資料,一個屬性。
      watch(()=>person.age,(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true})
    
      // 監視reactive資料,多個屬性。
      watch([()=>person.age,()=>person.name],(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true})
    
      // 監視reactive資料,這個屬性是物件。這是開啟deep配置有效
      watch([()=>person.job,()=>person.name],(newvalue,oldvalue)=>{
        console.log(newvalue,oldvalue)
      },{immediate:true,deep:true})
    

    watch監視ref定義的物件

    1. 加.value,監視的就是物件裡面的資料,
    2. 不加.value,監視的就是物件的地址,如果要監視資料,就要加deep:true

    watchEffect函式

    1. watch:既要指明監視啥,也要指明回撥函式
    2. watchEffect:不用指明監視啥,回撥函式中用到啥,就是監視的啥
    3. 類似computed,但computed側重計算返回的值必須寫返回值,watchEffect側重執行回撥不用寫返回值
     watchEffect(()=>{
        const x1=sum.value;
        const x2=person.age
        console.log(1111)
      })
    

    vue3生命週期鉤子

    1. 通過配置項的形式使用生命週期鉤子
      beforeCreate(){
      console.log('beforeCreate');
      },
      created(){
      console.log('created');
      },
      beforeMount(){
      console.log('beforeMount');
      },
      mounted(){
      console.log('Mounted');
      },
      beforeUpdate(){
      console.log('beforeUpdate');
      },
      updated(){
      console.log('updated');
      },
      beforeUnmount(){
      console.log('beforeUnmount');
      },
      unmounted(){
      console.log('unmounted');
      }

    2. 通過組合式api的形式,用哪個就引入哪個,
      beforeCreate => setup
      created => setup
      beforeMount => onBeforeMount
      mounted => onMounted
      beforeUpdate => onBeforeUpdate
      updated => onUpdated
      beforeUnmount => onBeforeUnmount
      unmounted => onUnmounted

    import {onBeforeMount} from 'vue'
    放在setup函式中
    onBeforeMount(()=>{
    console.log(111);
    })

    自定義hook函式

    1. hook,本質是一個函式,把setup函式中使用的組合式api進行了封裝
    2. 類似於vue2的mixin
    3. 優勢,複用程式碼,讓setup中的邏輯更清楚易懂

    toRef和toRefs

    1. 作用:建立一個ref物件,其value值指向另一個物件中的某個屬性
    2. 語法
        name:toRef(person,'name'),
        age:toRef(person,'age'),
        salary:toRef(person.job.jobs,'salary'),
        ...toRefs(person)
    
    1. 應用:要將響應式物件中的某個屬性單獨提供給外部使用
    2. toRef功能一致,可以批量建立多個ref物件

    shallowReactive和shallowRef

    1. shallowReactive 只處理物件最外層屬性的響應式(淺響應式)。如果一個數據結構比較深,變化只是最外層屬性,就用shallowReactive。
    2. shallowRef 只處理基本資料型別的響應式,不進行物件的響應式處理。如果一個物件資料,不會修改屬性,而是生成新的物件來替換,就用shallowRef。

    readonly 和 shallowReadonly

    1. readonly 讓一個響應式資料變成只讀的,深只讀的
    2. shallowReadonly 讓一個響應式資料變成只讀的,淺只讀的,第一層屬性是隻讀的
    3. 應用場景是不希望資料被修改
    person =readonly(person)
    

    toRaw 和 markRaw

    1. toRaw
    • 作用:將一個由reactive生成的響應式物件轉為普通物件
    • 使用場景:用於讀取響應式物件對應的普通物件,對這個普通物件的所有操作,不會引起頁面更新
    1. markRaw
    • 作用:標記一個物件,使其永遠不會再成為響應式物件
    • 應用場景:有些值不應該被設定為響應式的,比如第三方庫。當渲染不會變化的大列表,跳過響應式轉換可以提高效能
    const p=toRaw(person)
    

    customRef

    • 作用:建立一個自定義的ref,並對其依賴項和更新觸發進行顯式控制
    • 實現防抖效果,eg
    setup(){
      function myRef(value,delay){
        let timer
        return customRef((track,trigger)=>{
          return {
            get(){
              track()
              return value
            },
            set(newValue){
              clearTimeout(timer)
              timer=setTimeout(()=>{
                value=newValue
                trigger()
              },delay)
            }
          }
        })
      }
    
     let keyWord=myRef('hello',500)
    

    provide 和 inject

    1. 作用:實現祖和後代元件的通訊
    2. 父元件用provide提供資料,後代元件使用inject來接收資料
    import {provide,inject} from 'vue'
    provide('car',car)
    
    const car=inject('car')
    

    響應式資料的判斷

    1. isRef 檢查一個值是否是一個ref物件
    2. isReactive 檢查一個物件是否由reactive建立的響應式代理
    3. isReadonly 檢查一個物件是否是由readonly建立的只讀代理
    4. isProxy 堅持一個物件是否由reactive或者readonly建立的proxy代理

    傳統Options API 存在的問題

    • 新增或者修改一個需求,就需要分別在data,methods,computed裡面修改

    composition API的優勢

    • 更優雅的組織程式碼,讓相關功能的程式碼更有序的組織在一起

    fragment

    • vue2 元件必須有個根標籤
    • vue3 元件可以沒有根標籤,多個標籤包含在一個fragment虛擬元素中
    • 減少標籤層級,減少記憶體佔用

    teleport

    • 能將我們的元件移動到指定的位置
    • body 是移動到的位置,可以是#id,可以是標籤名
    <teleport to='body'>
      <div>
      </div>
    </teleport>
    

    suspense

    • 等待非同步元件或者網速慢時渲染一些額外內容,提高使用者體驗
    • 非同步引入元件
    import {defineAsyncComponent} from 'vue'
    const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
    
    • 使用suspense包裹元件,並配置好default和fallback
    <Suspense>
      <template>
        <Child/>
      </template>
    
      <template>
        <h3>載入中。。。。。</h3>
      </template>
    </Suspense>
    

    vue3 對全域性api的調整app上了

    1. Vue.config app.config
    2. Vue.config.productionTip 移除
    3. Vue.component app.component
    4. Vue.directive app. directive
    5. Vue.mixin app.use
    6. Vue.use app.use
    7. Vue.prototype app.config.globalProperties

    vue3 其他改變

    1. data始終被宣告為一個函式
    2. 過度類名的更改
      .v-enter 要改為 .v-enter-from
    3. 移除keyCode作為v-on的修飾符,比如@keyup.13
    4. 不再支援config.keyCodes
    5. 移除v-on.native修飾符

    移除過濾器filter

    • filter需要自定義語法,有學習成本和實現成本
    • 建議使用方法或者計算屬性替代