官网文档:https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
注意:需要保证自己的vue-cli版本在4.5.0以上
查看自己@vue/cli版本 Vue -V 安装或升级@vue/cli npm install -g @vue/cli 创建Vue3项目 vue create 项目名 使用ui可视化界面创建【 ps:会在浏览器中打开一个管理窗口,进行手动创建和配置选项,目前不建议用,学完所有就可以使用了 】 vue ui 启动Vue3项目 cd 进入到创建的项目中 npm run serve
官网地址;https://v3.cn.vuejs.org/guide/installation.html#vite
vite是另一门技术,是下一代的前端构建工具【 ps:是vue官网打造的,久一代的就是webpack 】。vite官网地址 https://vitejs.cn/
vite的优势:
整理vite创建vue3的相关指令
创建项目 npm init vite-app 项目名 进入项目目录 cd 项目名 安装依赖 npm install 运行项目 npm run dev
其他的东西和vue2中没什么两样
注意点:template中的写法和vue2相比有点变化
注意:这里安装的测试版( data )
直接使用google进行安装即可,要是无法进入google应用商店的话,那么:去百度chrome插件网就可以了;或者:下载一个佛跳墙 / 极光【 ps:佛跳墙现在的名字貌似改为极光了,下载安装之后,直接链接,然后就可以FQ了,有其他APN代理更好 】
注意:vue2和vue3的开发者工具最好别一起开启,开了vue2就别开vue3,开了vue3就别开vue2,很容器出问题
setup是Compostition API / 组合式API的地基,setup是一个函数,且必须有返回值,玩vue3,那么就需要提供一个平台,而这个平台就是setup
<template> <!-- 这里面能够拿到以下的东西,全靠的是setup的return返回回来的结果 --> <h1>姓名: {{name}}</h1> <h1>性别: {{sex}}</h1> <h1>工种: {{job}}</h1> <br> <br> <button @click="helloword">调用一下vue3的setup中定义的方法</button> </template> <script> export default { name: 'App', // 一、配置setup平台 setup(){ // 这里面的配置和vue2中的差不多,什么数据、方法、计算属性、生命周期.......只是写法有区别 // 配置数据【 ps:直接定义即可 】 let name = '紫邪情'; let sex = '女'; let job = 'Java'; // 配置方法 function helloword(){ // 注意点:alert()里面用的是模板字符串 - 飘字符嘛;${name}就是取上面定义的数据 alert(`我叫: ${name},性别: ${sex}.工种: ${job}`) } // setup必须有返回值 return - 就是为了把setup配置的东西交出去嘛,不然别人怎么拿到 // 但是:return有两种写法 // 1、对象写法 return { // 返回数据 name,sex,job, // 返回方法 helloword } } } </script>
补充:setup函数返回值的另一种写法:返回渲染函数写法 - 了解接口【 ps:这是为了自定义渲染内容的 】
import {h} from 'vue'
// 2、第二种写法:返回渲染函数 - 了解即可 // 这种写法:会将下面自定义写的渲染内容 放到 前面template中去渲染 // 即:template的渲染依赖于下面自定义内容 // 第一步:需要在本组件中引入渲染函数h // 第二步:使用渲染函数 并 返回 // return ( (h) => h( 'h1', '这是setup中的返回渲染函数用户') ) // 简写 return () => h('h1','这是setup中的返回渲染函数用户')
用setup和vue2的写法一起用 - 最好:坚决别用
setup()的另外一个注意点 和 其可以接收的两个参数 - 演示自行玩
this.$attrs
this.$slots
this.$emit
emits
配置项即可 - 和props声明接收属性的配置一样,如:emits: ['getField']
import {h} from 'vue'
return () => h('h1','这是setup中的返回渲染函数用户')
setup()的另外一个注意点 和 其可以接收的两个参数
this.$attrs
this.$slots
this.$emit
emits
配置项即可 - 和props声明接收属性的配置一样,如:emits: ['getField']
先做一个实例:修改setup中的数据
<template> <h1>vue3的setup函数得到的操作</h1> <h2>姓名: {{name}}</h2> <h2>性别: {{sex}}</h2> <button @click="changeData">修改setup中的数据</button> </template> <script> export default { name: 'App', // 一、配置setup平台 setup(){ let name = '紫邪情'; let sex = '女'; function changeData(){ name = '紫邪晴' sex = '男' console.log("修改之后的数据: ",name,sex); } // 1、对象写法 return { // 返回数据 name,sex, // 返回方法 changeData } } } </script>
没实现出来,原因就是:vue不认你的修改,因此:需要借助ref函数来套娃
<template> <h1>vue3的setup函数得到的操作</h1> <h2>姓名: {{name}}</h2> <h2>性别: {{sex}}</h2> <button @click="changeData">修改setup中的数据</button> </template> <script> import {ref} from 'vue' export default { name: 'App', // 一、配置setup平台 setup(){ // 使用ref函数来进行实现,进行套娃,把数据丢给ref函数进行管理 let name = ref('紫邪情'); let sex = ref('女'); function changeData(){ // console.log("修改之后的数据: ",name,sex); // 看一下ref函数的真身 console.log(name); } // 1、对象写法 return { // 返回数据 name,sex, // 返回方法 changeData } } } </script>
既然知道了ref函数的真身,那么:想要实现数据的改变就变得轻松了
有个注意点
<template> <h2>工种: {{job.type}}</h2> <h2>薪资: {{job.salary}}</h2> <button @click="changeData">查看一下ref函数中套对象的样子</button> </template> <script> import {ref} from 'vue' export default { name: 'App', // 一、配置setup平台 setup(){ // 套对象在ref中 let job = ref({ type: 'Java', salary: '20k' }); function changeData(){ // 先看一下ref中套对象的样子是怎样的 console.log(job.value); } // 1、对象写法 return { // 返回数据 job, // 返回方法 changeData } } } </script>
既然知道了ref函数中套了对象的样子长什么样的,那么:想要修改ref里面套的对象的属性就很好操作了
小小总结一下
作用:定义一个响应式的数据【 ps:即,修改数据之后可以把改后的数据渲染到页面中 】
语法:const xxx = ref(initValue)
xxx.value
<div>{{xxx}}</div>
注意点:
reactive()函数
简单玩一下reactive()函数
import {reactive} from 'vue'
<template> <h1>ref托管的数据</h1> <h2>{{name}}</h2> <br> <br> <h1>reactive托管的数据</h1> <h2>{{job.type}}</h2> <h2>{{job.salary}}</h2> <br> <br> <button @click="changeData">修改ref和reactive托管的数据</button> </template> <script> import {ref,reactive} from 'vue' export default { name: 'App', // 一、配置setup平台 setup(){ // 配置基本类型数据 - 通过ref实现 let name = ref('紫邪情'); // 使用reactive来管理数据 let job = reactive({ type: 'Java', salary: '20k' }) // 修改基本类型数据 function changeData(){ // 修改ref管理的数据类型 name.value = '紫邪晴'; // 修改reactive托管的数据 - 相比ref,不再跟value了 job.type = 'C'; job.salary = '3毛'; } return { // 返回基本类型数据 - ref托管 name, // 返回reactive托管的数据 job, // 返回函数 changeData, } } } </script>
了解reactive的细节问题
import {reactive} from 'vue'
const 代理对象 = reactive(源对象)
接收一个对象 / 数组,返回一个代理对象 / proxy对象vue2中数据监视如果是对象类型的,那么是通过Object.defineProperty()的getter和setter来做到数据监视的;如果是数组类型那么就是通过那7个API做到数据监视,但是这种方式有弊端,如下:
但是:vue3中就不会出现上面的几种情况
先来看一下Proxy长什么样子
使用Proxy进行修改数据
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>研究Proxy监视数据原理</title> </head> <body> <script> // 定义一个对象 let person = { name: '紫邪情', sex: '女' } // 利用Window.Proxy()来进行修改person // 先看一下Proxy的样子 // console.log( new Proxy(person,{} ) ); // 使用Proxy进行数据修改 /* people 就是代理对象 它代理的就是person new Proxy()就是创建一个代理对象嘛 - 后端的人太熟悉不过了 */ const people = new Proxy( person, { // 获取对象的属性时调用 /* target 就是源对象 即:person propName 就是对象中的属性名 如:name、sex..... */ get(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); console.log(`有人获取person中的${propName}属性`); return target[propName]; }, // 修改对象中的属性时调用【 ps:修改含增、改、删除是另一个配置 】 // value就是修改之后的值 set( target,propName,value ){ console.log( "target,propName,value这三个参数为: ", target,propName,value); console.log( `有人修改person中的${propName}属性` ); return target[propName] = value; }, // 删除对象中的属性时调用 deleteProperty(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); return delete target[propName]; } }) </script> </body> </html>
在vue3中数据监视不止用了window的Proxy对象,还用了window的Reflect对象
Reflect就是反射的意思,这个东西对于玩Java的人来说再熟悉不过了,所以不再过多介绍,在前段中这个是ES6的特性
认识Reflect对象
// 先看看Reflect长什么样 console.log(window.Reflect);
经过上图的查看之后,其实也就知道Reflect改怎么玩了,调对应的API就可以了【 ps:ECMA组织正打算把常用的一些API放到Reflect对象身上,如:目前把Object.defineProperty()就放在Reflect中了 - vue2的数据代理原理的API 】
使用Reflect实现数据监视
let person = { name: '紫邪情', sex: '女' } // 先看看Reflect长什么样 // console.log(window.Reflect); // 使用Reflect实现数据监视 // 1、获取对象的属性 - key-value的形式 /* key 就是对象名 value 就是对象的属性名 */ Reflect.get( person,'name' ); // 2、修改对象的属性 Reflect.set( person,'sex','男'); Reflect.set( person,'age', '18'); // 3、删除对象的属性 Reflect.deleteProperty( person,'sex');
注意:使用Reflect做对应的操作之后是有返回值的,如:Reflect.set( person,'age',18 ),返回值是true,所以:就可以利用这个返回值做很多事情,如:进行封装,而Object.defineProperty()并没有返回值
同时:Reflect支持属性名重复,即:若用set()这个API对同一个对象的同一个属性做多次相同的操作,则:不会返回异常,而是返回true / false,因此:才说可以用这个返回值做很多事情;若用Object.defineProperty()来进行相同的操作,则:会直接抛异常,甚至想要后续的代码还能运行,就只能使用try......catch....来对该部分的代码进行包裹了
vue3真正做到数据监视的原理 - 使用Proxy和Reflect对象进行套娃
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>vue3实现数据监视的真正原理</title> </head> <body> <script> let person = { name: '紫邪情', sex: '女' } const people = new Proxy( person, { // 获取对象的属性时调用 get(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); console.log(`有人获取person中的${propName}属性`); // 此处进行了Reflect套娃 // return target[propName]; return Reflect.get(target,propName); }, // 修改对象中的属性时调用【 ps:修改含增、改、删除是另一个配置 】 set( target,propName,value ){ console.log( "target,propName,value这三个参数为: ", target,propName,value); console.log( `有人修改person中的${propName}属性` ); // 此处进行了Reflect套娃 // return target[propName] = value; return Reflect.set(target,propName,value); }, // 删除对象中的属性时调用 deleteProperty(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); // 此处进行了Reflect套娃 // return delete target[propName]; return Reflect.defineProperty(target,propName); } }) </script> </body> </html>
通过Proxy代理对象:拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等
通过Reflect反射对象:对被代理对象的属性进行操作,例子如下:
const people = new Proxy( person, { // 拦截读取属性值 get(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); console.log(`有人获取person中的${propName}属性`); // 此处进行了Reflect套娃 // return target[propName]; return Reflect.get(target,propName); }, // 拦截修改属性值【 ps:是修改和新增 】 set( target,propName,value ){ console.log( "target,propName,value这三个参数为: ", target,propName,value); console.log( `有人修改person中的${propName}属性` ); // 此处进行了Reflect套娃 // return target[propName] = value; return Reflect.set(target,propName,value); }, // 拦截删除属性值 deleteProperty(target,propName){ console.log( "target,propName这两个参数为: ", target,propName); // 此处进行了Reflect套娃 // return delete target[propName]; return Reflect.defineProperty(target,propName); } })
另外:附上Proxy和Reflec对象说明的官网链接
Object.defineProperty()
的get和set来实现的数据劫持 / 数据监视 / 响应式.value
,读取数据时模板中直接读取,不需要.value
.value
<template> 姓;<input type="text" v-model="person.firstName"> <br> 名: <input type="text" v-model="person.lastName"> <br> <span>全名: {{person.fullName}}</span> </template> <script> import { reactive } from '@vue/reactivity' // 1、引入computed计算属性函数 import { computed } from '@vue/runtime-core' export default { name: 'App', setup(){ // 数据 let person = reactive({ firstName: '紫', lastName: '邪情' }) // 2、使用计算属性函数 setup中this无效,所以computed()中使用兰姆达和正常写法都无所谓 // 简写形式 - 只考虑读的问题 person.fullName = computed( ()=>{ return person.firstName + "-" + person.lastName; }) // 完整写法 - 考虑读和改的问题 /* person.fullName = computed({ get(){ return person.firstName + "-" + person.lastName; }, set(value){ const nameDataArr = value.split('-') person.firstName = nameDataArr[0] person.lastName = nameDataArr[1] } }) */ // 返回数据 return { person, } } } </script>
简单写法:监视ref托管的单个响应式数据
<template> <h1>当前值为: {{num}}</h1> <button @click="num ++ ">num++</button> </template> <script> // 1、引入watch函数 import { ref, watch } from '@vue/runtime-core' export default { name: 'App', setup(){ // 准备数据 - 用ref托管 let num = ref(0) // 一、简单写法 // 2、使用watch函数 /* 可以接受三个参数 第一个:监视的是谁? 第二个:回调函数 - 新值 和 旧值 第三个:配置项 - deep深度监视也可以配置 */ watch( num , (newValue,oldValue)=>{ console.log("num的值发生改变了",newValue,oldValue); },{immediate:true}) return { num, } } } </script>
监视多个属性:监视ref托管的多个响应式数据【 ps:数组写法 】
<template> <span>当前名字为: {{name}}</span> <br> <button @click="name += '!'">改变name</button> </template> <script> // 1、引入watch函数 import { ref, watch } from '@vue/runtime-core' export default { name: 'App', setup(){ // 准备数据 - 用ref托管 let num = ref(0) let name = ref('紫邪情') // 监视ref托管的多个响应式数据 - 变化就在这里 监事的是谁?采用数组写法即可 watch( [num,name],(newValue,oldValue)=>{ console.log("num 和 name的值发生改变了",newValue,oldValue); },{immediate:true}) return { num,name } } } </script>
监视reactive托管的一个响应式数据中的全部属性
<template> 姓名: <input type="text" v-model="person.name"> <br> 性别: <input type="text" v-model="person.sex"> <br> 地址: <input type="text" v-model="person.address.detailed.value"> <br> <br> <span>姓名: {{person.name}}</span> <br> <span>性别: {{person.sex}}</span> <br> <span>地址: {{person.address.detailed.value}}</span> </template> <script> import { reactive } from '@vue/reactivity' import { watch } from '@vue/runtime-core' export default { name: 'App', setup(){ // 准备数据 - 用reactive托管 let person = reactive({ name: '紫邪情', sex: '女', address: { detailed: { value: '浙江省杭州市' } } }) // 监视reactive托管的一个响应式数据中的全部属性 watch( person,(newValue,oldValue)=>{ console.log( "person被修改了", newValue,oldValue); }) return { person, } } } </script>
上面这种坑就是在监视此种reactive托管的一个响应式数据的全部属性时,并不能获得旧值oldValue,因为:旧值oldValue和新值newValue一样
但是:还有一种坑,就是:此种类型是强制开启了深度监视,即:配置deep:false
不顶用
监视reactive托管的一个响应式数据中的某一个属性
// 类型二、监视reactive托管的一个响应式数据中的某一个属性 /* 奇葩的地方: 1、要监视的这个属性需要写成函数式 ()=> person.name 2、可以争取获取newValue、oldValue */ watch( ()=> person.name , (newValue,oldValue)=>{ console.log("person中的name属性被修改了",newValue,oldValue); })
监视reactive托管的一个响应式数据中的某些属性 - 函数式数组写法
// 类型三、监视reactive托管的一个响应式数据中的某些属性 /* 奇葩的地方: 1、监视的多个属性需要使用数组套起来 2、数组中的每一个属性需要写成函数式 */ watch( [ ()=> person.name , ()=> person.sex ] , (newValue,oldValue)=>{ console.log("person中的name和sex属性被修改了",newValue,oldValue); })
特殊情况:监视reactive托管的一个响应式数据中的某一个属性【 ps:此属性套娃了,又是一个对象 】
// 类型四、监视reactive托管的一个响应式数据中的某个属性,但:此属性又套娃了 /* 奇葩的地方: 1、需要开启深度监视 即:deep:true 又生效了 2、不加 deep:true配置,代码会无效 */ watch( ()=> person.address , (newValue,oldValue)=>{ console.log("person中的address属性被修改了",newValue,oldValue); },{deep:true})
但是:如果不加deep:true
配置呢?
// 准备数据 - 用reactive托管 let person = reactive({ name: '紫邪情', sex: '女', address: { detailed: { value: '浙江省杭州市' } } }) // 类型一、监视reactive托管的一个响应式数据中的全部属性 /* 此种类型的坑: 1、无法正确获得oldValue的值【 ps:因newValue和oldValue的值一样 】 2、简直强制开启了深度监视 【 ps:即deep:false配置无效 】 */ watch( person,(newValue,oldValue)=>{ console.log( "person被修改了", newValue,oldValue); },{deep:false}) /* 如:这里关闭深度监视 理论上:应该监视不到address.detailed.value 但是:天真 */ // 类型二、监视reactive托管的一个响应式数据中的某一个属性 /* 奇葩的地方: 1、要监视的这个属性需要写成函数式 ()=> person.name 2、可以争取获取newValue、oldValue */ watch( ()=> person.name , (newValue,oldValue)=>{ console.log("person中的name属性被修改了",newValue,oldValue); }) // 类型三、监视reactive托管的一个响应式数据中的某些属性 /* 奇葩的地方: 1、监视的多个属性需要使用数组套起来 2、数组中的每一个属性需要写成函数式 */ watch( [ ()=> person.name , ()=> person.sex ] , (newValue,oldValue)=>{ console.log("person中的name和sex属性被修改了",newValue,oldValue); }) // 类型四、监视reactive托管的一个响应式数据中的某个属性,但:此属性又套娃了 /* 奇葩的地方: 1、需要开启深度监视 即:deep:true 又生效了 2、不加 deep:true配置,代码会无效 */ watch( ()=> person.address , (newValue,oldValue)=>{ console.log("person中的address属性被修改了",newValue,oldValue); },{deep:true}) return { person, }
<template> 姓名: <input type="text" v-model="person.name"> <br> 性别: <input type="text" v-model="person.sex"> <br> 地址: <input type="text" v-model="person.address.detailed.value"> <br> <br> <span>姓名: {{person.name}}</span> <br> <span>性别: {{person.sex}}</span> <br> <span>地址: {{person.address.detailed.value}}</span> </template> <script> import { reactive } from '@vue/reactivity' // 1、引入watchEffect函数 import { watchEffect } from '@vue/runtime-core' export default { name: 'App', setup(){ let person = reactive({ name: '紫邪情', sex: '女', address: { detailed: { value: '浙江省杭州市' } } }) // 2、使用watchEffect函数对响应式数据进行智能监视 /* 1、不需要指名要监视谁 2、不需要newValue 和 oldValue【 ps:因为都不知道要监视谁 】 */ watchEffect( ()=>{ // 所谓智能:就体现在这里面的函数体中 // 要监视谁,取决于这个函数体里面用到了谁,那就监视谁 // 如:要监视person中的name,那就直接写改写的代码即可,此函数会自动判定,从而监视 const personName = person.name // 如:要监视person中的sex,那就用它就可以了 const personSex = person.sex console.log("watchEffect智能监视函数被调用了"); // 而此函数体中没有用到的,那么:就不会去监视它 }) return { person, } } } </script>
上面这种图官网中有
对比vue2中的生命周期,vue3中改动的地方,如下所示
2、vue3中生命周期的写法问题
<script> export default { name: 'App', setup() {}, // vue3中的生命周期 - 配置项写法 【 ps:和name、setup保持平级即可 】 beforeCreate(){ console.log("------beforeCreate-----"); }, created(){ console.log("------created-----"); }, beforeMount(){ console.log("------beforeMount-----"); }, mounted(){ console.log("------mounted-----"); }, beforeUpdate(){ console.log("------beforeUpdate-----"); }, updated(){ console.log("------updated-----"); }, beforeUnmount(){ console.log("------beforeUnmount-----"); }, unmounted(){ console.log("------unmounted-----"); }, } </script>
另一种写法:组合式API写法 - 万事引入对应函数嘛 - 不过此种方式名字有点区别
beforeCreate
====> setup()
created
====> setup()
beforeMount
====> onBeforeMount
mounted
====> onMounted
beforeUpdate
====> onBeforeUpdate
updated
====> onUpdated
beforeUnMount
====> onBeforeUnMount
UnMounted
====> onUnMount
<script> // 1、引入对应的钩子函数 import { onBeforeMount, onMounted } from '@vue/runtime-core' export default { name: 'App', setup() { // 另一种写法 - 组合式API写法 - 万事引入对应的函数嘛 /* 只是注意:setup()就相当于beforeCreate() 和 created() */ // 2、使用对应的钩子函数 onBeforeMount( ()=>{ console.log("------beforeMount-----"); }) onMounted( ()=>{ console.log("------onMounted-----"); }) // 其他的都是一样的,就不写了,注意名字即可 }, </script>
需要注意一个点:配置项写法和组合式API写法同时存在同一个钩子函数时
则:setup()中所用的组合式API写法比配置项写法优先执行
1、使用toRef()函数交出单个数据
<template> <h2>姓名: {{person.name}}</h2> <h2>性别: {{person.sex}}</h2> <h2>地址: {{person.address.value}}</h2> <!-- 上面这种方式并不好,简化 --> <br> <br> <h1>使用toRef和toRefs函数进行简化</h1> <br> <!-- 下面就可以直接简写了 --> <h2>姓名: {{name}}</h2> <h2>性别: {{sex}}</h2> <h2>地址: {{address}}</h2> </template> <script> // 1、组合式还是逃不开引入的问题 import { reactive, toRef } from '@vue/reactivity' export default { name: 'App', setup() { let person = reactive({ name: '紫邪情', sex: '女', address: { value: '浙江杭州' } }) return { person, // 2、使用toRef()函数 // 使用toRef函数交出单个数据 /* 第一个参数: 交出的数据是哪个对象中的 第二个参数: 要交出的是对象中的哪个属性 */ name: toRef(person,'name'), sex: toRef(person,'sex'), // 这里需要注意一下:要交出的对象里面又套娃了,那么:第一个参数需要再进一步 address: toRef(person.address,'value'), } }, } </script>
2、使用toRefs()函数
<template> <h2>姓名: {{person.name}}</h2> <h2>性别: {{person.sex}}</h2> <h2>地址: {{person.address.value}}</h2> <!-- 上面这种方式并不好,简化 --> <br> <br> <h1>使用toRefs函数进行简化</h1> <br> <!-- 下面就可以直接简写了 --> <h2>姓名: {{name}}</h2> <h2>性别: {{sex}}</h2> <!-- 但是:美中不足就是,这里是里面套的娃,所以还得需要xxx.xxx一下 --> <h2>地址: {{address.value}}</h2> </template> <script> // 1、组合式还是逃不开引入的问题 import { reactive, toRefs } from '@vue/reactivity' export default { name: 'App', setup() { let person = reactive({ name: '紫邪情', sex: '女', address: { value: '浙江杭州' } }) return { person, // 利用toRef()交出数据,需要写多次toRef,所以还是不喜欢,那就用toRefs()函数 /* 直接说要交出哪个对象即可 注意点:return{}是一个对象,所以:使用toRefs就是对象中套对象,因此注意写法 */ ...toRefs(person) } }, } </script>
现在回过来看一下,为什么通过toRef() 和 toRefs()函数可以做到数据简化
使用toRef()举例,去看一下它长什么样子? - toRefs()函数是一样的原理
console.log( toRef(person,'name') );
const name = toRef(person,'name')
记得先引入对应的函数toRefs
与toRef
功能一致,但:可以批量创建多个RefImpl引用对象
toRefs(person)