0

0

一文深入剖析Vue3中的响应式机制

青灯夜游

青灯夜游

发布时间:2022-09-19 20:13:14

|

2162人浏览过

|

来源于掘金社区

转载

一文深入剖析Vue3中的响应式机制

今天我带你深入了解一下 Vue 3 的响应式机制,相信学完今天的内容,你会对响应式机制有更深地体会;我还会结合代码示例,帮你掌握响应式机制的进阶用法,让我们正式开始学习吧!【相关推荐:vuejs视频教程

什么是响应式

响应式一直都是 Vue 的特色功能之一;与之相比,JavaScript 里面的变量,是没有响应式这个概念的;你在学习 JavaScript 的时候首先被灌输的概念,就是代码是自上而下执行的;

我们看下面的代码,代码在执行后,打印输出的两次 double 的结果也都是 2;即使 我们修改了代码中 count 的值后,double 的值也不会有任何改变

let count = 1
let double = count * 2
count = 2

double 的值是根据 count 的值乘以二计算而得到的,如果现在我们想让 doube 能够跟着 count 的变化而变化,那么我们就需要在每次 count 的值修改后,重新计算 double

立即学习前端免费学习笔记(深入)”;

 比如,在下面的代码,我们先把计算 doube 的逻辑封装成函数,然后在修改完 count 之 后,再执行一遍,你就会得到最新的 double 值

let count = 1
// 计算过程封装成函数
let getDouble = n=>n*2 //箭头函数
let double = getDouble(count)
count = 2
// 重新计算double ,这里我们不能自动执行对double的计算
double = getDouble(count)

实际开发中的计算逻辑会比计算 doube 复杂的多,但是都可以封装成一个函数去执行;下 一步,我们要考虑的是,如何让 double 的值得到自动计算

  如果我们能让 getDouble 函数自动执行,也就是如下图所示,我们使用 JavaScript 的某种机制,把 count 包裹一层,每当对 count 进行修改时,就去同步更新 double 的值,那 么就有一种 double 自动跟着 count 的变化而变化的感觉,这就算是响应式的雏形了

1.png


响应式原理

响应式原理是什么呢?Vue 中用过三种响应式解决方案,分别是 defineProperty、Proxy 和 value setter我们首先来看 Vue 2 的 defineProperty API

这里我结合一个例子来说明,在下面的代码中,我们定义个一个对象 obj,使用 defineProperty 代理了 count 属性;这样我们就对 obj 对象的 value 属性实现了拦截,读取 count 属性的时候执行 get 函数,修改 count 属性的时候执行 set 函数,并在 set  函数内部重新计算了 double

let getDouble = n=>n*2
let obj = {}
let count = 1
let double = getDouble(count)
Object.defineProperty(obj,'count',{
    get(){
        return count
    },
    set(val){
        count = val
        double = getDouble(val)
    }
})
console.log(double) // 打印2
obj.count = 2
console.log(double) // 打印4 有种自动变化的感觉

这样我们就实现了简易的响应式功能,在课程的第四部分,我还会带着你写一个更完善的响应式系统

但 defineProperty API 作为 Vue 2 实现响应式的原理,它的语法中也有一些缺陷;比如在下面代码中,我们删除 obj.count 属性,set 函数就不会执行,double 还是之前的数值;这也是为什么在 Vue 2 中,我们需要 $delete 一个专门的函数去删除数据

delete obj.count
console.log(double) // doube还是4

Vue 3 的响应式机制是基于 Proxy 实现的;就 Proxy 这个名字来说,你也能看出来这是代理的意思,Proxy 的重要意义在于它解决了 Vue 2 响应式的缺陷

我们看下面的代码,在其中我们通过 new Proxy 代理了 obj 这个对象,然后通过 get、set 和 deleteProperty 函数代理了对象的读取、修改和删除操作,从而实现了响应式的功能

let proxy = new Proxy(obj,{
    get : function (target,prop) {
        return target[prop]
    },
    set : function (target,prop,value) {
        target[prop] = value;
        if(prop==='count'){
            double = getDouble(value)
    }
},
deleteProperty(target,prop){
    delete target[prop]
    if(prop==='count'){
        double = NaN
    }
   }
})
console.log(obj.count,double)
proxy.count = 2
console.log(obj.count,double)
delete proxy.count
// 删除属性后,我们打印log时,输出的结果就会是 undefined NaN
console.log(obj.count,double)

我们从这里可以看出 Proxy 实现的功能和 Vue 2 的 definePropery 类似,它们都能够在用户修改数据的时候触发 set 函数,从而实现自动更新 double 的功能。而且 Proxy 还完善了几个 definePropery 的缺陷,比如说可以监听到属性的删除

Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且我们也能通过 deleteProperty 实现对删除操作的代理

