在Vue3.0中创建响应式数据需要引用ref,reactive这两个方法,ref一般用来创建基本数据类型的响应式数据,reactive一般用来创建引用数据类型的响应式数据。
在模板中使用,跟之前没有区别,需要注意的是,ref属于将基本类型数据包装成应用类型,在模板中正常使用。在方法中访问的时候需要带上.value才能访问到。
为什么要这么写呢?是因为Proxy的原因,Proxy要进行数据劫持的时候需要接收一个对象,所以ref就对基本数据类型的数据进行了包装,使其可以进行响应式。
ref例子:
<template> <div> {{ count }} <button @click="add">+</button> </div> </template> <script> import { ref } from "vue"; export default { /* 在Vue3.0中创建响应式数据需要引用ref,reactive这两个方法,ref一般用来创建基本数据类型的响应式数据,reactive一般用来创建引用数据类型的响应式数据。 在模板中使用,跟之前没有区别,需要注意的是,ref属于将基本类型数据包装成应用类型,在模板中正常使用。在方法中访问的时候需要带上.value才能访问到。为什么要这么写呢?是因为Proxy的原因,Proxy要进行数据劫持的时候需要接收一个对象,所以ref就对基本数据类型的数据进行了包装,使其可以进行响应式。 */ name: "Test", setup(props, context) { const count = ref(0); // 定义响应式数据count const objData = { name: "erha", age: "1", skill: "拆家", }; const add = ()=>{ count.value++; } return { count, add, }; }, }; </script>
由于Proxy的机制原因,如果将reactive中的响应式数据进行解构,那么原先的响应式数据就变成不可响应的了。
为什么将可观察对象中的属性解构出来后,变成不再可观察了呢?因为通过reactive方法创建的可观察对象,内部的属性本身并不是可观察的,而是通过Proxy代理实现的读写观察,如果将这些属性解构,这些属性就不再通过原对象的代理来访问了,就无法再进行观察。
Composition API提供了一种方法来解决此机制带来的问题,那就是toRefs,它可以将reactive创建的可观察对象,转换成可观察的ref对象
当使用了toRefs的时候在模板中只需要使用name即可
<template> <div> <!-- {{ data.age }} --> {{age}} </div> </template> <script> import { reactive, toRefs } from "vue"; export default { /* 由于Proxy的机制原因,如果将reactive中的响应式数据进行解构,那么原先的响应式数据就变成不可响应的了。 为什么将可观察对象中的属性解构出来后,变成不再可观察了呢?因为通过reactive方法创建的可观察对象,内部的属性本身并不是可观察的,而是通过Proxy代理实现的读写观察,如果将这些属性解构,这些属性就不再通过原对象的代理来访问了,就无法再进行观察。Composition API提供了一种方法来解决此机制带来的问题,那就是toRefs,它可以将reactive创建的可观察对象,转换成可观察的ref对象 */ // 当使用了toRefs的时候在模板中只需要使用name即可 name: "Test", setup(props, context) { const data = reactive({ name: "lisa", age: 18, }); let { name , age} = toRefs(data) // data.age = 20; //响应式 // age = 30; //非响应式 data.age = 30; //也是响应式 return { // data, ...toRefs(data) }; }, }; </script>
Composition API提供的computed方法就相当于2.x版本中的计算属性。使用如下:
<template> <div> {{ count }} {{ doubeCount }} </div> </template> <script> import { ref, computed } from "vue"; export default { /* Composition API提供的computed方法就相当于2.x版本中的计算属性。 */ name: "Test", setup(props, context) { const count = ref(2); const doubeCount = computed(() => { return count.value * 2; }); return { count, doubeCount }; }, }; </script>
Composition API提供的watch方法相当于就是2.x的观察属性。
watch方法接收两个参数,第一个参数是一个函数,第二个参数也是个函数,第一个参数函数返回值表示要监听哪个数据,第二个参数函数,表示监听成功后的逻辑,该函数的第一个参数就是监听到目标数据变化后的值。同时watch可以监听多个数据。
使用如下:
<template> <div class="test"> <div>watch: count+num:{{ countAddNum }}</div> <button @click="addCount">点击+1</button> </div> </template> <script> import { ref, computed, watch } from "vue"; export default { /* watch方法接收两个参数,第一个参数是一个函数,第二个参数也是个函数,第一个参数函数返回值表示要监听哪个数据,第二个参数函数,表示监听成功后的逻辑,该函数的第一个参数就是监听到目标数据变化后的值。同时watch可以监听多个数据。 */ name: "Test", setup() { const count = ref(0); // 定义响应式数据count const num = ref(1); // 定义响应式数据num const countAddNum = computed(() => { // 计算属性 return count.value + num.value; }); // 相当于watch watch( [() => count.value, () => num.value], ([count, num], [oldCount, oldNum]) => { // watch 同时观察count和num两个值 console.log( `count:${count},num:${num} oldCount:${oldCount},oldNum:${oldNum}` ); } ); watch( () => { return count.value; }, (newcount) => { console.log("count变啦", newcount); } ); // 相当于methods const addCount = () => { // 定义增加count方法 count.value++; }; // 统一return出去 return { count, num, addCount, countAddNum, }; }, }; </script>
在Vue2.x版本中频繁出现的this,在Vue3.0中也消失了,取而代之的是Composition API提供的
getCurrentInstance
方法,用来获取当前组件实例,然后通过ctx获取当前上下文。
下面是路由跳转的例子:
<template> <button @click="pushRoute">push</button> </template> <script> import { getCurrentInstance } from "vue"; export default { name: "Test", setup(props, context) { const { ctx } = getCurrentInstance(); console.log(ctx); const pushRoute = () => { // 编程导航 ctx.$router.push({ path: "/", }); }; return { pushRoute, }; }, }; </script>

最后看一下Vue3.0中的生命周期,生命周期也是有所改动,钩子函数名称均发生变化。
beforeCreate,created生命周期在
setup
方法中自动执行,其余生命周期钩子函数都是从Vue中引入使用(注意在setup方法中使用)
<template> <div> <h1>{{ msg }}</h1> <div>{{ a }}</div> <button @click="setA">加A</button> </div> </template> <script> import { ref, onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, onErrorCaptured, onRenderTracked, onRenderTriggered, } from "vue"; export default { setup(props, context) { // console.log(props.msg, context) const a = ref(0); const setA = () => { return a.value++; }; // 相当于 beforeMount onBeforeMount(() => { console.log("onBeforeMount"); }); // 相当于 mounted onMounted(() => { console.log("onMounted"); }); // 相当于 beforeUpdate onBeforeUpdate(() => { console.log("onBeforeUpdate"); }); // 相当于 updated onUpdated(() => { console.log("onUpdated"); }); // 相当于 beforeDestroy onBeforeUnmount(() => { console.log("onBeforeUnmount"); }); // 相当于 destroyed onUnmounted(() => { console.log("onUnmounted"); }); onErrorCaptured(() => { // 错误监控 参考文章 https://zhuanlan.zhihu.com/p/37404624 console.log("onErrorCaptured"); }); onRenderTracked(() => { // 已渲染 console.log("onRenderTracked"); }); onRenderTriggered(() => { // 当组件更新时会首先触发此生命周期钩子 onRenderTriggered->onRenderTracked->onBeforeUpdate->onUpdated console.log("onRenderTriggered"); }); return { a, setA, }; }, name: "HelloWorld", props: { msg: String, }, }; </script>