Vue 3.0初探
Vue Function API (转)
vue-function-api
使开发者们可以在 Vue2.x
中使用 Vue3
引入的基于函数的逻辑复用机制。
安装
npm
1 | npm install vue-function-api --save |
yarn
1 | yarn add vue-function-api |
CDN
1 | <script src="https://unpkg.com/vue-function-api/dist/vue-function-api.umd.js"></script> |
通过全局变量 window.vueFunctionApi
来使用。
CodePen
在线示例,fork 后进行测试或 bug 反馈。
使用
您必须显式地通过 Vue.use()
来安装 vue-function-api
:
1 | import Vue from 'vue' |
安装插件后,您就可以使用新的函数式 API来书写组件了。
示例
Todo App Compare with Vue2 API
CodePen Live Demo
Single-File Component
1 | <template> |
API
setup
▸ setup(props: Props
, context: Context
): Object|undefined
组件现在接受一个新的 setup
选项,在这里我们利用函数 api 进行组件逻辑设置。
setup()
中不可以使用 this
访问当前组件实例, 我们可以通过 setup
的第二个参数 context
来访问 vue2.x API 中实例上的属性。
1 | const MyComponent = { |
value
▸ value(value: any
): Wrapper
value
函数为组件声明一个响应式属性,我们只需要在 setup
函数中返回 value
的返回值即可。
Example:
1 | import { value } from 'vue-function-api' |
state
▸ state(value: any
)
与 Vue.observable
等价。
Example:
1 | import { state } from 'vue-function-api' |
computed
▸ computed(getter: Function
, setter?: Function
): Wrapper
与 vue 2.x computed property 行为一致。
Example:
1 | import { value, computed } from 'vue-function-api' |
watch
▸ watch(source: Wrapper | () => any
, callback: (newVal, oldVal)
, options?: WatchOption
): Function
▸ watch(source: Array<Wrapper | () => any>
, callback: ([newVal1, newVal2, ... newValN], [oldVal1, oldVal2, ... oldValN])
, options?: WatchOption
): Function
watch
允许我们在相应的状态发生改变时执行一个回调函数。
返回值 Function
一个可调用的函数来停止 watch
。
effect-cleanup 当前并不支持。
WatchOption
Name | Type | Default | Description |
---|---|---|---|
lazy | boolean |
false |
与 2.x watch 中的 immediate 选项含义相反. |
deep | boolean |
false |
与 2.x 相同 |
flush | "pre" | "post" | "sync" |
"post" |
"post" : render 后触发; "pre" : render 前触发, "sync" : 同步触发 |
Example:
1 | watch( |
Example(Multiple Sources):
1 | watch( |
lifecycle
▸ onCreated(cb: Function
)
▸ onBeforeMount(cb: Function
)
▸ onMounted(cb: Function
)
▸ onXXX(cb: Function
)
支持 2.x 中除 beforeCreated
以外的所有生命周期函数,额外提供 onUnmounted
。
Example:
1 | import { onMounted, onUpdated, onUnmounted } from 'vue-function-api' |
provide, inject
▸ provide(key: string
| symbol
, value: any
)
▸ inject(key: string
| symbol
)
与 2.x 中的 provide
和 inject
选项行为一致。
Example:
1 | import { provide, inject } from 'vue-function-api' |
Context
Context
对象中的属性是 2.x 中的 vue 实例属性的一个子集。完整的属性列表:
- parent
- root
- refs
- slots
- attrs
- emit
Wrapper (包装对象)
以下内容引自 尤雨溪知乎专栏
一个包装对象只有一个属性:value
,该属性指向内部被包装的值。
为什么需要包装对象?
我们知道在 JavaScript 中,原始值类型如 string
和 number
是只有值,没有引用的。如果在一个函数中返回一个字符串变量,接收到这个字符串的代码只会获得一个值,是无法追踪原始变量后续的变化的。
因此,包装对象的意义就在于提供一个让我们能够在函数之间以引用的方式传递任意类型值的容器。这有点像 React Hooks 中的 useRef
—— 但不同的是 Vue 的包装对象同时还是响应式的数据源。有了这样的容器,我们就可以在封装了逻辑的组合函数中将状态以引用的方式传回给组件。组件负责展示(追踪依赖),组合函数负责管理状态(触发更新):
1 | setup() { |
包装对象也可以包装非原始值类型的数据,被包装的对象中嵌套的属性都会被响应式地追踪。用包装对象去包装对象或是数组并不是没有意义的:它让我们可以对整个对象的值进行替换 —— 比如用一个 filter 过的数组去替代原数组:
1 | const numbers = value([1, 2, 3]) |
如果你依然想创建一个没有包装的响应式对象,可以使用 state
API(和 2.x 的 Vue.observable()
等同):
1 | import { state } from 'vue' |
Value Unwrapping(包装对象的自动展开)
当包装对象被暴露给模版渲染上下文,或是被嵌套在另一个响应式对象中的时候,它会被自动展开 (unwrap) 为内部的值。
比如一个包装对象的绑定可以直接被模版中的内联函数修改:
1 | const MyComponent = { |
当一个包装对象被作为另一个响应式对象的属性引用的时候也会被自动展开:
1 | const count = value(0) |
以上这些关于包装对象的细节可能会让你觉得有些复杂,但实际使用中你只需要记住一个基本的规则:只有当你直接以变量的形式引用一个包装对象的时候才会需要用 .value
去取它内部的值 —— 在模版中你甚至不需要知道它们的存在。
其他
- 由于
Vue2.x
的公共 API 限制,vue-function-api
无法避免的会产生一些额外的内存负载。如果您的应用并不工作在极端内存环境下,无需关心此项。
参考资料
注:本文不以盈利为目的,仅做学习交流使用,若有侵权,请联系我删除,万分感谢!