首页技术栈归档照片墙音乐日记随想收藏夹友链留言关于

vue中的响应式原理3.x

写作时间:2026-07-08

vue中的响应式原理3.x

回顾vue2.x的响应式

实现原理:

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

数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)

0bject.defineProperty(data,'count', {
      get(){},
      set (){}
})    

存在问题:

新增属性、删除属性,界面不会更新。

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

App.vue

<template>
  <div id="app">
    <!--v-show="person.name" 如果名字不存在不展示-->
    <h1 v-show="person.name">姓名:{{person.name}}</h1>
    <h1 v-show="person.age">年龄:{{person.age}}</h1>
    <h1>爱好:{{person.hobby}}</h1>
    <button @click="deleteName">删除名称</button>
     <button @click="updaeAge">修改年龄</button>
    <button @click="updaeHobby">修改爱好</button>
  </div>
</template>

<script>

import Vue from "vue"
export default {
  name: 'App',
  data(){
    return{
      person:{
       name:"张三",
      age:13,
      hobby:["玩游戏","看电视"]
      }
    }
  },
  methods:{
    updaeAge(){
        //Vue.set(this.person,"age",100)
        this.$set(this.person,"age",100)
    },
    deleteName(){
       // this.$delete(this.person,"name")
        Vue.delete(this.person,"name")
    },
    updaeHobby(){
      //this.person.hobby.splice(0,1,"看电影")
      //this.$set(this.person.hobby,0,"看电影")
      Vue.set(this.person.hobby,0,"看电影")
    }
  }
}
</script>

<style>

</style>

vue3.x响应式

实现原理:

通过Proxy(代理)∶拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等

通过Reflect(反射):对被代理对象的属性进行操作。

MDN文档中描述的Proxy与Reflect:

.Proxy: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

. Reflect: https://developer.mozilla.org/zh-CN/docs/WebJavaScript/Reference/Global

App.vue

<template>
    <h1>信息</h1>
    <h1 v-show="person.name">姓名{{person.name}}</h1>
    <h1>年龄:{{person.age}}</h1>
    <h1 v-show="person.sex">性别:{{person.sex}}</h1>
    <h1>工作类型:{{person.job.type}}</h1>
    <h1>工作薪水:{{person.job.salary}}</h1>
    <h1>爱好:{{person.hobby}}</h1>
    <button @click="geng()">更新数据</button>
     <button @click="updateAge()">修改性别</button>
      <button @click="deleteName()">删除名字</button>
</template>
<script>
 //引用ref和reactive
 import {reactive} from "vue"
export default {
  name: 'App',
  setup(){
    //一个大的对象
    let person=reactive({
      name:"张三",
      age:18,
      sex:"男",
      job:{
      type:"前端工程师",
      salary:"100k"
    },
    //数组类型通过reactive进行赋值
    hobby:["抽烟","喝酒","吃槟榔"]
    })
    //点击时更新数据
     function geng(){
       person.name="李四"
       person.age=20
       //通过reactive进行更新值
       person.job.type="UI设计师"
       person.job.salary="200K"
       //更新数组的值
       person.hobby[0]="学习"
     }
     //修改年龄
      function updateAge(){
           person.sex="女"
      }
      //删除名字
      function deleteName(){
           delete person.name
      }
    return{
      person,
      geng,
      updateAge,
      deleteName
    }
  }
}
</script>

vue3.x reactive对比ref

从定义数据角度对比:

ref用来定义:基本类型数据。

reactive用来定义:对象(或数组)类型数据。

备注: ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象。

从原理角度对比:

ref通过object.defineProperty()的get与set来实现响应式(数据劫持)。

reactive通过使用Proxy来实现响应式(数据劫持)﹐并通过Reflect操作源对象内部的数据。

从使用角度对比:

ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value .

reactive定义的数据:操作数据与读取数据:均不需要.value )。

vue3.x setup两个注意点

setup执行的时机

在beforeCreate之前执行一次,this是undefined

setup的参数

props:值为对象,包含:组件外部传递过来,且组件内部声明接收了的属性

context: 上下文对象

attrs:值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于this.$attrs

slots:收到的插槽内容,相当于this.$slots

emit:分发自定义事件的函数,相当于this.$emit

App.vue

<template>
   <Dome @hello="showHelloMsg"  msg="你好" school="张三">
     <template v-slot:que>
            <span>张三</span>
     </template>
   </Dome>
</template>
<script>
import Dome from './components/Dome.vue'
export default {
  name: 'App',
  components: { Dome },
  setup(){
    function showHelloMsg(value){
      alert('你出发了hello事件,接收到的参数是:'+value+'')
    }
    return{
       showHelloMsg
    }

  }
}
</script>

Dome.vue

<template>
    <h1>信息</h1>
    <h1 v-show="person.name">姓名{{person.name}}</h1>
    <h1>年龄:{{person.age}}</h1>
     <button @click="test()">测试一下Demo组件的Hello事件</button>
</template>
<script>
 import {reactive} from "vue"
export default {
  name: 'Dome',
  //在app配置的msg和school要在者配置
  props:["msg","school"],
  //在app配置的点击事件hello
  emits:["hello"],
  // beforeCreate(){
  //    console.log("-----beforeCreate-----")
  // },
  setup(props,context){
    //  console.log("--setup--",props)
     //console.log("--context--",context.attrs)//详单与vue2中的$attrs
     //console.log("--context--",emit)//触发自定义事件
     console.log("--setup--",context.slots)//插槽
    //数据
    let person=reactive({
      name:"张三",
      age:18,
    })
    //方法
    function test(){
      //触发hello事件
      context.emit("hello",666)
    }
    return{
      person,
      test
    }
  }
}
</script>
avatar

yuanyourdomain

写代码,做研究,记录生活。

RECOMMENDED

MyBatis 动态 SQL

2026-07-08

Nginx 基础入门

2026-07-08

Maven 多模块与私服

2026-07-08