再说vue响应式数据

news2024/11/27 5:32:01
  • 请说一下你对响应式数据的理解
    • 如何实现响应式数据据
      • 对象
        • vue2 响应式核心代码
      • 数组
    • vue2 处理缺陷
    • Vue3则采用 proxy
      - vue3 响应式核心代码

请说一下你对响应式数据的理解

如何实现响应式数据据

数组和对象类型当值变化时如何劫持到。

对象

对象内部通过defineReactive方法,使用object.defineProperty将属性进行劫持(只会劫持已经存在的属性)

多层对象是通过递归来实现劫持。

vue2 响应式核心代码
let obj = {
    name:'jw' , 
    age:30,
    n: {
        num: 000
    }
};

// 定义相应式函数
function defineReactive(target,key,value){
    // 判断检测对象中是否有嵌套对象
    observer(value)

    object.defineProperty(target, key,{
        get(){
            return value
        },
        set(newValue){
            if(value !== newValue){
                value = newValue;
                // 判断心智是否有是对象
                observer(newValue)
            } 
        } 
    }) 
}

// 定义观察函数
function observer(data){
    // 如果不是对象或者数据为空,直接返回
    if(typeof data !== "object" || typeof data == null){
        return data
    }

    // 循环执行第一层数据
    for(let key in data){
        defineReactive(data, key , data[key])
    }
}

observer(obj) 
数组

数组则是通过重写数组方法来实现。

Vue2中数组的响应式更新没有使用Object.defineProperty,而是采用了一种特殊的技术。

使用Object.defineProperty可以定义对象属性的获取(get)和设置(set)方法,从而实现对属性的拦截和控制。然而,对于数组来说,它只能拦截并控制数组对象本身的变化,而不能直接拦截数组元素的变化。

因此,如果使用Object.defineProperty来实现数组的响应式,需要对数组的每一个索引进行拦截,监听其变化并触发更新,这样会带来很大的性能开销和复杂度。

为了解决这个问题,Vue2采用了数组的变异方法(mutation method)来触发响应式更新。

这些变异方法,如pushpopshiftunshiftsplicesortreverse,在执行时会被重写,以便在修改数组时同时触发响应式更新。

以下几个数组方法会被重写以实现响应式:

  1. push():向数组末尾添加一个或多个元素。
  2. pop():删除并返回数组的最后一个元素。
  3. shift():删除并返回数组的第一个元素。
  4. unshift():向数组的开头添加一个或多个元素。
  5. splice():从指定位置插入、删除或替换元素。
  6. sort():对数组进行排序。
  7. reverse():颠倒数组中元素的顺序。

当调用这些方法时,Vue2会拦截它们的调用,并执行以下操作:

  1. 在Vue初始化阶段: Vue2会对data选项中的数组进行遍历,并重写数组的变异方法。
  2. 更新依赖:Vue2会更新依赖于该数组的视图或计算属性。
  3. 触发响应:Vue2会通知相关组件进行重新渲染。

通过重写数组变异方法,Vue2能够在数组被修改时,及时地通知相关组件进行更新,从而实现数组的响应式。

需要注意的是,这种方式只能拦截变异方法的调用,而无法拦截直接通过索引修改数组元素的方式。如果需要修改数组中的某个元素,并触发响应式更新,需要使用Vue提供的特定方法,比如$setVue.set方法。

var vm = new Vue({
  data: {
    list: ['apple', 'banana', 'orange']
  }
})

// 修改数组,触发响应式更新
vm.list.push('grape');
// 视图会自动更新,list中的元素会显示为['apple', 'banana', 'orange', 'grape']

// 直接通过索引修改数组元素,不会触发响应式更新
vm.list[0] = 'watermelon';
// 视图不会自动更新,list中的元素仍然显示为['apple', 'banana', 'orange', 'grape']

// 使用Vue.set方法修改数组元素,触发响应式更新
Vue.set(vm.list, 0, 'watermelon');
// 视图会自动更新,list中的元素会显示为['watermelon', 'banana', 'orange', 'grape']

更多详细内容,请微信搜索“前端爱好者戳我 查看

vue2 处理缺陷

  • 在Vue2 的时候使用 defineProperty 来进行数据的劫持,需要对属性进行重写添加getter及setter 性能差
  • 当新增属性和删除属性时无法监控变化。需要通过$set、 $delete实现
  • 数组不采用 defineproperty 来进行劫持 (浪费性能,对所有索引进行劫持会造成性能浪费)需要对数组单独进行处理
  • 对于 ES6 中新产生的 Map、Set 这些数据结构不支持

Vue3则采用 proxy

Vue2 不采用 proxy,因为浏览器兼容

vue3 响应式核心代码
let obj = {
    name:'jw' , 
    age:30,
    n: {
        num: 000
    }
};

let handler = {
    get(target, key) { 
        // 在访问属性时进行依赖收集
        let temp = target[key]
        
        // 如果值是对象,则递归监听
        if(typeof temp=== "object"){
            return new Proxy(temp, handler)
        } 

        // 否则直接返回
        return temp 
    },
    set(target, key, value) { 
        // 在更新属性时触发依赖更新
        target[key] = value
    }, 
}

function reactive(target) {
  return new Proxy(target, handler);
} 

const proxy = reactive(obj)

reactive函数接受一个普通对象作为参数,并返回一个经过代理的响应式对象。

这个代理对象利用Proxy的get和set方法来拦截属性的读取和修改操作,并触发相应的依赖收集和更新。

复杂实例

在Vue 3中,可以使用Proxy对象来实现响应式实例。

Proxy是ES6引入的新特性,它可以拦截并自定义对象的操作。

下面是一个使用Proxy实现响应式实例的示例:

function reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      // 在访问属性时进行依赖收集
      track(target, key);
      return Reflect.get(target, key);
    },
    set(target, key, value) {
      // 在更新属性时触发依赖更新
      const oldValue = target[key];
      const result = Reflect.set(target, key, value);
      if (oldValue !== value) {
        trigger(target, key);
      }
      return result;
    },
    deleteProperty(target, key) {
      // 在删除属性时触发依赖更新
      const hasKey = Object.prototype.hasOwnProperty.call(target, key);
      const result = Reflect.deleteProperty(target, key);
      if (hasKey) {
        trigger(target, key);
      }
      return result;
    }
  });
}

在上述代码中,reactive函数接受一个普通对象作为参数,并返回一个经过代理的响应式对象。这个代理对象利用Proxygetset方法来拦截属性的读取和修改操作,并触发相应的依赖收集和更新。

需要注意的是,上述代码中的tracktrigger函数是为了配合依赖收集和更新使用的,它们在实际应用中需要根据具体场景进行实现。

使用上述的reactive函数,我们可以将一个普通对象转换成响应式实例。例如:

const user = reactive({
  name: 'Alice',
  age: 25
});

console.log(user.name); // 输出:'Alice'

user.age = 26; // 触发依赖更新

通过reactive函数创建的user对象就是一个响应式实例了。当访问user对象的属性时,会自动进行依赖收集;当更新属性的值时,会触发相应的依赖更新。这样就实现了Vue 3中的响应式机制。

由于Proxy是ES6的新特性,不支持的浏览器可能无法正常运行上述代码。

在实际开发中,可以使用Babel等工具进行转换,以兼容不同的浏览器环境。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1587448.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql重启失败

服务器重启了一下,然后启动后发现mysql自动启动没有生效,于是手动通过systemctl启动mysqld,然后就报错:Starting MySQL...........The server quit without updating P[FAILED](/data/mysql/iz2zebvmy1qv3fao9c5riuz.pid). 根据配置my.cnf文…

Hello 算法10:搜索

https://www.hello-algo.com/chapter_searching/binary_search/ 二分查找法 给定一个长度为 n的数组 nums ,元素按从小到大的顺序排列,数组不包含重复元素。请查找并返回元素 target 在该数组中的索引。若数组不包含该元素,则返回 -1 。 # 首…

Ubuntu下配置Android NDK环境

Android-NDK的下载 下载Android-NDK wget -c http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin 执行bin文件(即解压) ./android-ndk-r10c-linux-x86_64.bin Android-NDK的配置 要想使用Android-NDK,还需要进行环境变量…

程序猿之路

我接触计算机算对自己来说是比较晚的了,上初中的时候就有微机课,但是在那个小县城,上课也只是3个人共用一个电脑,我初中整个过程只会开关机,哈哈,虽然学过word,但是无奈,我插不上手呀…

Qlik Sense :use Peek function to Group by and Get Rowno

Question Row number based on groups of data Calculate row number for groups 有时候我们需要基于分组来对数据进行内部排序,例如一个iddate,把不同的属性的记录标记为123,又或者把重复记录标记出来 Solved: Calculate row number for…

如何实现word一键注音?给一篇word文章快速注音的方法

在日常生活和工作中,我们经常需要处理各种文档,其中不乏包含大量生僻字或需要标注拼音的文本。手动为每一个字添加拼音不仅效率低下,而且容易出错。那么,有没有一种方法可以实现Word文档的一键注音呢?本文将为大家详细…

基于SpringBoot和Vue的企业客户管理系统

