vue2 - composition-api(未完)


原文地址 github.com

安裝

NPM

npm install @vue/composition-api
# or
yarn add @vue/composition-api

在使用 @vue/composition-api 前,必須先通過 Vue.use() 進行安裝。之后才可使用新的 組合式 API 進行組件開發。

import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)
// 使用 API
import { ref, reactive } from '@vue/composition-api'

💡 當遷移到 Vue 3 時,只需簡單的將 @vue/composition-api 替換成 vue 即可。你現有的代碼幾乎無需進行額外的改動。

CDN

在 Vue 之后引入 @vue/composition-api ,插件將會自動完成安裝。

<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.0.0-rc.5"></script>

@vue/composition-api 將會暴露在全局變量 window.VueCompositionAPI 中。

const { ref, reactive } = VueCompositionAPI

TypeScript 支持

本插件要求使用 TypeScript 3.5.1 或以上版本

為了讓 TypeScript 在 Vue 組件選項中正確地進行類型推導,我們必須使用 defineComponent 來定義組件:

import { defineComponent } from '@vue/composition-api'

export default defineComponent({
  // 類型推斷啟用
})

JSX/TSX

JSX 現已在 vuejs/jsx 中官方支持。你可以根據這篇文檔開啟支持。你也可以使用由 @luwanquan 維護的社區版本 babel-preset-vca-jsx

對於 TSX 支持,請在你的項目中創建如下聲明文件:

// file: shim-tsx.d.ts
import Vue, { VNode } from 'vue';
import { ComponentRenderProxy } from '@vue/composition-api';

declare global {
  namespace JSX {
    interface Element extends VNode {}
    interface ElementClass extends ComponentRenderProxy {}
    interface ElementAttributesProperty {
      $props: any; // specify the property name to use
    }
    interface IntrinsicElements {
      [elem: string]: any;
    }
  }
}

SSR

盡管 Vue 3 暫時沒有給出確定的 SSR 的 API,這個插件實現了 onServerPrefetch 生命周期鈎子函數。這個鈎子允許你使用傳統 API 中的 serverPrefetch 函數。

import { onServerPrefetch } from '@vue/composition-api'

export default {
  setup(props, { ssrContext }) {
    const result = ref()

    onServerPrefetch(async () => {
      result.value = await callApi(ssrContext.someId)
    })

    return {
      result,
    }
  },
}

限制

✅ 支持     ❌ 不支持

Ref 自動展開 (unwrap)

數組索引屬性無法進行自動展開:

不要 使用數組直接存取 ref 對象

const state = reactive({
  list: [ref(0)],
})
// 不會自動展開, 須使用 `.value`
state.list[0].value === 0 // true

state.list.push(ref(1))
// 不會自動展開, 須使用 `.value`
state.list[1].value === 1 // true

不要 在數組中使用含有 ref 的普通對象

const a = {
  count: ref(0),
}
const b = reactive({
  list: [a], // `a.count` 不會自動展開!!
})

// `count` 不會自動展開, 須使用 `.value`
b.list[0].count.value === 0 // true

const b = reactive({
  list: [
    {
      count: ref(0), // 不會自動展開!!
    },
  ],
})

// `count` 不會自動展開, 須使用 `.value`
b.list[0].count.value === 0 // true

✅ 在數組中,應該 總是將 ref 存放到 reactive 對象中

const a = reactive({
  count: ref(0),
})
const b = reactive({
  list: [a],
})
// 自動展開
b.list[0].count === 0 // true

b.list.push(
  reactive({
    count: ref(1),
  })
)
// 自動展開
b.list[1].count === 1 // true

⚠️ setdel 添加與刪除響應式屬性變通方案

⚠️ 警告: setdel 並非 Vue 3 的一部分。由於 Vue 2.x 響應式系統的限制,我們在插件中提供該 API 作為添加響應式屬性的一個變通方案。在 Vue 3 中,你只需要直接為屬性賦值即可。

import { reactive, set } from '@vue/composition-api'

const a = reactive({
  foo: 1
})

// 添加新的響應式屬性
set(a, 'bar', 1)

// 刪除屬性並觸發響應式更新
del(a, 'bar')

模板 Refs

✅ 字符串 ref && 從 setup() 返回 ref

<template>
  <div ref="root"></div>