当然,为了帮助你理解 Proxy,我们还可以把 double 相关的代码都写在 set 和 deleteProperty 函数里进行实现,在课程的后半程我会带你做好更完善的封装;比如下面代码中,Vue 3 的 reactive 函数可以把一个对象变成响应式数据,而 reactive 就是基于 Proxy 实现的;我们还可以通过 watchEffect,在 obj.count 修改之后,执行数据的打印

import {reactive,computed,watchEffect} from 'vue'
let obj = reactive({
    count:1
})
let double = computed(()=>obj.count*2)
obj.count = 2
watchEffect(()=>{
    console.log('数据被修改了',obj.count,double.value)
})

有了 Proxy 后,响应式机制就比较完备了;但是在 Vue 3 中还有另一个响应式实现的逻辑,就是利用对象的 get 和 set 函数来进行监听,这种响应式的实现方式,只能拦截某一个属性的修改,这也是 Vue 3 中 ref 这个 API 的实现

名品购物网店系统
名品购物网店系统

适合品牌专卖店专用,从前台的美工设计就开始强调视觉形象,有助于提升商品的档次,打造网店品牌!后台及程序核心比较简洁,着重在线购物,去掉了繁琐的代码及垃圾程式,在结构上更适合一些中高档的时尚品牌商品展示. 率先引入语言包机制,可在1小时内制作出任何语言版本,程序所有应用文字皆引自LANG目录下的语言包文件,独特的套图更换功能,三级物品分类,购物车帖心设计,在国内率先将购物车与商品显示页面完美结合,完

下载

在下面的代码中,我们拦截了 count 的 value 属性,并且拦截了 set 操作,也能实现类似的功能

let getDouble = n => n * 2
let _value = 1

double = getDouble(_value)
let count = {
    get value() {
        return _value
    },
    set value(val) {
        _value = val
        double = getDouble(_value)
    }
}

console.log(count.value,double)
count.value = 2
console.log(count.value,double)

三种实现原理的对比表格如下,帮助你理解三种响应式的区别

实现原理 defineProperty Proxy value setter
实际场景 Vue 2 响应式 Vue 3 reactive Vue 3 ref
优势 兼容性 基于proxy实现真正的拦截 实现简单
劣势 数组和属性删除等拦截不了 兼容不了 IE11 只拦截了 value 属性
实际应用 Vue 2 Vue 3 复杂数据结构 Vue 3 简单数据结构

定制响应式数据

简单入门响应式的原理后,接下来我们学习一下响应式数据在使用的时候的进阶方式;我们看下使用 重构之后的 todolist 的代码;这段代码使用 watchEffect,数据变化之后会把数据同步到 localStorage 之上,这样我们就实现了 todolist 和本地存储的同步

import { ref, watchEffect, computed } from "vue";
let title = ref("");
let todos = ref(JSON.parse(localStorage.getItem('todos')||'[]'));
watchEffect(()=>{
    localStorage.setItem('todos',JSON.stringify(todos.value))
})
function addTodo() {
    todos.value.push({
        title: title.value,
        done: false,
    });
    title.value = "";
}

更进一步,我们可以直接抽离一个 useStorage 函数,在响应式的基础之上,把任意数据响应式的变化同步到本地存储;我们先看下面的这段代码,ref 从本地存储中获取数据,封装成响应式并且返回,watchEffect 中做本地存储的同步,useStorage 这个函数可以抽离成一个文件,放在工具函数文件夹中

function useStorage(name, value=[]){
    let data = ref(JSON.parse(localStorage.getItem(name)||'[]'))
    watchEffect(()=>{
        localStorage.setItem(name,JSON.stringify(data.value))
    })
    return data
}

在项目中我们使用下面代码的写法,把 ref 变成 useStorage,这也是 Composition API 最大的优点,也就是可以任意拆分出独立的功能

let todos = useStorage('todos',[])
function addTodo() {
    ...code
}

现在,你应该已经学会了在 Vue 内部进阶地使用响应式机制,去封装独立的函数;在后续的实战应用中,我们也会经常对通用功能进行封装;如下图所示,我们可以把日常开发中用到的数据,无论是浏览器的本地存储,还是网络数据,都封装成响应式数据,统一使用响应式数据开发的模式;这样,我们开发项目的时候,只需要修改对应的数据就可以了

2.png

基于响应式的开发模式,我们还可以按照类似的原理,把我们需要修改的数据,都变成响应式;比如,我们可以在 loading 状态下,去修改浏览器的小图标 favicon;和本地存储类似,修改 favicon 时,我们需要找到 head 中有 icon 属性的标签

