vue3中的响应式原理

阅读: 评论:0

vue3中的响应式原理

vue3中的响应式原理

在讲vue3的响应式之前,先简单说一下vue2的响应式原理。

对象类型:通过Object.defineProperty()对属性的读取丶修改进行拦截(数据劫持)

数组类型:通过重写更新数组的一系列方法来实现拦截。

vue2的响应式会存在下列的问题:

1.新增属性,或者删除属性,界面不会更新

2.直接通过下标修改数组,界面不会自动更新

我们来验证一下:

点击按钮的时候往对象里面添加年龄属性,这时候我们看到浏览器的控制台已经打印出了obj.sex为女。说明我们已经往obj对象上面添加了属性。但是页面上并没有发生改变。原因是vue监测不到。

<template><div><div><h1>姓名:{{obj.name}}</h1><h1>年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1></div><div><button @click="addSex">点击添加性别</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',}}},methods:{addSex(){console.log(this.obj.sex)this.obj.sex = '女'console.log(this.obj.sex)}}}
</script><style scoped></style>

 解决办法:利用$set

代码:

<template><div><div><h1>姓名:{{obj.name}}</h1><h1>年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1></div><div><button @click="addSex">点击添加性别</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',}}},methods:{addSex(){console.log(this.obj.sex)this.$set(this.obj,'sex','女')console.log(this.obj.sex)}}}
</script><style scoped></style>

效果图:

 再次添加一个按钮,点击删除obj下面的name属性。可以看到,页面上面依旧没有发生变化。

代码:

<template><div><div><h1>姓名:{{obj.name}}</h1><h1>年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1></div><div><button @click="addSex">点击添加性别</button></div><br><div><button @click="delAge">点击删除年龄</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',}}},methods:{addSex(){console.log(this.obj.sex)this.$set(this.obj,'sex','女')console.log(this.obj.sex)},delAge(){console.log(this.obj.age)delete this.obj.ageconsole.log(this.obj.age)}}}
</script><style scoped></style>

效果图:

解决办法:利用$delete

代码:

<template><div><div><h1>姓名:{{obj.name}}</h1><h1 v-if="obj.age">年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1></div><div><button @click="addSex">点击添加性别</button></div><br><div><button @click="delAge">点击删除年龄</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',}}},methods:{addSex(){console.log(this.obj.sex)this.$set(this.obj,'sex','女')console.log(this.obj.sex)},delAge(){console.log(this.obj.age)this.$delete(this.obj,'age')console.log(this.obj.age)}}}
</script><style scoped></style>

效果图:

接下来说一下数组。如果要改变数组里面的值。利用索引是没有效果的。页面不会发生改变。

代码:

<template><div><div><h1>姓名:{{obj.name}}</h1><h1 v-if="obj.age">年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1><h1>爱好:{{obj.hobby}}</h1></div><div><button @click="addSex">点击添加性别</button></div><br><div><button @click="delAge">点击删除年龄</button></div><br><div><button @click="updateHobby">点击修改爱好</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',hobby:['抽烟','烫头'],}}},methods:{addSex(){console.log(this.obj.sex)this.$set(this.obj,'sex','女')console.log(this.obj.sex)},delAge(){console.log(this.obj.age)this.$delete(this.obj,'age')console.log(this.obj.age)},updateHobby(){console.log(this.obj.hobby);this.obj.hobby[0] = '打妖怪'console.log(this.obj.hobby);}}}
</script><style scoped></style>

 效果图:

 解决办法有两种:

1.$set()

2.splice()

代码:

