@vue/composition-api
使开发者们可以在 Vue 2.x
中使用 Vue 3.0
引入的基于函数的逻辑复用机制。
npm
npm install @vue/composition-api --save
yarn
yarn add @vue/composition-api
CDN
<script src="https://unpkg.com/@vue/composition-api/dist/vue-composition-api.umd.js"></script>
通过全局变量 window.vueCompositionApi
来使用。
在使用任何 @vue/composition-api
提供的能力前,必须先通过 Vue.use()
进行安装:
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);
安装插件后,您就可以使用新的 Composition API 来开发组件了。
请使用最新版的 TypeScript,如果你使用了 vetur
,请将 vetur.useWorkspaceDependencies
设为 true
。
为了让 TypeScript 正确的推导类型,我们必须使用 createComponent
来定义组件:
import { createComponent } from '@vue/composition-api';
const Component = createComponent({
// 启用类型推断
});
const Component = {
// 无法进行选项的类型推断
// TypeScript 无法知道这是一个 Vue 组件的选项对象
};
🚀 这里有一个配置好 TS/TSX 支持的示例仓库来帮助你快速开始.
要支持 TSX,请创建一个类型定义文件并提供正确的 JSX 定义。内容如下:
// file: shim-tsx.d.ts`
import Vue, { VNode } from 'vue';
import { ComponentRenderProxy } from '@vue/composition-api';
declare global {
namespace JSX {
// tslint:disable no-empty-interface
interface Element extends VNode {}
// tslint:disable no-empty-interface
interface ElementClass extends ComponentRenderProxy {}
interface ElementAttributesProperty {
$props: any; // specify the property name to use
}
interface IntrinsicElements {
[elem: string]: any;
}
}
}
数组索引属性无法进行自动的Unwrap
:
const state = reactive({
list: [ref(0)],
});
// no unwrap, `.value` is required
state.list[0].value === 0; // true
state.list.push(ref(1));
// no unwrap, `.value` is required
state.list[1].value === 1; // true
const a = {
count: ref(0),
};
const b = reactive({
list: [a], // a.count will not unwrap!!
});
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0; // true
const b = reactive({
list: [
{
count: ref(0), // no unwrap!!
},
],
});
// no unwrap for `count`, `.value` is required
b.list[0].count.value === 0; // true
const a = reactive({
count: ref(0),
});
const b = reactive({
list: [a],
});
// unwrapped
b.list[0].count === 0; // true
b.list.push(
reactive({
count: ref(1),
})
);
// unwrapped
b.list[1].count === 1; // true
此行为与 Vue 2 中的 Vue.observable
一致
Vue 3 中会返回一个新的的代理对象.
不支持 onTrack
和 onTrigger
选项。
✅ Support ❌ Not Support
✅ String ref && return it from setup()
:
<template>
<div ref="root"></div>
</template>
<script>
export default {
setup() {
const root = ref(null);
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value); // <div/>
});
return {
root,
};
},
};
</script>
✅ String ref && return it from setup()
&& Render Function / JSX:
export default {
setup() {
const root = ref(null);
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(root.value); // <div/>
});
return {
root,
};
},
render() {
// with JSX
return () => <div ref="root" />;
},
};
❌ Function ref:
<template>
<div :ref="el => root = el"></div>
</template>
<script>
export default {
setup() {
const root = ref(null);
return {
root,
};
},
};
</script>
❌ Render Function / JSX:
export default {
setup() {
const root = ref(null);
return () =>
h('div', {
ref: root,
});
// with JSX
return () => <div ref={root} />;
},
};
如果你依然选择在 setup()
中写 render
函数,那么你可以使用 SetupContext.refs
来访问模板引用,它等价于 Vue 2.x 中的 this.$refs
:
⚠️ 警告:SetupContext.refs
并不属于Vue 3.0
的一部分,@vue/composition-api
将其曝光在SetupContext
中只是临时提供一种变通方案。
export default {
setup(initProps, setupContext) {
const refs = setupContext.refs;
onMounted(() => {
// the DOM element will be assigned to the ref after initial render
console.log(refs.root); // <div/>
});
return () =>
h('div', {
ref: 'root',
});
// with JSX
return () => <div ref="root" />;
},
};
如果项目使用了 TypeScript,你还需要扩展 SetupContext
类型:
import Vue from 'vue';
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);
declare module '@vue/composition-api/dist/component/component' {
interface SetupContext {
readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] };
}
}