在下面的代码中,我们把对图标的对应修改的操作封装成了 useFavicon 函数,并且通过 ref 和 watch 的包裹,我们还把小图标变成了响应式数据

import {ref,watch} from 'vue'
export default function useFavicon( newIcon ) {
    const favicon = ref(newIcon)
    const updateIcon = (icon) => {
        document.head
        .querySelectorAll(`link[rel*="icon"]`)
        .forEach(el => el.href = `${icon}`)
    }
watch( favicon,
    (i) => {
        updateIcon(i)
    }
)
    return {favicon,reset}
}

这样在组件中,我们就可以通过响应式的方式去修改和使用小图标,通过对 faivcon.value 的修改就可以随时更换网站小图标;下面的代码,就实现了在点击按钮之后,修改了网页的图标为 geek.png 的操作



Vueuse 工具包

我们自己封装的 useStorage,算是把 localStorage 简单地变成了响应式对象,实现数据的更新和localStorage 的同步;同理,我们还可以封装更多的类似 useStorage 函数的其他 use 类型的函数,把实际开发中你用到的任何数据或者浏览器属性,都封装成响应式数据,这样就可以极大地提高我们的开发效率

Vue 社区中其实已经有一个类似的工具集合,也就是 VueUse,它把开发中常见的属性都封装成为响应式函数

VueUse 趁着这一波 Vue 3 的更新,跟上了响应式 API 的潮流;VueUse 的官方的介绍说这是一个 Composition API 的工具集合,适用于 Vue 2.x 或者 Vue 3.x,用起来和 React Hooks 还挺像的

在项目目录下打开命令行里,我们输入如下命令,来进行 VueUse 插件的安装:

npm install @vueuse/core

然后,我们就先来使用一下 VueUse;在下面这段代码中,我们使用 useFullscreen 来返回全屏的状态和切换全屏的函数;这样,我们就不需要考虑浏览器全屏的 API,而是直接使用 VueUse 响应式数据和函数就可以很轻松地在项目中实现全屏功能


useFullscreen 的封装逻辑和 useStorage 类似,都是屏蔽了浏览器的操作,把所有我们需要用到的状态和数据都用响应式的方式统一管理,VueUse 中包含了很多我们常用的工具函数,我们可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理

(学习视频分享:web前端开发编程基础视频

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java入门学习合集
java入门学习合集

本专题整合了java入门学习指南、初学者项目实战、入门到精通等等内容,阅读专题下面的文章了解更多详细学习方法。

2

2026.01.29

java配置环境变量教程合集
java配置环境变量教程合集

本专题整合了java配置环境变量设置、步骤、安装jdk、避免冲突等等相关内容,阅读专题下面的文章了解更多详细操作。

2

2026.01.29

java成品学习网站推荐大全
java成品学习网站推荐大全

本专题整合了java成品网站、在线成品网站源码、源码入口等等相关内容,阅读专题下面的文章了解更多详细推荐内容。

0

2026.01.29

Java字符串处理使用教程合集
Java字符串处理使用教程合集

本专题整合了Java字符串截取、处理、使用、实战等等教程内容,阅读专题下面的文章了解详细操作教程。

0

2026.01.29

Java空对象相关教程合集
Java空对象相关教程合集

本专题整合了Java空对象相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.29

clawdbot ai使用教程 保姆级clawdbot部署安装手册
clawdbot ai使用教程 保姆级clawdbot部署安装手册

Clawdbot是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

25

2026.01.29

clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址
clawdbot龙虾机器人官网入口 clawdbot ai官方网站地址

clawdbot龙虾机器人官网入口:https://clawd.bot/,clawdbot ai是一个“有灵魂”的AI助手,可以帮用户清空收件箱、发送电子邮件、管理日历、办理航班值机等等,并且可以接入用户常用的任何聊天APP,所有的操作均可通过WhatsApp、Telegram等平台完成,用户只需通过对话,就能操控设备自动执行各类任务。

16

2026.01.29

Golang 网络安全与加密实战
Golang 网络安全与加密实战

本专题系统讲解 Golang 在网络安全与加密技术中的应用,包括对称加密与非对称加密(AES、RSA)、哈希与数字签名、JWT身份认证、SSL/TLS 安全通信、常见网络攻击防范(如SQL注入、XSS、CSRF)及其防护措施。通过实战案例,帮助学习者掌握 如何使用 Go 语言保障网络通信的安全性,保护用户数据与隐私。

8

2026.01.29

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

622

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue 教程
Vue 教程

共42课时 | 7.4万人学习

Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 1.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号