setup函数的特性
- 使用Composition API 的入口
- 在beforeCreate之前调用
- 在setup中没有this
- 返回对象中的属性刻在模板中使用
- setup函数是处于生命周期函数 beforeCreate 和 Created 两个钩子函数之间的函数 也就说在 setup函数中是无法 使用 data 和 methods 中的数据和方法的
- setup函数是 Composition API(组合API)的入口
- 在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
setup定义变量及方法ref和reactive
ref
接受一个内部值并返回一个响应式且可变的 ref
对象。ref
对象具有指向内部值的单个 property .value
reactive
是返回对象的响应式副本
1、简单数据类型(String、Number等)推荐使用ref
引入: import { ref } from 'vue' 使用:let count = ref(1); 后面想改变或获取值,通过count.value进行
2、复杂数据类型(Array、Object)推荐使用reactive
引入: import { reactive } from 'vue' 使用: let arr = reactive({ age:18 }),传入一个对象,vue会封装成Proxy对象,使用里面的方法实现响应式数据
注意:如果不需要做响应式的数据,比如从接口获取的数据,直接声明变量存放即可,不需要调用ref或者reactive
上代码:
<template>
<div class="word">
<div>ref:{{ count }}</div>
<button @click="addRefFun">点击ref自增</button>
<div>reactive:{{ state.reactivelist }}</div>
<div>reactive数组:{{ state.arr }}</div>
<button @click="addReactiveFun">点击reactive自增</button>
</div>
</template>
<script>
import { reactive, ref, toRef } from "vue";
export default {
components: {},
setup() {
const count = ref(1);
const state = reactive({
reactivelist: 1,
arr: [1, 2],
});
const addRefFun = () => {
count.value++;
};
const addReactiveFun = () => {
state.reactivelist++;
state.arr.push(3, 4, 5);
};
let age = toRef(state, "age");
state.age = 1;
console.log(state);
return {
count,
state,
age,
addRefFun,
addReactiveFun,
};
},
};
</script>
说了那么多,其实我们一直都在做同一件事情,那就是双向数据绑定。vue一共提供了两种数据响应式监听,这就有点React Hooks的味道了。ref 函数传入一个值作为参数,返回一个基于该值的响应式Ref对象,该对象中的值一旦被改变和访问,都会被跟踪到,就像我们改写后的示例代码一样,通过修改 count.value 的值,可以触发模板的重新渲染,显示最新的值。 其实,除了 ref 函数,Vue3.0中还提供了另外一个可以创建响应式对象的函数,那就是 reactive 函数。
为什么要同时提供这两个API呢?下面来说一说。
1.是为了适应不同的写法的人群
有人喜欢这种的写法:
const a = 1
const b = 2
也有人喜欢这种的写法:
const field = {
a : 1,
b : 1
}
怎么样的写法,看自己跟人。这两种风格的代码都是没有问题。关键在于个人的偏好。
2.ref只可以监听简单的数据,而reactive可以监听所有的数据
ref这种写法简单,但也有弊端,经过尝试,我发现他只能监听一些如数字、字符串、布尔之类的简单数据。而一些复杂的数据或者是对象我们可以用reactive来实现
3.使用的方式不一样
1、ref修改数据需要使用这样count.value=xxx的形式,而reactive只需要state.reactiveField=值这样来使用
2、第二点体现在template中引用时候为reactiveField,不需要state,也就是说我reactive对象里面字段是应该直接使用的
3、体现在reactive在return时候需要toRefs来转换成响应式对象
ref和reactive区别:
- 如果在template里使用的是ref类型的数据, 那么Vue会自动帮我们添加.value
- 如果在template里使用的是reactive类型的数据, 那么Vue不会自动帮我们添加.value
我门可以通过isRef / isReactive 方法来判断数据到底是ref还是reactive
setup声明周期
从'vue'中引入的生命周期函数,这些生命周期钩子注册函数只能在setup()期间同步使用 因为它们依赖于内部的全局状态来定位当前组件实例(正在调用setup()的组件实例),不在当前组件下调用这些函数会抛出一个错误。 即可以从其他文件引入使用了生命周期的函数等,放在setup中执行
和外部的生命周期函数相比,会优先指向setUp内的生命周期函数,再去执行外部的生命周期函数
vue2.0 | vue3.0 |
---|---|
beforeCreate | setup |
beforeCreate | setup |
created | setup |
beforeMount(挂载前) | onBeforeMount |
mounted(挂载后) | onMounted |
beforeUpdate(数据更新前) | onBeforeUpdate |
updated(数据更新后) | onUpdated |
beforeDestroy(销毁前) | onBeforeUnmount |
destroyed(销毁后) | onUnmounted |
<script>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onRenderTracked,
onRenderTriggered,
} from "vue";
export default {
components: {},
data() {
return {};
},
setup() {
// setup里面存着两个生命周期创建前和创建后
// beforeCreate
// created
onBeforeMount(() => {
console.log("onBefore ====> vue2.0 x beforemount");
});
onMounted(() => {
console.log("onMounted ====> vue2.0 x mount");
});
onBeforeUpdate(() => {
console.log("onBeforeUpdate ====> vue2.0 x beforeUpdate");
});
onUpdated(() => {
console.log("onUpdated ====> vue2.0 x update");
});
onBeforeUnmount(() => {
//在卸载组件实例之前调用。在这个阶段,实例仍然是完全正常的。
console.log("onBeforeUnmount ====> vue2.0 x beforeDestroy");
});
onUnmounted(() => {
//卸载组件实例后调用,调用此钩子时,组件实例的所有指令都被解除绑定,所有事件侦听器都被移除,所有子组件实例被卸载。
console.log("onUnmounted ====> vue2.0 x destroyed");
});
// 新增两个生命周期函数
//每次渲染后重新收集响应式依赖
onRenderTracked(({ key, target, type }) => {
// 跟踪虚拟DOM重新渲染时调用,钩子接收debugger event作为参数,此事件告诉你哪个操作跟踪了组件以及该操作的目标对象和键。
// type:set/get操作
// key:追踪的键
// target:重新渲染后的键
console.log("onRenderTracked");
});
//每次触发页面重新渲染时自动执行
onRenderTriggered(({ key, target, type }) => {
//当虚拟DOM重新渲染被触发时调用,和renderTracked类似,接收debugger event作为参数,
// 此事件告诉你是什么操作触发了重新渲染,以及该操作的目标对象和键
console.log("onRenderTriggered");
});
return {};
},
};
</script>