首先咱们来看看 option-api。javascript
default export { data() { return { state:0 } }, methods:{ myFun() { console.log(this.state) } } }
上面代码的方式就是 option-api, 也是 vue2.x 中最经常使用的方式。
vue
在vue3.x中,可使用下面的 composition-api 方式。java
default export { setup(){ const state = ref(0) function myFunOne() { console.log(state.value) } function myFunTwo() { console.log(state.value + 1) } return { state, myFunOne } } }
看下面的图片(来源:https://composition-api.vuejs.org/#code-organization),相同业务的代码颜色相同,能够看见 Options API 的相同业务代码分散在各处,这样后期维护起来就会很是麻烦,而Composition-Api 解决了这个痛点。
node
关于 composition-api 所包含的函数有以上这么多,下面根据相关例子一个个来学习。
react
setup
功能是新的组件选项。它是组件内部使用Composition-API的入口。
vue-router
它有两个可选参数 props 和 context。
这两个参数能够解构使用。api
props: { msg: String }, // 须要在 emits 中声明 否则会报错 下面会有解释 emits: { sayhi: payload => { // validate payload by returning a boolean return payload } }, // 1. 通常使用 // setup(props, context) { // console.log('====>', props) // context.emit('sayhi', 'hi') //} // 2. 可解构使用 setup({ msg }, { emit }) { console.log('====>', msg) emit('sayhi', 'hi') }
在 setup 中使用 emit , 须要在emits 中声明它,不然会报如下错误。数组
Extraneous non-emits event listeners (此处是函数名) were passed to component but could not be automatically inherited because component renders fragment or text root nodes. If the listener is intended to be a component custom event listener only, declare it using the "emits" option.
<template> <div> <div>{{ state }}</div> <button @click="addOne">新增1</button> </div> </template> <script lang="ts"> import { defineComponent, ref, onMounted } from "vue" export default defineComponent({ setup(){ // 经过 ref 初始化一个响应式的对象 const state = ref(0) // 在生命周期 onMounted 中打印 state onMounted(() => { console.log(state) }) function addOne() { state.value += 1 } return { state, addOne } } }) </script>
咱们再来看看这段代码。
在 dom挂载完毕的生命周期 onMounted
中打印 state
, 发现它是一个对象。
由于 state
是经过ref 传参,而后返回的一个对象( ref 是一个函数,它接受一个参数,返回的一个响应式对象 )。咱们初始化的这个 0 做为参数包裹到这个对象中去,在将来能够检测到改变并做出对应的相应。
在 addOne
函数中, 若要改变 这个 state
响应式对象的值, 则须要经过 赋值 state.value
来实现。
在 template 模板中 ,vue 已经帮咱们自动获取了其 value属性,因此咱们只须要传{{ state }}
便可。
dom
reactive 和 ref 很是类似, 也是一个函数, 可是其接收一个对象。咱们改造上面学习 ref 的 例子来了解 reactive。函数
<template> <div> <div>{{ state }}</div> <button @click="addOne">新增1</button> </div> </template> <script lang="ts"> import { defineComponent, onMounted, reactive, toRefs } from "vue" export default defineComponent({ setup(){ // 经过 reactive 初始化数据 const data = reactive({ state: 0, }) // const state = ref(0) // 在生命周期 onMounted 中打印 state onMounted(() => { console.log('无 toRefs', data) console.log('经过 toRefs 处理', toRefs(data)) }) function addOne() { data.state += 1 } return { // ...data, // 这样导出会使数据失去响应式 ...toRefs(data), // 经过 toRefs 使得 data 中数据得到响应式 addOne } } }) </script>
与 ref 相比:
注意点:
使用 reactive
时要记得使用 toRefs
保证 reactive
对象属性保持响应性。
// 经过 reactive 初始化数据 const data = reactive({ state: 0, num: 2, arr: [1, 2, 3] }) // 简单监听 watch(data, () => { console.log(data.state) }) // 下面直接监听data.state会报错。watch 监听的目标只能是getter/effect函数、ref、reactive对象或数组。 // watch(data.state, (newValue, oldValue) => { // console.log('newValue', newValue) // console.log('oldValue', oldValue) // }) // 监听 新的值和旧值 watch(() => data.state, (newValue, oldValue) => { console.log('newValue', newValue) console.log('oldValue', oldValue) }) // watch 监听多个属性,返回的也是多个值的数组 watch([() => data.num, () => data.state], (newValue, oldValue) => { console.log('old', oldValue) console.log('new', newValue) }) // watchEffect 不须要指定监听的属性 watchEffect(()=>{ console.log('watchEffect ===>', data.state); });
A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types.
watch 监听源只能是getter/effect函数、ref、reactive对象或数组。
具体用法如上述代码所见
watch
只能监听指定的属性而作出变动,vue3.x能够同时监听多个属性。watchEffect 和 watch 相似,能够监听属性的变化。具体使用方式如上述代码。
watchEffect
不须要指定监听的属性,它会自动的收集依赖,只要咱们回调中引用到了 响应式的属性, 那么当这些属性变动的时候,这个回调都会执行,而 watch
只能监听指定的一个或多个属性而作出变动。watch
能够获取到新值与旧值,而 watchEffect
是拿不到的 oldValue
watchEffect
在组件初始化的时候就会默认执行一次,而 watch 不须要。计算属性和vue2.x 中同样,代码示例以下。
<template> <div> <div>{{ state }}</div> <div>{{ double }}</div> <button @click="addOne">新增1</button> </div> </template> <script lang="ts"> import { computed, defineComponent, reactive, toRefs } from "vue" export default defineComponent({ setup(){ // 经过 reactive 初始化数据 const data = reactive({ state: 0, }) // 经过计算属性得到的新的值 const double = computed(() => data.state * 2) function addOne() { data.state += 1 } return { ...toRefs(data), // 经过 toRefs 使得 data 中数据得到响应式 addOne, double } } }) </script>