</template>

<script>
  export default {
    setup() {
      const root = ref(null)

      onMounted(() => {
        // 在初次渲染后 DOM 元素會被賦值給 ref
        console.log(root.value) // <div/>
      })

      return {
        root,
      }
    },
  }
</script>

✅ 字符串 ref && 從 setup() 返回 ref && 渲染函數 / JSX

export default {
  setup() {
    const root = ref(null)

    onMounted(() => {
      // 在初次渲染后 DOM 元素會被賦值給 ref
      console.log(root.value) // <div/>
    })

    return {
      root,
    }
  },
  render() {
    // 使用 JSX
    return () => <div ref="root" />
  },
}

❌ 函數 ref

<template>
  <div :ref="el => root = el"></div>
</template>

<script>
  export default {
    setup() {
      const root = ref(null)

      return {
        root,
      }
    },
  }
</script>

❌ 在 setup() 中的渲染函數 / JSX

export default {
  setup() {
    const root = ref(null)

    return () =>
      h('div', {
        ref: root,
      })

    // 使用 JSX
    return () => <div ref={root} />
  },
}

⚠️ $refs 訪問的變通方案

⚠️ 警告: SetupContext.refs 並非 Vue 3.0 的一部分, @vue/composition-api 將其暴露在 SetupContext 中只是臨時提供一種變通方案。

如果你依然選擇在 setup() 中寫 render 函數,那么你可以使用 SetupContext.refs 來訪問模板引用,它等價於 Vue 2.x 中的 this.$refs:

export default {
  setup(initProps, setupContext) {
    const refs = setupContext.refs
    onMounted(() => {
      // 在初次渲染后 DOM 元素會被賦值給 ref
      console.log(refs.root) // <div/>
    })

    return () =>
      h('div', {
        ref: 'root',
      })

    // 使用 JSX
    return () => <div ref="root" />
  },
}

如果項目使用了 TypeScript,你還需要擴展 SetupContext 類型:

import Vue from 'vue'

declare module '@vue/composition-api' {
  interface SetupContext {
    readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] }
  }
}

Reactive

⚠️ reactive() 會返回一個修改過的原始的對象

此行為與 Vue 2 中的 Vue.observable 一致

💡 在 Vue 3 中,reactive() 會返回一個新的的代理對象

Watch

❌ 不支持 onTrackonTrigger 選項

watch(
  () => {
    /* ... */
  },
  {
    immediate: true,
    onTrack() {}, // 不可用
    onTrigger() {}, // 不可用
  }
)

shallowReadonly

⚠️ shallowReadonly() 會返回一個新的淺拷貝對象,在此之后新加的字段將不會獲得只讀或響應式狀態。

💡 在 Vue 3 中,shallowReadonly() 會返回一個新的的代理對象

readonly

⚠️ readonly() ** 只提供類型層面 ** 的只讀。

readonly() 只在類型層面提供和 Vue 3 的對齊。在其返回值或其屬性上使用 isReadonly() 檢查的結果將無法保證。

props

⚠️ 當使用 toRefs 訪問深層屬性對象 (如 toRefs(props.foo.bar) 時將會得到不正確的警告。 ⚠️ isReactive(props.foo.bar) 將會返回 false。

defineComponent({
  setup(props) {
    const { bar } = toRefs(props.foo) // it will `warn`

    // use this instead
    const { foo } = toRefs(props)
    const a = foo.value.bar
  }
})

缺失的 API

以下在 Vue 3 新引入的 API ,在本插件中暫不適用:

  • onRenderTracked
  • onRenderTriggered
  • isProxy

data() 中使用組合式 API

❌ 在 data() 中使用 ref, reactive 或其他組合式 API 將不會生效

export default {
  data() {
    return {
      // 在模版中會成為 { a: { value: 1 } }
      a: ref(1),
    }
  },
}

emit 選項

emit 僅因在類型定義中對齊 Vue3 的選項而提供,不會有任何效果。

defineComponent({
  emit: {
    // 無效
    submit: (eventOption) => {
      if (...) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  }
})

性能影響

由於 Vue 2 的公共 API 的限制,@vue/composition-api 不可避免地引入了額外的性能開銷。除非在極端情況下,否則這並不會對你造成影響。

你可以查看這個 跑分結果 了解更多信息。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM