天天看點

#導入MD文檔圖檔#VUE3.0學習筆記Vue3 的新特性(二) —— Composition-Api

不知不覺的VUE3.0釋出已經很久了。

在B站上看了教學視屏 瞬間勾起的我濃厚的學習興趣。視屏的内容講解的很棒這裡推薦一波。
https://www.bilibili.com/video/BV1yK4y1M7Fz?p=8&spm_id_from=pageDriver

亮點1

Vue 3全新的Web開發建構工具Vite

Vite是Vue的作者尤雨溪開發的Web開發建構工具,它是一個基于浏覽器原生ES子產品導入的開發伺服器,在開發環境下,利用浏覽器去解析import,在伺服器端按需編譯傳回,完全跳過了打包這個概念,伺服器随啟随用。同時不僅對Vue檔案提供了支援,還支援熱更新,而且熱更新的速度不會随着子產品增多而變慢。在生産環境下使用Rollup打包。

Vite具有以下特點:

快速的冷啟動即時熱子產品更新(HMR,Hot Module Replacement)真正按需編譯Vite是在推出Vue 3的時候開發的,目前僅支援Vue 3.x,這意味着與Vue 3不相容的庫也不能與Vite一起使用。

與Vue CLI類似,Vite也提供用npm或者yarn來生成項目結構的方式。選擇一個目錄,打開指令提示視窗,依次執行下面的指令建構腳手架項目,并啟動項目。

用npm指令建立一個vite的項目

npm init vite-app <project-name>

cd <project-name>

npm install

npm run dev
           

如果使用yarn,則依次執行下面的指令:

yarn create vite-app <project-name>

cd <project-name>

yarn

yarn dev
           

由于Vite使用了浏覽器原生的ES子產品導入功能,但IE 11并不支援ES的子產品導入,是以基于Vite開發項目,浏覽器不能使用IE11,其他主流的浏覽器均支援ES子產品的子產品功能。

我建立了一個項目 結構如下

可以發現,Vite生成的腳手架項目的目錄結構與Vue CLI生成的項目目錄結構很類似,确實是這樣的,而且開發方式也基本相同。不過Vite項目的預設配置檔案是vite.config.js,而不是vue.config.js。

package.json檔案的内容如下所示:

{
  "name": "webapp-vue3",
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "vue": "^3.0.4"
  },
  "devDependencies": {
    "vite": "^1.0.0-rc.13",
    "@vue/compiler-sfc": "^3.0.4"
  }
}
           

這裡與Vue CLI不同地方在這裡:

"dev": "vite",

"build": "vite build"           

體驗了一波非常棒,基本上都是秒啟動,改動代碼以後也是秒更新

Vue 3采用Proxy資料劫持

  1. Vue 2.x 利用 Object.defineProperty(),并且把内部解耦為 Observer, Dep, 并使用 Watcher 相連
  2. Vue 在 3.x 版本之後改用 Proxy 進行實作

那麼他們之前有什麼優缺點呢?

1、Object.defineProperty() 的問題主要有三個:

  • 不能監聽數組的變化
  • 必須周遊對象的每個屬性
  • 必須深層周遊嵌套的對象
  • 數組的這些方法是無法觸發set的:push, pop, shift, unshift,splice, sort, reverse.

    Vue 把會修改原來數組的方法定義為變異方法 (mutation method)

    非變異方法 (non-mutating method):例如 filter, concat, slice 等,它們都不會修改原始數組,而會傳回一個新的數組。

    Vue 的做法是把這些方法重寫來實作數組的劫持。

  • 使用 Object.defineProperty() 多數要配合 Object.keys() 和周遊,,于是多了一層嵌套
Object.keys(obj).forEach(key => {
  Object.defineProperty(obj, key, {
    // ...
  })
})           

當一個對象為深層嵌套的時候,必須進行逐層周遊,直到把每個對象的每個屬性都調用 Object.defineProperty() 為止。 Vue 的源碼中這樣的邏輯----walk 方法.

2、Proxy:

Proxy 對象用于定義基本操作的自定義行為(如屬性查找,指派,枚舉,函數調用等)。

  • 針對對象:針對整個對象,而不是對象的某個屬性
  • 支援數組:不需要對數組的方法進行重載,省去了衆多 hack
  • 嵌套支援: get 裡面遞歸調用 Proxy 并傳回
  • 其他

    針對對象

    不需要對 keys 進行周遊。這解決Object.defineProperty() 的第二個問題.Proxy 是針對整個 obj 的。是以 obj 内部包含的所有的 key ,都可以走進 set。(省了一個 Object.keys() 的周遊)

