当前位置:   article > 正文

vue3中的响应式原理_vue3响应式原理

vue3响应式原理

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

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

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

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

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

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

我们来验证一下:

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

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1>年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. </div>
  8. <div>
  9. <button @click="addSex">点击添加性别</button>
  10. </div>
  11. </div>
  12. </template>
  13. <script>
  14. export default {
  15. data(){
  16. return {
  17. obj:{
  18. name:'孙悟空',
  19. age:'99',
  20. }
  21. }
  22. },
  23. methods:{
  24. addSex(){
  25. console.log(this.obj.sex)
  26. this.obj.sex = '女'
  27. console.log(this.obj.sex)
  28. }
  29. }
  30. }
  31. </script>
  32. <style scoped>
  33. </style>

 解决办法:利用$set

代码:

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1>年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. </div>
  8. <div>
  9. <button @click="addSex">点击添加性别</button>
  10. </div>
  11. </div>
  12. </template>
  13. <script>
  14. export default {
  15. data(){
  16. return {
  17. obj:{
  18. name:'孙悟空',
  19. age:'99',
  20. }
  21. }
  22. },
  23. methods:{
  24. addSex(){
  25. console.log(this.obj.sex)
  26. this.$set(this.obj,'sex','女')
  27. console.log(this.obj.sex)
  28. }
  29. }
  30. }
  31. </script>
  32. <style scoped>
  33. </style>

效果图:

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

代码:

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1>年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. </div>
  8. <div>
  9. <button @click="addSex">点击添加性别</button>
  10. </div>
  11. <br>
  12. <div>
  13. <button @click="delAge">点击删除年龄</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. data(){
  20. return {
  21. obj:{
  22. name:'孙悟空',
  23. age:'99',
  24. }
  25. }
  26. },
  27. methods:{
  28. addSex(){
  29. console.log(this.obj.sex)
  30. this.$set(this.obj,'sex','女')
  31. console.log(this.obj.sex)
  32. },
  33. delAge(){
  34. console.log(this.obj.age)
  35. delete this.obj.age
  36. console.log(this.obj.age)
  37. }
  38. }
  39. }
  40. </script>
  41. <style scoped>
  42. </style>

效果图:

解决办法:利用$delete

代码:

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. </div>
  8. <div>
  9. <button @click="addSex">点击添加性别</button>
  10. </div>
  11. <br>
  12. <div>
  13. <button @click="delAge">点击删除年龄</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. data(){
  20. return {
  21. obj:{
  22. name:'孙悟空',
  23. age:'99',
  24. }
  25. }
  26. },
  27. methods:{
  28. addSex(){
  29. console.log(this.obj.sex)
  30. this.$set(this.obj,'sex','女')
  31. console.log(this.obj.sex)
  32. },
  33. delAge(){
  34. console.log(this.obj.age)
  35. this.$delete(this.obj,'age')
  36. console.log(this.obj.age)
  37. }
  38. }
  39. }
  40. </script>
  41. <style scoped>
  42. </style>

效果图:

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

代码:

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. <h1>爱好:{{obj.hobby}}</h1>
  8. </div>
  9. <div>
  10. <button @click="addSex">点击添加性别</button>
  11. </div>
  12. <br>
  13. <div>
  14. <button @click="delAge">点击删除年龄</button>
  15. </div>
  16. <br>
  17. <div>
  18. <button @click="updateHobby">点击修改爱好</button>
  19. </div>
  20. </div>
  21. </template>
  22. <script>
  23. export default {
  24. data(){
  25. return {
  26. obj:{
  27. name:'孙悟空',
  28. age:'99',
  29. hobby:['抽烟','烫头'],
  30. }
  31. }
  32. },
  33. methods:{
  34. addSex(){
  35. console.log(this.obj.sex)
  36. this.$set(this.obj,'sex','女')
  37. console.log(this.obj.sex)
  38. },
  39. delAge(){
  40. console.log(this.obj.age)
  41. this.$delete(this.obj,'age')
  42. console.log(this.obj.age)
  43. },
  44. updateHobby(){
  45. console.log(this.obj.hobby);
  46. this.obj.hobby[0] = '打妖怪'
  47. console.log(this.obj.hobby);
  48. }
  49. }
  50. }
  51. </script>
  52. <style scoped>
  53. </style>

 效果图:

 解决办法有两种:

1.$set()

2.splice()

