@vue/composition-api
v1.7.2
Published
Provide logic composition capabilities for Vue.
Downloads
592,584
Readme
@vue/composition-api
用于提供 组合式 API 的 Vue 2 插件.
English | 中文 ・ 组合式 API 文档
⚠️ 随着 Vue 2.7的发布,它内置了Composition API,你不再需要这个插件了。因此,这个插件已经进入维护模式,将只支持Vue 2.6 或更早的版本。本项目将在 2022 年底达到生命终点(EOL)。
安装
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'
:bulb: 当迁移到 Vue 3 时,只需简单的将
@vue/composition-api
替换成vue
即可。你现有的代码几乎无需进行额外的改动。
CDN
在 Vue 之后引入 @vue/composition-api
,插件将会自动完成安装。
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/[email protected]"></script>
@vue/composition-api
将会暴露在全局变量 window.VueCompositionAPI
中。
const { ref, reactive } = VueCompositionAPI
TypeScript 支持
本插件要求使用 TypeScript 4.2 或以上版本
为了让 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,
}
},
}
浏览器兼容性
@vue/composition-api
支持所有现代浏览器以及IE11+。对于更低版本的IE浏览器你需要安装WeakMap
polyfill (例如使用 core-js
库)。
限制
:white_check_mark: 支持 :x: 不支持
Ref
自动展开 (unwrap)
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
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
模板 Refs
<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>
export default {
setup() {
const root = ref(null)
onMounted(() => {
// 在初次渲染后 DOM 元素会被赋值给 ref
console.log(root.value) // <div/>
})
return {
root,
}
},
render() {
// 使用 JSX
return () => <div ref="root" />
},
}
<template>
<div :ref="el => root = el"></div>
</template>
<script>
export default {
setup() {
const root = ref(null)
return {
root,
}
},
}
</script>
export default {
setup() {
const root = ref(null)
return () =>
h('div', {
ref: root,
})
// 使用 JSX
return () => <div ref={root} />
},
}
:warning: 警告:
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
此行为与 Vue 2 中的 Vue.observable
一致
:bulb: 在 Vue 3 中,
reactive()
会返回一个新的的代理对象
⚠️ 警告:
set
和del
并非 Vue 3 的一部分。由于 Vue 2.x 响应式系统的限制, 我们在这里提供它们作为一种变通方案。 在 Vue 2中,你将需要调用set
去追踪object
上新的属性 (与Vue.set
类似,但用于由 Composition API 创建的reactive objects
)。在 Vue 3 中,你只需要像对待普通对象一样直接为属性赋值即可。同样地, 在 Vue 2 中你将需要调用
del
去 确保响应式对象中属性的删除将触发视图更新 (与Vue.delete
类似,但用于由 Composition API 创建的reactive objects
)。在Vue3中,你只需要通过调用delete foo.bar
来删除它们。
import { reactive, set, del } from '@vue/composition-api'
const a = reactive({
foo: 1
})
// 添加新的响应式属性
set(a, 'bar', 1)
// 刪除属性并触发响应式更新
del(a, 'bar')
Watch
watch(
() => {
/* ... */
},
{
immediate: true,
onTrack() {}, // 不可用
onTrigger() {}, // 不可用
}
)
createApp
在 Vue3 中,引入了 createApp()
来隔离不同应用实例的上下文(plugin, components 等)。 由于 Vue2 的设计,在这个插件中,我们提供 createApp()
作为一个向前兼容的 API ,它只是全局的一个别名。
const app1 = createApp(RootComponent1)
app1.component('Foo', Foo) // 相当于 Vue.component('Foo', Foo)
app1.use(VueRouter) // 相当于 Vue.use(VueRouter)
const app2 = createApp(RootComponent2)
app2.component('Bar', Bar) // 相当于 Vue.component('Bar', Bar)
createElement
/ h
在 Vue2中 createElement
/ h
只能通过 render()
函数访问。要在 render()
之外使用它, 你可以显式地给它绑定一个组件实例。
:warning: 警告: 此功能是作为 Vue 2 的变通方法提供的,它不是 Vue 3 API 的一部分。
import { h as _h } from '@vue/composition-api'
export default {
setup() {
const vm = getCurrentInstance()
const h = _h.bind(vm)
return () =>
h('div', {
ref: 'root',
})
},
}
shallowReadonly
:bulb: 在 Vue 3 中,
shallowReadonly()
会返回一个新的的代理对象
readonly
readonly()
只在类型层面提供和 Vue 3 的对齐。在其返回值或其属性上使用 isReadonly() 检查的结果将无法保证。
props
defineComponent({
setup(props) {
const { bar } = toRefs(props.foo) // it will `warn`
// use this instead
const { foo } = toRefs(props)
const a = foo.value.bar
}
})
computed().effect
由于实现上的不同, 在 @vue/composition-api
中没有 ReactiveEffect
这种概念。 因此, effect
为 true
只是为了能够区分 computed 和 refs:
function isComputed<T>(o: ComputedRef<T> | unknown): o is ComputedRef<T>
function isComputed(o: any): o is ComputedRef {
return !!(isRef(o) && o.effect)
}
缺失的 API
以下在 Vue 3 新引入的 API ,在本插件中暂不适用:
onRenderTracked
onRenderTriggered
isProxy
在 data()
中使用组合式 API
export default {
data() {
return {
// 在模版中会成为 { a: { value: 1 } }
a: ref(1),
}
},
}
emit
选项
defineComponent({
emit: {
// 无效
submit: (eventOption) => {
if (...) {
return true
} else {
console.warn('Invalid submit event payload!')
return false
}
}
}
})
性能影响
由于 Vue 2 的公共 API 的限制,@vue/composition-api
不可避免地引入了额外的性能开销。除非在极端情况下,否则这并不会对你造成影响。
你可以查看这个 跑分结果 了解更多信息。