vue3技术简易入门剖析(一)https://developer.aliyun.com/article/1432712
四、vue3中的响应式原理
4.1 vue2中的响应式原理
通过 Object.defineProperty()
方法来实现。通过getter
和setter
方法来完成。
Object.defineProperty(obj,'属性',{ get(){},set(){} })
4.2 vue3的响应式原理
ref() ===> reactive()
通过Es6
中的 proxy
代理来完成的。
4.2.1 回顾ES6中proxy的使用
<body> <script type="text/javascript"> let obj = { name:'张三', age:18, address:'郑州' } let p = new Proxy(obj,{ //target表示 被代理对象 propKey表示读取的属性值 get(target,propKey){ console.log(`获取了${propKey}属性`) return target[propKey] }, set(target,propKey,value){ console.log(`修改了${propKey}属性`) target[propKey] = value }, deleteProperty(target,propKey){ console.log(`删除了${propKey}属性`) return delete target[propKey] } }) </script> </body> </html> 获取属性调用get()方法 修改或者新增属性调用set()方法 删除属性调用deleteProperty()方法
4.2.2 ES6 中的 Reflect
反射
反射:获取对象中的属性值
概念: 见教程:https://es6.ruanyifeng.com/#docs/reflect
**使用:**Reflect是与Proxy 完全对应的方法,我们可以通过Proxy代理对 对象的操作添加一些拦截 做一些事情,同时可以使用Reflect反射 来从对象中获取数据。主要用途:封装底层框架,保证代码顺利执行
<body> <script type="text/javascript"> let obj = { name:'张三', age:18, address:'郑州' } let p = new Proxy(obj,{ //target表示 被代理对象 propKey表示读取的属性值 get(target,propKey){ console.log(`获取了${propKey}属性`) return Reflect.get(target,propKey) }, set(target,propKey,value){ console.log(`修改了${propKey}属性`) Reflect.set(target,propKey,value) }, deleteProperty(target,propKey){ console.log(`删除了${propKey}属性`) return Reflect.deleteProperty(target,propKey) } }) </script> </body> </html>
五、computed计算属性
仍然可以按照vue2中的语法来实现计算属性。
但是这里我们推荐使用vue3
- 首先引入computed
import {computed} from 'vue'
- 在setup中定义计算属性
<template> <input v-model="msg"/> <p>转为大写:{{newVal}}</p> </template> <script> import {ref,computed} from 'vue' export default{ setup(){ let msg = ref('') //定义计算属性 let newVal = computed(()=>{ return msg.value.toUpperCase() }) return {msg,newVal} } } </script>
六、watch侦听器
首先:vue2中侦听器的使用方式在vue3中仍然可以使用
6.1 watch侦听
vue3的方式定义侦听器:
语法格式:
import {watch} from 'vue' export default{ watch(被监视的数据,监视的回调函数), watch(name,(newVal,oldVal)=>{}) }
案例:
<template> <!-- vue3中的侦听器 --> <h1>数量:{{count}}</h1> <button type="button" @click='count++'>点我+1</button> <h1>数量:{{num}}</h1> <button type="button" @click='num+=2'>点我+2</button> <h1>===========================reactive数据监听====================================</h1> <h1>姓名:{{obj.name}}</h1> <button type="button" @click='obj.name+="#"'>点我改变名字</button> <h1>年龄:{{obj.age}}</h1> <button type="button" @click='obj.age+=1'>点我改变年龄</button> <h1>班级:{{obj.class.c1}}</h1> <button type="button" @click='obj.class.c1+="--"'>点我改变班级</button> </template> <script> import {ref,reactive,watch} from 'vue' export default{ setup(){ let count = ref(0) let num = ref(10) let obj = reactive({ name:'张三', age:18, address:'郑州', class:{ c1:'qy147', c2:'qy148' } }) //监视一个数据 /* watch(count,(newVal,oldVal)=>{ console.log(newVal,oldVal) }) */ //监听多个数据 此时的newVal,oldVal 都是以数组形式展示数据 /* watch([count,num],(newVal,oldVal)=>{ console.log(newVal,oldVal) }) */ //监听reactive对象数据 //注意:此处可以监听到数据的改变,但是无法获取到oldVal //reactive响应式数据的监听,vue3会自动开启深度监听 并且是强制开启的 deep配置没有效果 /* watch(obj,(newVal,oldVal)=>{ console.log(newVal,oldVal) },{immediate:true}) */ //监听对象中单独的属性 //注意:需要把要监听的属性以函数的形式返回 才可以监视到 //此时的oldVal也可以使用 /* watch(()=>obj.class.c1,(newVal,oldVal)=>{ console.log(newVal,oldVal) },{immediate:true}) */ //此时直接监听class对象 此时需要开启 deep:true属性 watch(()=>obj.class,(newVal,oldVal)=>{ console.log(newVal,oldVal) },{immediate:true,deep:true}) return {count,num,obj} } } </script>
6.2 watchEffect
侦听
**简介:**立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。也就是说监视的回调函数中用到了哪个属性,那么当这个属性发生改变时,watchEffect回调就会执行。
watchEffect(()=>{ num.value+=1 console.log('watchEffect执行了') })
只要num的值 发生了改变 watchEffect中的回调函数就会执行。
七、vue3内置组件
7.1 Fragment组件
概念:Fragment就是一个虚拟的元素,vue3中元素不必使用根元素包括,其实就是放在一个Fragment虚拟元素中了。
7.2 Teleport组件 传送门
**简介:**Vue 鼓励我们通过将 UI 和相关行为封装到组件中来构建 UI。我们可以将它们嵌套在另一个内部,以构建一个组成应用程序 UI 的树。
然而,有时组件模板的一部分逻辑上属于该组件,而从技术角度来看,最好将模板的这一部分移动到 DOM 中 Vue app 之外的其他位置。
一个常见的场景是创建一个包含全屏模式的组件。在大多数情况下,你希望模态框的逻辑存在于组件中,但是模态框的快速定位就很难通过 CSS 来解决,或者需要更改组件组合。
语法格式:
<teleport to="#Father"></teleport> 通过to属性指定要传送的位置。to属性的值: 可以是html标签名 也可以是标签的id值
官方案例: 点击按钮 打开弹出框,teleport内置组件可以让弹出框显示在指定的位置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZjdmYW1-1655452084601)(assets/image-20220309110532944.png)]
Father.vue组件:
<template> <div id="Father"> <h1>这里是父组件</h1> <Son></Son> </div> </template> <script> import Son from './Son.vue' export default{ components:{Son} } </script> <style scoped> #Father{ border:1px solid red; background-color: red; line-height: 100px; } </style>
Son.vue组件
<template> <div id="son"> <h1>这里是儿子组件</h1> <Child></Child> <button type="button" @click='isShow=true'>打开弹窗</button> <Dialog v-if="isShow" @closeDialog='bbb'></Dialog> </div> </template> <script> import Child from './Child.vue' import Dialog from './Dialog.vue' import {ref} from 'vue' export default{ components:{Child,Dialog}, //emits:['closeDialog'], setup(props,context){ let isShow = ref(false) function bbb(val){ isShow.value = val } return {isShow,bbb} } } </script> <style scoped> #son{ border:1px solid red; background-color: gray; line-height: 100px; } </style>
Child.vue组件
<template> <div id="child"> <h1>这里是孙子组件</h1> <button type="button" @click='isShow=true'>打开弹窗</button> <Dialog v-if="isShow" @closeDialog='bbb'></Dialog> </div> </template> <script> import Dialog from './Dialog.vue' import {ref} from 'vue' export default{ components:{Dialog}, //emits:['closeDialog'], setup(){ let isShow = ref(false) function bbb(val){ isShow.value = val } return {isShow,bbb} } } </script> <style scoped> #child{ border:1px solid red; background-color: blue; line-height: 100px; color: white; } </style>
Dialog.vue组件:
<template> <teleport to="#Father"> <div id="dialog"> <div class="dialog"> <h2>这里是弹出层组件</h2> <h3>你好啊哈哈哈</h3> <button type="button" @click="close">点我关闭</button> </div> </div> </teleport> </template> <script> import {ref} from 'vue' export default{ emits:['closeDialog'], setup(props,context){ let isShow = ref(true) function close(){ context.emit('closeDialog',false) } return{isShow,close} } } </script> <style scoped> #dialog{ background-color: rgba(0,0,0,0.5); position: absolute; top: 0; left: 0; right: 0; bottom: 0; } .dialog{ width: 300px; height: 300px; background-color: yellow; margin: auto; margin-top: 200px; } </style>
完成效果:让dialog弹出层 能够显示在teleport的to属性指定的位置。
7.3 Suspense组件
vue3技术简易入门剖析(三)https://developer.aliyun.com/article/1432714