今天要和大家聊的是基于SpringBoot和Vue的企业客户管理系统 !!! 有需要的小伙伴可以通过文章末尾名片咨询我哦!!! 💕💕作者:李同学 💕💕个人简介…

IntelliJ IDEA(WebStorm、PyCharm、DataGrip等)设置中英文等宽字体,英文为中文的一半(包括标点符号)

1.设置前(idea默认字体为 JetBrains Mono) 2.设置后(楷体)

Oracle 19c补丁升级(Windows)

文章目录 一、打补丁前备份检查1、补丁包获取2、备份数据包以及数据库软件3、检查OPatch版本 二、补丁升级1、更新OPatch2、关闭监听以及服务3、补丁升级过程4、启动监听以及服务 三、数据库补丁应用 一、打补丁前备份检查 1、补丁包获取 补丁包: 百度网盘链接&am…

贪心算法:排列算式

题目描述 给出n数字,对于这些数字是否存在一种计算顺序,使得计算过程中数字不会超过3也不会小于0? 输入描述: 首行给出一个正整数t,(1≤t≤1000)代表测试数据组数每组测试数据第一行一个正整数n,(1≤n≤500)第二行包含n个以空格分隔的数字…

CLIPSeg如果报“目标计算机积极拒绝,无法连接。”怎么办?

CLIPSeg这个插件在使用的时候,偶尔会遇到以下报错: Error occurred when executing CLIPSeg: (MaxRetryError("HTTPSConnectionPool(hosthuggingface.co, port443): Max retries exceeded with url: /CIDAS/clipseg-rd64-refined/resolve/main/toke…

练习题(2024/4/11)

1每日温度 给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。 示例 1: 输入…

使用 vue3-sfc-loader 加载远程Vue文件, 在运行时动态加载 .vue 文件。无需 Node.js 环境,无需 (webpack) 构建步骤

加载远程Vue文件 vue3-sfc-loader vue3-sfc-loader ,它是Vue3/Vue2 单文件组件加载器。 在运行时从 html/js 动态加载 .vue 文件。无需 Node.js 环境,无需 (webpack) 构建步骤。 主要特征 支持 Vue 3 和 Vue 2(参见dist/)仅需…

订单中台架构:打造高效订单管理系统的关键

在现代商业环境下,订单管理对于企业来说是至关重要的一环。然而,随着业务规模的扩大和多渠道销售的普及,传统的订单管理方式往往面临着诸多挑战,如订单流程复杂、信息孤岛、数据不一致等问题。为了应对这些挑战并抓住订单管理的机…

Redis 的数据结构和内部编码

Redis的 5 种数据类型 Redis 底层在实现上述数据结构的时候,会在源码层面,针对上述实现进行 特定的优化 ,来达到节省时间/节省空间效果 特定的优化:内部的具体实现的数据结构,在特定场景下,不是其对应的标准…

【HTML】制作一个简单的线性动画

目录 前言 HTML部分 CSS部分 JS部分 效果图 总结 前言 无需多言,本文将详细介绍一段HTML代码,具体内容如下: 开始 首先新建文件夹,创建一个文本文档,两个文件夹,其中HTML的文件名改为[index.html]&am…

TFT显示屏驱动

REVIEW 已经学习过VGA 时序与实现-CSDN博客 VGA 多分辨率-CSDN博客 今天就来让TFT屏显示一下 小梅哥视频:24 RGB TFT显示屏原理与驱动实现_哔哩哔哩_bilibili 1. 设置显示屏参数与时钟 注意到VGA_parameter.v中,不懂得分辨率对应于不同的频率&#xff…

Vue3学习04 组件通信

Vue3学习04 组件通信 组件通信props 父 ↔ 子自定义事件 子 > 父mitt 任意组件间通信v-model 父↔子$attrs 祖↔孙$refs、$parent案例的完整代码ref注意点 provide、inject 祖↔孙piniaslot① 默认插槽② 具名插槽③ 作用域插槽 组件通信 Vue3组件通信和Vue2的区别&#xf…

K8S之Controller

我们在回顾下pod的启动流程: 用户通过kubectl,向api-server 发起请求api-server接受请求,并将数据写入etcdkube-scheduler通过watch检测到未绑定node 的pod,调度pod到某一node上,并通知给api-server,api-se…

Centos7 k8s 集群 - Rook Ceph 安装

环境准备 基础环境 系统名称操作系统CPU内存硬盘Kubernete 版本Docker版本IPmasterCentos74c4gsdb 20G1.17.023.0.1192.168.1.128node01Centos74c4gsdb 20G1.17.023.0.1192.168.1.129node02Centos74c4gsdb 20G1.17.023.0.1192.168.1.130node03Centos74c4gsdb 20G1.17.023.0.1…