帶你瞭解 vue-next(Vue 3.0)之 小試牛刀

看完上一章 初入茅廬以後,相信你們已經對vue-next(Vue 3.0)有所瞭解了。本章帶你掌握 vue-next 函數式的API,瞭解這些的話,不管是對於源碼的閱讀,仍是當正式版發佈時開始學習,應該都會有起到必定的輔助做用。javascript

基本例子

直接拷貝下面代碼,去運行看效果吧。推薦使用高版本的chrome瀏覽器,記得打開F12調試工具哦!html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<script src="https://s1.zhuanstatic.com/common/js/vue-next-3.0.0-alpha.0.js"></script>
<div id="app"></div>
<script> const { ref, reactive, createApp, watch, effect } = Vue function useMouse() { const x = ref(0) const y = ref(0) const update = e => { x.value = e.pageX y.value = e.pageY } Vue.onMounted(() => { window.addEventListener('mousemove', update) }) Vue.onUnmounted(() => { window.removeEventListener('mousemove', update) }) return { x, y } } const App = { props: { age: Number }, // Composition API 使用的入口 setup(props, context){ console.log('props.age', props.age) // 定義響應數據 const state = reactive({name:'zhuanzhuan'}); // 使用公共邏輯 const {x,y} = useMouse(); Vue.onMounted(()=>{ console.log('當組掛載完成') }); Vue.onUpdated(()=>{ console.log('數據發生更新') }); Vue.onUnmounted(()=>{ console.log('組件將要卸載') }) function changeName(){ state.name = '轉轉'; } // 建立監視,並獲得 中止函數 const stop = watch(() => console.log(`watch state.name:`, state.name)) // 調用中止函數,清除對應的監視 // stop() // 觀察包裝對象 watch(() => state.name, (value, oldValue) => console.log(`watch state.name value:${value} oldValue:${oldValue}`)) effect(() => { console.log(`effect 觸發了! 名字是:${state.name},年齡:${props.age}`) }) // 返回上下文,能夠在模板中使用 return { // state: Vue.toRefs(state), // 也能夠這樣寫,將 state 上的每一個屬性,都轉化爲 ref 形式的響應式數據 state, x, y, changeName, } }, template:`<button @click="changeName">名字是:{{state.name}} 鼠標x: {{x}} 鼠標: {{y}}</button>` } createApp().mount(App, '#app', {age: 123}); </script>
</body>
</html>

複製代碼

設計動機

邏輯組合與複用

組件 API 設計所面對的核心問題之一就是如何組織邏輯,以及如何在多個組件之間抽取和複用邏輯。基於 Vue 2.x 目前的 API 有一些常見的邏輯複用模式,但都或多或少存在一些問題。這些模式包括:vue

  • Mixins
  • 高階組件 (Higher-order Components, aka HOCs)
  • Renderless Components (基於 scoped slots / 做用域插槽封裝邏輯的組件)

網絡上關於這些模式的介紹不少,這裏就再也不贅述細節。整體來講,以上這些模式存在如下問題:java

  • 模版中的數據來源不清晰。舉例來講,當一個組件中使用了多個 mixin 的時候,光看模版會很難分清一個屬性究竟是來自哪個 mixinHOC 也有相似的問題。react

  • 命名空間衝突。由不一樣開發者開發的 mixin 沒法保證不會正好用到同樣的屬性或是方法名。HOC 在注入的 props 中也存在相似問題。git

  • 性能。HOCRenderless Components 都須要額外的組件實例嵌套來封裝邏輯,致使無謂的性能開銷。github

從以上useMouse例子中能夠看到:chrome

  • 暴露給模版的屬性來源清晰(從函數返回);
  • 返回值能夠被任意重命名,因此不存在命名空間衝突;
  • 沒有建立額外的組件實例所帶來的性能損耗。

類型推導

vue-next 的一個主要設計目標是加強對 TypeScript 的支持。本來指望經過 Class API 來達成這個目標,可是通過討論和原型開發,認爲 Class 並非解決這個問題的正確路線,基於 ClassAPI 依然存在類型問題。api

基於函數的 API 自然對類型推導很友好,由於 TS 對函數的參數、返回值和泛型的支持已經很是完備。更值得一提的是基於函數的 API 在使用 TS 或是原生 JS 時寫出來的代碼幾乎是徹底同樣的。數組

setup() 函數

咱們將會引入一個新的組件選項,setup()。顧名思義,這個函數將會是咱們 setup 咱們組件邏輯的地方,它會在一個組件實例被建立時,初始化了 props 以後調用。它爲咱們使用 vue-nextComposition API 新特性提供了統一的入口。

執行時機

setup 函數會在 beforeCreate 以後、created 以前執行。

state

聲明 state 主要有如下幾種類型。

基礎類型

基礎類型能夠經過 ref 這個api 來聲明,以下:

const App = {
    setup(props, context){
        const msg = ref('hello')

        function appendName(){
            msg.value = `hello ${props.name}`
        }

        return {appendName, msg}
    },
    template:`<div @click="appendName">{{ msg }}</div>`
}

複製代碼

咱們知道在 JavaScript 中,原始值類型如 stringnumber 是隻有值,沒有引用的。若是在一個函數中返回一個字符串變量,接收到這個字符串的代碼只會得到一個值,是沒法追蹤原始變量後續的變化的。

所以,包裝對象的意義就在於提供一個讓咱們可以在函數之間以引用的方式傳遞任意類型值的容器。這有點像 React Hooks 中的 useRef —— 但不一樣的是 Vue 的包裝對象同時仍是響應式的數據源。有了這樣的容器,咱們就能夠在封裝了邏輯的組合函數中將狀態以引用的方式傳回給組件。組件負責展現(追蹤依賴),組合函數負責管理狀態(觸發更新):

setup(props, context){
    // x,y 可能被 useMouse() 內部的代碼修改從而觸發更新
    const {x,y} = useMouse();

    return { x, y }
}
複製代碼

包裝對象也能夠包裝非原始值類型的數據,被包裝的對象中嵌套的屬性都會被響應式地追蹤。用包裝對象去包裝對象或是數組並非沒有意義的:它讓咱們能夠對整個對象的值進行替換 —— 好比用一個 filter 過的數組去替代原數組:

const numbers = ref([1, 2, 3])
// 替代原數組,但引用不變
numbers.value = numbers.value.filter(n => n > 1)
複製代碼

這裏補充一下,在 基礎類型 第一個例子中你可能注意到了,雖然 setup() 返回的 msg是一個包裝對象,但在模版中咱們直接用了 {{ msg }}這樣的綁定,沒有用 .value。這是由於當包裝對象被暴露給模版渲染上下文,或是被嵌套在另外一個響應式對象中的時候,它會被自動展開 (unwrap)爲內部的值。

引用類型

引用類型除了可使用 ref 來聲明,也能夠直接使用 reactive,以下:

const App = {
    setup(props, context){
        const state  = reactive({name:'zhuanzhuan'});

        function changeName(){
            state.name = '轉轉';
        }

        return {state, changeName, msg}
    },
    template:`<button @click="changeName">名字是:{{state.name}}</button>`
}

複製代碼

接收 props 數據

  • props 中定義當前組件容許外界傳遞過來的參數名稱:
props: {
    age: Number
}
複製代碼
  • 經過 setup 函數的第一個形參,接收 props 數據:
setup(props) {
  console.log('props.age', props.age)

  watch(() => props.age, (value, oldValue) => console.log(`watch props.age value:${value} oldValue:${oldValue}`))
}
複製代碼

除此以外,還能夠直接經過 watch 方法來觀察某個 prop 的變更,這是爲何呢?答案很是簡單,就是 props自己在源碼中,也是一個被 reactive 包裹後的對象,所以它具備響應性,因此在watch 方法中的回調函數會自動收集依賴,以後當 age 變更時,會自動調用這些回調邏輯。

context

setup 函數的第二個形參是一個上下文對象,這個上下文對象中包含了一些有用的屬性,這些屬性在 vue 2.x 中須要經過 this 才能訪問到,那我想經過 this 像在 vue2 中訪問一些內置屬性,怎麼辦?好比 attrs 或者 emit。咱們能夠經過 setup 的第二個參數,在 vue-next 中,它們的訪問方式以下:

const MyComponent = {
  setup(props, context) {
    context.attrs
    context.slots
    context.parent
    context.root
    context.emit
    context.refs
  }
}
複製代碼

注意:==在 setup() 函數中沒法訪問到 this==

reactive() 函數

reactive() 函數接收一個普通對象,返回一個響應式的數據對象。

基本語法

等價於 vue 2.x 中的 Vue.observable()函數,vue 3.x 中提供了 reactive() 函數,用來建立響應式的數據對象,基本代碼示例以下:

// 建立響應式數據對象,獲得的 state 相似於 vue 2.x 中 data() 返回的響應式對象
const state  = reactive({name:'zhuanzhuan'});
複製代碼

定義響應式數據供 template 使用

  1. 按需導入 reactive 函數:
const { reactive } = Vue
複製代碼
  1. setup() 函數中調用 reactive() 函數,建立響應式數據對象:
const { reactive } = Vue

setup(props, context){
    const state  = reactive({name:'zhuanzhuan'});

    return state
}
複製代碼
  1. template 中訪問響應式數據:
template:`<button>名字是:{{name}} </button>`
複製代碼

Value Unwrapping(包裝對象的自動展開)

ref() 函數

ref() 函數用來根據給定的值建立一個響應式的數據對象,ref() 函數調用的返回值是一個對象,這個對象上只包含一個 .value 屬性。

基本語法

const { ref } = Vue

// 建立響應式數據對象 age,初始值爲 3
const age = ref(3)

// 若是要訪問 ref() 建立出來的響應式數據對象的值,必須經過 .value 屬性才能夠
console.log(age.value) // 輸出 3
// 讓 age 的值 +1
age.value++
// 再次打印 age 的值
console.log(age.value) // 輸出 4
複製代碼

在 template 中訪問 ref 建立的響應式數據

  1. setup() 中建立響應式數據:
setup() {
 const age = ref(3)

     return {
         age,
         name: ref('zhuanzhuan')
     }
}
複製代碼
  1. template 中訪問響應式數據:
template:`<p>名字是:{{name}},年齡是{{age}}</p>`
複製代碼

在 reactive 對象中訪問 ref 建立的響應式數據

當把 ref() 建立出來的響應式數據對象,掛載到 reactive() 上時,會自動把響應式數據對象展開爲原始的值,不需經過 .value 就能夠直接被訪問。

換句話說就是當一個包裝對象被做爲另外一個響應式對象的屬性引用的時候也會被自動展開例如:

const age = ref(3)
const state = reactive({
  age
})

console.log(state.age) // 輸出 3
state.age++            // 此處不須要經過 .value 就能直接訪問原始值
console.log(age)       // 輸出 4
複製代碼

以上這些關於包裝對象的細節可能會讓你以爲有些複雜,但實際使用中你只須要記住一個基本的規則:只有當你直接以變量的形式引用一個包裝對象的時候纔會須要用 .value 去取它內部的值 —— 在模版中你甚至不須要知道它們的存在。

==注意:新的 ref 會覆蓋舊的 ref,示例代碼以下:==

// 建立 ref 並掛載到 reactive 中
const c1 = ref(0)
const state = reactive({
  c1
})

// 再次建立 ref,命名爲 c2
const c2 = ref(9)
// 將 舊 ref c1 替換爲 新 ref c2
state.c1 = c2
state.c1++

console.log(state.c1) // 輸出 10
console.log(c2.value) // 輸出 10
console.log(c1.value) // 輸出 0
複製代碼

isRef() 函數

isRef() 用來判斷某個值是否爲 ref() 建立出來的對象;應用場景:當須要展開某個可能爲 ref() 建立出來的值的時候,例如:

const { isRef } = Vue

const unwrapped = isRef(foo) ? foo.value : foo
複製代碼

toRefs() 函數

const { toRefs } = Vue

setup() {
    // 定義響應式數據對象
	const state = reactive({
      age: 3
    })

    // 定義頁面上可用的事件處理函數
    const increment = () => {
      state.age++
    }

    // 在 setup 中返回一個對象供頁面使用
    // 這個對象中能夠包含響應式的數據,也能夠包含事件處理函數
    return {
      // 將 state 上的每一個屬性,都轉化爲 ref 形式的響應式數據
      ...toRefs(state),
      // 自增的事件處理函數
      increment
    }
}
複製代碼

頁面上能夠直接訪問 setup() 中 return 出來的響應式數據:

template:` <div> <p>當前的age值爲:{{age}}</p> <button @click="increment">+1</button> </div> `
複製代碼

computed() 函數

computed() 用來建立計算屬性,computed() 函數的返回值是一個 ref 的實例。使用 computed 以前須要按需導入:

const { computed } = Vue
複製代碼

建立只讀的計算屬性

const { computed } = Vue

// 建立一個 ref 響應式數據
const count = ref(1)

// 根據 count 的值,建立一個響應式的計算屬性 plusOne
// 它會根據依賴的 ref 自動計算並返回一個新的 ref
const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 輸出 2
plusOne.value++            // error
複製代碼

建立可讀可寫的計算屬性

在調用 computed() 函數期間,傳入一個包含 getset 函數的對象,能夠獲得一個可讀可寫的計算屬性,示例代碼以下:

const { computed } = Vue

// 建立一個 ref 響應式數據
const count = ref(1)

// 建立一個 computed 計算屬性
const plusOne = computed({
  // 取值函數
  get: () => count.value + 1,
  // 賦值函數
  set: val => { count.value = val - 1 }
})

// 爲計算屬性賦值的操做,會觸發 set 函數
plusOne.value = 9
// 觸發 set 函數後,count 的值會被更新
console.log(count.value) // 輸出 8
複製代碼

watch() 函數

watch() 函數用來監視某些數據項的變化,從而觸發某些特定的操做,使用以前須要按需導入:

const { watch } = Vue
複製代碼

基本用法

const { watch } = Vue

const count = ref(0)

// 定義 watch,只要 count 值變化,就會觸發 watch 回調
// watch 會在建立時會自動調用一次
watch(() => console.log(count.value))
// 輸出 0

setTimeout(() => {
  count.value++
  // 輸出 1
}, 1000)
複製代碼

監視指定的數據源

監視 reactive 類型的數據源:

const { watch, reactive } = Vue

const state  = reactive({name:'zhuanzhuan'});

watch(() => state.name, (value, oldValue) => { /* ... */ })
複製代碼

監視 ref 類型的數據源:

const { watch, ref } = Vue

// 定義數據源
const count = ref(0)
// 指定要監視的數據源
watch(count, (value, oldValue) => { /* ... */ })
複製代碼

監視多個數據源

監視 reactive 類型的數據源:

const { reactive, watch, ref } = Vue

onst state = reactive({ age: 3, name: 'zhuanzhuan' })

watch(
  [() => state.age, () => state.name],    // Object.values(toRefs(state)),
  ([age, name], [prevCount, prevName]) => {
    console.log(age)         // 新的 age 值
    console.log(name)          // 新的 name 值
    console.log('------------')
    console.log(prevCount)     // 舊的 age 值
    console.log(prevName)      // 新的 name 值
  },
  {
    lazy: true // 在 watch 被建立的時候,不執行回調函數中的代碼
  }
)

setTimeout(() => {
  state.age++
  state.name = '轉轉'
}, 1000)
複製代碼

清除監視

setup() 函數內建立的 watch 監視,會在當前組件被銷燬的時候自動中止。若是想要明確地中止某個監視,能夠調用 watch() 函數的返回值便可,語法以下

// 建立監視,並獲得 中止函數
const stop = watch(() => { /* ... */ })

// 調用中止函數,清除對應的監視
stop()
複製代碼

在 watch 中清除無效的異步任務

有時候,當被 watch 監視的值發生變化時,或 watch 自己被 stop 以後,咱們指望可以清除那些無效的異步任務,此時,watch 回調函數中提供了一個 cleanup registrator function 來執行清除的工做。這個清除函數會在以下狀況下被調用:

  • watch 被重複執行了
  • watch 被強制 stop 了

Template 中的代碼示例以下:

/* template 中的代碼 */
<input type="text" v-model="keywords" />

複製代碼

Script 中的代碼示例以下:

// 定義響應式數據 keywords
const keywords = ref('')

// 異步任務:打印用戶輸入的關鍵詞
const asyncPrint = val => {
  // 延時 1 秒後打印
  return setTimeout(() => {
    console.log(val)
  }, 1000)
}

// 定義 watch 監聽
watch(
  keywords,
  (keywords, prevKeywords, onCleanup) => {
    // 執行異步任務,並獲得關閉異步任務的 timerId
    const timerId = asyncPrint(keywords)

    // keywords 發生了變化,或是 watcher 即將被中止.
    // 取消還未完成的異步操做。
    // 若是 watch 監聽被重複執行了,則會先清除上次未完成的異步任務
    onCleanup(() => clearTimeout(timerId))
  },
  // watch 剛被建立的時候不執行
  { lazy: true }
)

// 把 template 中須要的數據 return 出去
return {
  keywords
}
複製代碼

之因此要用傳入的註冊函數來註冊清理函數,而不是像 ReactuseEffect 那樣直接返回一個清理函數,是由於watcher 回調的返回值在異步場景下有特殊做用。咱們常常須要在 watcher 的回調中用 async function 來執行異步操做:

const data = ref(null)
watch(getId, async (id) => {
  data.value = await fetchData(id)
})
複製代碼

咱們知道 async function 隱性地返回一個 Promise - 這樣的狀況下,咱們是沒法返回一個須要被馬上註冊的清理函數的。除此以外,回調返回的 Promise 還會被 Vue 用於內部的異步錯誤處理。

watch 回調的調用時機

默認狀況下,全部的 watch 回調都會在當前的 renderer flush 以後被調用。這確保了在回調中 DOM 永遠都已經被更新完畢。若是你想要讓回調在 DOM 更新以前或是被同步觸發,可使用 flush 選項:

watch(
  () => count.value + 1,
  () => console.log(`count changed`),
  {
    flush: 'post', // default, fire after renderer flush
    flush: 'pre', // fire right before renderer flush
    flush: 'sync' // fire synchronously
  }
)
複製代碼

所有的 watch 選項(TS 類型聲明)

interface WatchOptions {
  lazy?: boolean
  deep?: boolean
  flush?: 'pre' | 'post' | 'sync'
  onTrack?: (e: DebuggerEvent) => void
  onTrigger?: (e: DebuggerEvent) => void
}

interface DebuggerEvent {
  effect: ReactiveEffect
  target: any
  key: string | symbol | undefined
  type: 'set' | 'add' | 'delete' | 'clear' | 'get' | 'has' | 'iterate'
}
複製代碼
  • lazy與 2.x 的 immediate 正好相反
  • deep與 2.x 行爲一致
  • onTrack 和 onTrigger 是兩個用於 debug 的鉤子,分別在 watcher - 追蹤到依賴和依賴發生變化的時候被調用,得到的參數是一個包含了依賴細節的 debugger event。

LifeCycle Hooks 生命週期函數

全部現有的生命週期鉤子都會有對應的 onXXX 函數(只能在 setup() 中使用):

const { onMounted, onUpdated, onUnmounted } = Vue

const MyComponent = {
  setup() {
    onMounted(() => {
      console.log('mounted!')
    })

    onUpdated(() => {
      console.log('updated!')
    })

    // destroyed 調整爲 unmounted
    onUnmounted(() => {
      console.log('unmounted!')
    })
  }
}
複製代碼

下面的列表,是 vue 2.x 的生命週期函數與新版 Composition API 之間的映射關係:

  • beforeCreate -> setup()
  • created -> setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

provide & inject

provide()inject() 能夠實現嵌套組件之間的數據傳遞。這兩個函數只能在 setup() 函數中使用。父級組件中使用 provide() 函數向下傳遞數據;子級組件中使用 inject() 獲取上層傳遞過來的數據。

共享普通數據

App.vue 根組件:

<template>
  <div id="app">
    <h1>App 根組件</h1>
    <hr />
    <LevelOne />
  </div>
</template>

<script> import LevelOne from './components/LevelOne' // 1. 按需導入 provide import { provide } from '@vue/composition-api' export default { name: 'app', setup() { // 2. App 根組件做爲父級組件,經過 provide 函數向子級組件共享數據(不限層級) // provide('要共享的數據名稱', 被共享的數據) provide('globalColor', 'red') }, components: { LevelOne } } </script>
複製代碼

LevelOne.vue 組件:

<template>
  <div>
    <!-- 4. 經過屬性綁定,爲標籤設置字體顏色 -->
    <h3 :style="{color: themeColor}">Level One</h3>
    <hr />
    <LevelTwo />
  </div>
</template>

<script> import LevelTwo from './LevelTwo' // 1. 按需導入 inject import { inject } from '@vue/composition-api' export default { setup() { // 2. 調用 inject 函數時,經過指定的數據名稱,獲取到父級共享的數據 const themeColor = inject('globalColor') // 3. 把接收到的共享數據 return 給 Template 使用 return { themeColor } }, components: { LevelTwo } } </script>
複製代碼

LevelTwo.vue 組件:

<template>
  <div>
    <!-- 4. 經過屬性綁定,爲標籤設置字體顏色 -->
    <h5 :style="{color: themeColor}">Level Two</h5>
  </div>
</template>

<script> // 1. 按需導入 inject import { inject } from '@vue/composition-api' export default { setup() { // 2. 調用 inject 函數時,經過指定的數據名稱,獲取到父級共享的數據 const themeColor = inject('globalColor') // 3. 把接收到的共享數據 return 給 Template 使用 return { themeColor } } } </script>
複製代碼

共享 ref 響應式數據

以下代碼實現了點按鈕切換主題顏色的功能,主要修改了 App.vue 組件中的代碼,LevelOne.vueLevelTwo.vue 中的代碼不受任何改變:

<template>
  <div id="app">
    <h1>App 根組件</h1>

	<!-- 點擊 App.vue 中的按鈕,切換子組件中文字的顏色 -->
    <button @click="themeColor='red'">紅色</button>
    <button @click="themeColor='blue'">藍色</button>
    <button @click="themeColor='orange'">橘黃色</button>

    <hr />
    <LevelOne />
  </div>
</template>

<script> import LevelOne from './components/LevelOne' import { provide, ref } from '@vue/composition-api' export default { name: 'app', setup() { // 定義 ref 響應式數據 const themeColor = ref('red') // 把 ref 數據經過 provide 提供的子組件使用 provide('globalColor', themeColor) // setup 中 return 數據供當前組件的 Template 使用 return { themeColor } }, components: { LevelOne } } </script>
複製代碼

template refs

經過 ref() 還能夠引用頁面上的元素或組件。

元素的引用

示例代碼以下:

<template>
  <div>
    <h3 ref="h3Ref">TemplateRefOne</h3>
  </div>
</template>

<script> import { ref, onMounted } from '@vue/composition-api' export default { setup() { // 建立一個 DOM 引用 const h3Ref = ref(null) // 在 DOM 首次加載完畢以後,才能獲取到元素的引用 onMounted(() => { // 爲 dom 元素設置字體顏色 // h3Ref.value 是原生DOM對象 h3Ref.value.style.color = 'red' }) // 把建立的引用 return 出去 return { h3Ref } } } </script>
複製代碼

組件的引用

TemplateRefOne.vue 中的示例代碼以下:

<template>
  <div>
    <h3>TemplateRefOne</h3>

    <!-- 4. 點擊按鈕展現子組件的 count 值 -->
    <button @click="showNumber">獲取TemplateRefTwo中的count值</button>

    <hr />
    <!-- 3. 爲組件添加 ref 引用 -->
    <TemplateRefTwo ref="comRef" />
  </div>
</template>

<script> import { ref } from '@vue/composition-api' import TemplateRefTwo from './TemplateRefTwo' export default { setup() { // 1. 建立一個組件的 ref 引用 const comRef = ref(null) // 5. 展現子組件中 count 的值 const showNumber = () => { console.log(comRef.value.count) } // 2. 把建立的引用 return 出去 return { comRef, showNumber } }, components: { TemplateRefTwo } } </script>
複製代碼

TemplateRefTwo.vue 中的示例代碼:

<template>
  <div>
    <h5>TemplateRefTwo --- {{count}}</h5>
    <!-- 3. 點擊按鈕,讓 count 值自增 +1 -->
    <button @click="count+=1">+1</button>
  </div>
</template>

<script> import { ref } from '@vue/composition-api' export default { setup() { // 1. 定義響應式的數據 const count = ref(0) // 2. 把響應式數據 return 給 Template 使用 return { count } } } </script>
複製代碼

createComponent

這個函數不是必須的,除非你想要完美結合 TypeScript 提供的類型推斷來進行項目的開發。

這個函數僅僅提供了類型推斷,方便在結合 TypeScript 書寫代碼時,能爲 setup() 中的 props 提供完整的類型推斷。

import { createComponent } from 'vue'

export default createComponent({
  props: {
    foo: String
  },
  setup(props) {
    props.foo // <- type: string
  }
}
複製代碼

參考


以上就是 vue-next(Vue 3.0) API,相信你們已經能夠靈活運用了吧。

那麼你們必定很好奇 vue-next 響應式的原理,下一章vue-next(Vue 3.0)之 爐火純青 帶你解密。

相關文章
相關標籤/搜索