Vue Vue3的响应式

news/2024/7/10 3:02:47 标签: vue

vue2x__0">回顾 vue2.x 的响应式

实现原理:
。对象类型:通过object.defineProperty()对属性的读取、修改进行拦截(数据劫持)
。数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)

Object.defineProperty(data,'count ",{
	get(){},
	set(){}
})

存在问题:
。新增属性、删除属性,界面不会更新
。直接通过下标修改数组,界面不会自动更新

但是 vue2 给了解决方法,我们看以下代码:

<template>
  <div>
    <h2>我是vue2写的效果</h2>
    <h4 v-show="person.name">姓名:{{person.name}}</h4>
    <h4>年龄:{{person.age}}</h4>
    <h4 v-show="person.sex">性别:{{person.sex}}</h4>
    <h4>爱好:{{person.hobby}}</h4>
    <button @click="addSex">添加sex属性</button>
    <button @click="deleteName">删除name属性</button>
    <button @click="changeHobby">修改爱好</button>
  </div>
</template>

<script>
import Vue from 'vue'
export default {
  name: 'App',
  data(){
    return{
      person:{
        name:'张三',
        age:18,
        hobby:['学习','吃饭']
      }
    }
  },
  methods:{
    addSex(){
      //这样直接加是不行的
      //this.person.sex = '男'
      this.$set(this.person,"sex",'男')
      //Vue.set(this.person,"sex",'男')
    },
    deleteName(){
      //这样直接加是不行的
      //delete this.person.name
      //this.$delete(this.person,'name')
      Vue.delete(this.person,"name")
    },
    changeHobby(){
      //这样直接加是不行的
      //this.person.hobby[0] = '逛街'
      //可以这样
      this.$set(this.person.hobby,0,'逛街')
      //或
      //this.person.hobby.splice(0,1,"逛街")
    },
  }
}
</script>

在这里插入图片描述
我们可以用 js 模拟 vue2 的响应式

<script>
        //源数据
        let person = {
            name:"张三",
            age:18
        }
        let p = {}
        //模拟vue2实现响应式
        Object.defineProperty(p,"name",{
        	configurable:true,
            get() {//有人读取name时调用
                return person.name
            },
            set(v) {
                person.name = v
                console.log("有人修改了name属性,我发现了,我要去更新界面");
            }
        })
        Object.defineProperty(p,"age",{
            get() {//有人读取age时调用
                return person.age
            },
            set(v) {
                person.age = v
                console.log("有人修改了age属性,我发现了,我要去更新界面");
            }
        })
    </script>

先输出 person,然后看下 p
当修改 name 或 age 时会检测到
在这里插入图片描述
它的问题是,如果增加一个 sex 属性,vue 不会检测到,虽然增加了 sex 属性,但它不像 name 和 age 有 getter 和 setter,不是响应式的
在这里插入图片描述
同样,当删除 name 属性时也监测不到
在这里插入图片描述

vue3_111">vue3的响应式

<template>
  <h1>一个人的信息</h1>
  <h3 v-show="person.name">姓名:{{ person.name }}</h3>
  <h3>年龄:{{ person.age }}</h3>
  <h3 v-show="person.sex">性别:{{ person.sex }}</h3>
	......
  <button @click="changeInfo">修改人的信息</button>
  <button @click="addSex">添加一个sex属性</button>
  <button @click="deleteName">删除一个name属性</button>
</template>

<script>
import {reactive} from 'vue'

export default {
  name: 'App',
  setup() {
	......

    function changeInfo() {
      ......
      person.hobby[0] = '学习'
    }
    
    function addSex() {
      person.sex = "男"
    }

    function deleteName() {
      delete person.name
    }

    return {
      ......
      addSex,
      deleteName
    }
  }
}
</script>

在这里插入图片描述
模拟 vue3 中的响应式

    <script>
        //源数据
        let person = {
            name:"张三",
            age:18
        }
        const p = new Proxy(person,{
            //有人读取p的某个属性时调用
            get(target, p, receiver) {
                console.log(`有人读取了p身上的${p}属性`);
                //return target[p]
                return Reflect.get(target,p)
            },
            //有人修改、增加p的某个属性时调用
            set(target, p, value, receiver) {
                console.log(`有人修改了p身上的${p},我要去更新界面了`);
                //target[p] = value
                Reflect.set(target,p,value)
            },
            //有人删除p的某个属性时调用
            deleteProperty(target, p) {
                console.log(`有人删除了p身上的${p},我要去更新界面了`);
                //return delete target[p]
                return Reflect.deleteProperty(target,p)
            }
        })
    </script>

在这里插入图片描述
在这里插入图片描述

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

MDN文档中描述的 Proxy 与 Reflect
Proxy
Reflect

new Proxy(data,{
	//拦截读取属性值
	get (target, prop){
		return Reflect.get(target,prop)
	},
	//拦截设置属性值或添加新属性
	set (target,prop, value) {
		return Reflect.set(target,prop, value)
	},
	//拦截删除属性
	deleteProperty (target,prop) {
		return Reflect.deleteProperty(target,prop)
	}
})
proxy.name = "tom"

http://www.niftyadmin.cn/n/1816689.html

相关文章

jQuery身份证验证插件

jQuery身份证验证插件 /*!* jQuery isIDCard Plugin v1.0.0* http://www.cnblogs.com/cssfirefly/p/5629561.html** Copyright 2016 link* Released under the MIT license*/ (function(factory) {if (typeof define function && define.amd) {// AMDdefine([jquery],…

Vue Vue3中的 computed、watch、watchEffect

文章目录computedwatchwatchEffectcomputed <template>姓&#xff1a;<input v-model"person.firstName"><br/><br/>名&#xff1a;<input v-model"person.lastName"><br/><br/><span>全名&#xff1a;{…

jsp博客

1.一个国内的博客系统&#xff0c;基于java开发的&#xff0c;blogmethods 转载于:https://www.cnblogs.com/291099657/archive/2008/08/02/1258866.html

form表单无刷新提交文件(iframe)

先看一段代码&#xff08;PHP例子&#xff09; 1、表单代码&#xff08;form.html&#xff09;&#xff1a; <iframe name"testIframeName" style"display:none;"></iframe> <form target"testIframeName" method"post&qu…

Vue Vue3的生命周期

文章目录配置项的形式使用组合式API形式使用配置项的形式使用 用一个例子来学习 vue3 的生命周期钩子 App.vue 中引入 Demo&#xff0c;并添加一个按钮来隐藏或显示 <template><div><Demo v-if"isShow"/><br><button click"isSh…

在asp.net中生成html文件代码

在asp.net中生成html文件代码如下&#xff1a; public static bool CreatHtmlPage(string[] strNewsHtml, string[] strOldHtml, string strModeFilePath, string strPageFilePath) { bool Flage false; StreamReader ReaderFile null; …

js生成有缩进的表格

项目中用到用了两天时间想到的&#xff0c;记录下来&#xff0c;如有更好的方法&#xff0c;留言给我&#xff0c;谢谢&#xff01; js做如下表格&#xff1a; json [{"id":302,"serviceId":15,"name":"data","type":"…

Vue 自定义hook函数

文章目录定义使用封装发ajax请求的hook函数&#xff08;ts版本&#xff09;定义 什么是hook? 。本质是一个函数&#xff0c;把 setup 函数中使用的 Composition API &#xff08;组合API&#xff09;进行了封装 。类似于 vue2.x 中的 mixin 自定义 hook 的优势 。复用代码&a…