代码:

  1. <template>
  2. <div>
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. <h1>爱好:{{obj.hobby}}</h1>
  8. </div>
  9. <div>
  10. <button @click="addSex">点击添加性别</button>
  11. </div>
  12. <br>
  13. <div>
  14. <button @click="delAge">点击删除年龄</button>
  15. </div>
  16. <br>
  17. <div>
  18. <button @click="updateHobby">点击修改爱好</button>
  19. </div>
  20. </div>
  21. </template>
  22. <script>
  23. export default {
  24. data(){
  25. return {
  26. obj:{
  27. name:'孙悟空',
  28. age:'99',
  29. hobby:['抽烟','烫头'],
  30. }
  31. }
  32. },
  33. methods:{
  34. addSex(){
  35. console.log(this.obj.sex)
  36. this.$set(this.obj,'sex','女')
  37. console.log(this.obj.sex)
  38. },
  39. delAge(){
  40. console.log(this.obj.age)
  41. this.$delete(this.obj,'age')
  42. console.log(this.obj.age)
  43. },
  44. updateHobby(){
  45. console.log(this.obj.hobby);
  46. // this.obj.hobby[0] = '打妖怪'
  47. // this.$set(this.obj.hobby,0,'打妖怪')
  48. this.obj.hobby.splice(0,1,'打妖怪')
  49. console.log(this.obj.hobby);
  50. }
  51. }
  52. }
  53. </script>
  54. <style scoped>
  55. </style>

效果图:

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

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

安装最新版本脚手架:

npm install -g @vue/cil

这里简单介绍一下setup.

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

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

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

代码:

  1. <template>
  2. <div class="hello">
  3. </div>
  4. </template>
  5. <script>
  6. import {h} from 'vue'
  7. export default {
  8. name: 'HelloWorld',
  9. setup() {
  10. return ()=> h('h1','我是vue3')
  11. },
  12. props: {
  13. msg: String
  14. }
  15. }
  16. </script>
  17. <!-- Add "scoped" attribute to limit CSS to this component only -->
  18. <style scoped>
  19. </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。

代码:

  1. <template>
  2. <div class="hello">
  3. <div>
  4. <h1>姓名:{{obj.name}}</h1>
  5. <h1 v-if="obj.age">年龄:{{obj.age}}</h1>
  6. <h1 v-if="obj.sex">性别:{{obj.sex}}</h1>
  7. </div>
  8. <div>
  9. <button @click="addSex">点击添加性别</button>
  10. </div>
  11. <br>
  12. <div>
  13. <button @click="delAge">点击删除年龄</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. import {reactive} from 'vue'
  19. export default {
  20. name: 'HelloWorld',
  21. setup() {
  22. let obj = reactive({
  23. name:'孙悟空',
  24. age:99,
  25. })
  26. function addSex() {
  27. obj.sex = '男'
  28. console.log('我添加了sex');
  29. console.log(obj.sex)
  30. }
  31. function delAge() {
  32. delete obj.age
  33. console.log('我删除了年龄');
  34. console.log(obj.age)
  35. }
  36. return {
  37. obj,
  38. addSex,
  39. delAge
  40. }
  41. },
  42. props: {
  43. msg: String
  44. }
  45. }
  46. </script>
  47. <!-- Add "scoped" attribute to limit CSS to this component only -->
  48. <style scoped>
  49. </style>

效果图:

 

 

vue3的响应式原理

实现原理:

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

先来讲下Proxy的基本用法:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script>
  10. //源数据
  11. let obj = {
  12. name:'孙悟空',
  13. age:100
  14. }
  15. // 模拟vue3中的响应式
  16. //Proxy第一个参数是源数据。第二个参数是配置
  17. const p = new Proxy(obj,{
  18. // 读取
  19. get(target,propName){
  20. console.log(`读取了p的${propName}属性`)
  21. return target[propName]
  22. },
  23. // 修改,新增
  24. set(target,propName,value){
  25. console.log(`修改了p的${propName}属性,准备更新界面`)
  26. return target[propName] = value
  27. },
  28. //删除
  29. deleteProperty(target,propName){
  30. console.log(`删除了p的${propName}属性,准备更新界面`)
  31. return delete target[propName]
  32. }
  33. })
  34. </script>
  35. </html>

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

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

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. </head>
  7. <body>
  8. </body>
  9. <script>
  10. //源数据
  11. let obj = {
  12. name:'孙悟空',
  13. age:100
  14. }
  15. // 模拟vue3中的响应式
  16. //Proxy第一个参数是源数据。第二个参数是配置
  17. const p = new Proxy(obj,{
  18. // 读取
  19. get(target,propName){
  20. console.log(`读取了p的${propName}属性`)
  21. return Reflect.get(target,propName)
  22. },
  23. // 修改,新增
  24. set(target,propName,value){
  25. console.log(`修改了p的${propName}属性,准备更新界面`)
  26. return Reflect.set(target,propName,value)
  27. },
  28. //删除
  29. deleteProperty(target,propName){
  30. console.log(`删除了p的${propName}属性,准备更新界面`)
  31. return Reflect.deleteProperty(target,propName)
  32. }
  33. })
  34. </script>
  35. </html>

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/283907
推荐阅读
相关标签
  

闽ICP备14008679号