let obj = {
  name: 'Eason',
  age: 30
}
let handler = {
  get (target, key, receiver) {
    console.log('get', key)
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    console.log('set', key, value)
    return Reflect.set(target, key, value, receiver)
  }
}
let proxy = new Proxy(obj, handler)
proxy.name = 'Zoe' // set name Zoe
proxy.age = 18 // set age 18           

嵌套支援

Proxy 也是不支援嵌套的,這點和 Object.defineProperty() 是一樣的。是以也需要通過逐層周遊來解決。Proxy 的寫法是在 get 裡面遞歸調用 Proxy 并傳回

let obj = {
  info: {
    name: 'eason',
    blogs: ['webpack', 'babel', 'cache']
  }
}
let handler = {
  get (target, key, receiver) {
    console.log('get', key)
    // 遞歸建立并傳回
    if (typeof target[key] === 'object' && target[key] !== null) {
      return new Proxy(target[key], handler)
    }
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    console.log('set', key, value)
    return Reflect.set(target, key, value, receiver)
  }
}
let proxy = new Proxy(obj, handler)
// 以下兩句都能夠進入 set
proxy.info.name = 'Zoe'
proxy.info.blogs.push('proxy')           

其它方面

優勢:Proxy 的第二個參數可以有 13 種攔截方法,比 Object.defineProperty() 要更加豐富,Proxy 作為新标準受到浏覽器廠商的重點關注和性能優化,相比之下 Object.defineProperty() 是一個已有的老方法。

劣勢:Proxy 的相容性不如 Object.defineProperty() (caniuse 的資料表明,QQ 浏覽器和百度浏覽器并不支援 Proxy,這對國内移動開發來說估計無法接受,但兩者都支援 Object.defineProperty()),不能使用 polyfill 來處理相容性

Vue3 的新特性(二) —— Composition-Api

Composition API

: 一組低侵入式的、函數式的 API,它使我們能夠更靈活地「組合」元件的邏輯。Composition API 的靈感來自于 React Hooks ,是比 mixin 更強大的存在。它可以提高代碼邏輯的可複用性,進而實作與模闆的無關性;同時函數式的程式設計使代碼的可壓縮性更強。另外,把 Reactivity 子產品獨立開來,意味着 Vue3.0 的響應式子產品可以與其他架構相組合。

如上圖,在較大元件的編寫中,

Composition-Api

可以把複雜元件的邏輯抽地更緊湊,而且可以将公共邏輯進行抽取。

setup() 函數

setup()

是 Vue3 中的新增内容。它為基于

Composition API

的新特性提供了統一的入口。

在Vue3中,定義

methods

watch

computed

data

資料 等都放在了

setup()

函數中

注意:在

setup()

函數中通路不到Vue的

this

執行個體

1. 執行時機

setup()

函數會在

created()

生命周期之前執行。
import { ref } from "vue";
// setup 在init執行的
export default {
  name: 'HelloWorld',
  setup () {
    console.log('setup')
    const name = ref('啊sir')
    // onMounted(()=>{
    //   alert('1111')
    // })
    return {
      name
    }
  },
  mounted () {
    console.log('mounted')
  },
  beforeCreate () {
    console.log('beforeCreate')
  },
  created () {
    console.log('created')
  }
}           

接收props資料(由于setup沒有this,是以通路内部屬性隻能傳遞參數)

setup()

函數的第一個參數是

props

,元件接收的

props

資料可以在

setup()

函數内通路到

context 是 setup() 的第二個參數,它是一個上下文對象,可以通過 context 來通路Vue的執行個體 this 。

setup(props,context) {
    console.log(this)
    console.log(context)
}
           

1. reactive()

reactive()

函數接收一個普通的對象,傳回出一個響應式對象。

在Vue2.x的版本中,我們隻需要在

data()

中定義一個資料就能将它變為響應式資料,在 Vue3.0 中,需要用

reactive

函數或者

ref

來建立響應式資料。
setup() {
    // 建立響應式對象
    const state = reactive({
        count:0
    });

    // 将響應式對象return出去,暴露給模闆使用
    return state;
}           

使用響應式對象

<p>目前的count的值為:{{count}}</p>

<button @click="count++">點選增加count<  button>
           

2. ref()

ref() 函數可以根據給定的值來建立一個響應式的資料對象,傳回值是一個對象,且隻包含一個 .value 屬性。           

用 ref 建立響應式對象

setup() {
    // 建立響應式對象
    const count = ref(0);

    return {
        count
    }
}           
<p>目前的count的值為:{{count}}</p>

<button @click="count++">點選增加count</button>
           

ref 的注意事項

在 setup() 函數内,由 ref() 建立的響應式資料傳回的是對象,是以需要用 .value 來通路;