<template><div><div><h1>姓名:{{obj.name}}</h1><h1 v-if="obj.age">年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1><h1>爱好:{{obj.hobby}}</h1></div><div><button @click="addSex">点击添加性别</button></div><br><div><button @click="delAge">点击删除年龄</button></div><br><div><button @click="updateHobby">点击修改爱好</button></div></div>
</template><script>export default {data(){return {obj:{name:'孙悟空',age:'99',hobby:['抽烟','烫头'],}}},methods:{addSex(){console.log(this.obj.sex)this.$set(this.obj,'sex','女')console.log(this.obj.sex)},delAge(){console.log(this.obj.age)this.$delete(this.obj,'age')console.log(this.obj.age)},updateHobby(){console.log(this.obj.hobby);// this.obj.hobby[0] = '打妖怪'// this.$set(this.obj.hobby,0,'打妖怪')this.obj.hobby.splice(0,1,'打妖怪')console.log(this.obj.hobby);}}}
</script><style scoped></style>

效果图:

以上就是vue2响应式原理,以及一些问题的解决方案。

接下来我们来说一下vue3的写法

安装最新版本脚手架:

npm install -g @vue/cil

这里简单介绍一下setup.

1.它是vue3.0中的一个新配置,值为一个函数

2.组件里面用到的数据,方法,都配置在setup中。(就是data和methods)

3.setup函数有两种返回值。若返回一个对象则对象中的属性,方法,在模板中都可以直接使用。还有一种,返回一个渲染函数,则可以自定义渲染内容。

代码:

<template><div class="hello"></div>
</template><script>import {h} from  'vue'export default {name: 'HelloWorld',setup() {return ()=> h('h1','我是vue3')},props: {msg: String}}
</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

效果图:

4.使用setup的时候,有以下几点需要注意:

  • 不要与vue2的配置混用。如果混用,在vue2的data,methods中可以访问到setup中的属性,方法。但是在setup里面不能访问到vue里面的配置。如果vue2和vue3的配置有重名,setup里面的配置优先。
  • setup不能是一个async函数,因为返回值不再是return的对象,而是一个promise,模板看不到return对象中的属性。

一样是添加两个按钮,分别是添加性别和删除年龄以及修改爱好。在vue3中直接obj.sex和delete obj.age以及数组的索引就可以对obj这个对象进行添加,修改以及删除,并且更新到页面上。这都得益于reactive。

代码:

<template><div class="hello"><div><h1>姓名:{{obj.name}}</h1><h1 v-if="obj.age">年龄:{{obj.age}}</h1><h1 v-if="obj.sex">性别:{{obj.sex}}</h1></div><div><button @click="addSex">点击添加性别</button></div><br><div><button @click="delAge">点击删除年龄</button></div></div>
</template><script>import {reactive} from  'vue'export default {name: 'HelloWorld',setup() {let obj = reactive({name:'孙悟空',age:99,})function addSex() {obj.sex = '男'console.log('我添加了sex');console.log(obj.sex)}function delAge() {delete obj.ageconsole.log('我删除了年龄');console.log(obj.age)}return {obj,addSex,delAge}},props: {msg: String}}
</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>

效果图:

 

 

vue3的响应式原理

实现原理:

  • 通过Proxy(代理):拦截对象中任意属性的变化,包括属性的读写,属性的添加,属性的删除等。
  • 通过Reflect(反射):对源对象的属性进行操作

先来讲下Proxy的基本用法:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body></body>
<script>//源数据let obj = {name:'孙悟空',age:100}// 模拟vue3中的响应式//Proxy第一个参数是源数据。第二个参数是配置const p = new Proxy(obj,{// 读取get(target,propName){console.log(`读取了p的${propName}属性`)return target[propName]},// 修改,新增set(target,propName,value){console.log(`修改了p的${propName}属性,准备更新界面`)return target[propName] = value},//删除deleteProperty(target,propName){console.log(`删除了p的${propName}属性,准备更新界面`)return delete target[propName]}})
</script>
</html>

 在讲一下Reflect(反射的意思),首先定义一个对象obj,obj下面有a,两个属性。一般我们要读取a属性,会用obj.a来实现。其实还有另外一种方式。就是Reflect。(obj,'a')

 vue3实现响应式原理就是利用了Reflect

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body></body>
<script>//源数据let obj = {name:'孙悟空',age:100}// 模拟vue3中的响应式//Proxy第一个参数是源数据。第二个参数是配置const p = new Proxy(obj,{// 读取get(target,propName){console.log(`读取了p的${propName}属性`)(target,propName)},// 修改,新增set(target,propName,value){console.log(`修改了p的${propName}属性,准备更新界面`)return Reflect.set(target,propName,value)},//删除deleteProperty(target,propName){console.log(`删除了p的${propName}属性,准备更新界面`)return Reflect.deleteProperty(target,propName)}})
</script>
</html>

总结一下,vue2实现原理主要依靠Object.defineProperty。而vue3则是引用了Proxy来做代理。

本文发布于:2024-02-04 18:37:07,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170713832358441.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:原理
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23