那些Vue开发遇到的坑---响应式系统
zhezhongyun 2025-05-08 08:04 8 浏览
Vue是目前使用较为广泛的前端框架之一。相比React,Vue更容易学习上手。毕竟在React中万物皆JavaScript。这让一些习惯于编写HTML+JavaScript的程序员不太乐于接受。相比之下,Vue的模板语法它不香么。
当然,Vue同样支持类似于JSX的语法的渲染函数,但是相信我,只要你学了模板语法,你就会放弃渲染函数。
有的同学可能会提到AngularJS,这里就要说道,Vue的一些语法设计的确参考了AngularJS,但是Vue的API设计相对AngularJS要简单的多,学习成本更低。
而且,Vue在设计过程中解决了很多AngularJS存在的问题,包括Vue对数据流的控制都会让你的代码更加清晰易懂,让你可以在使用框架或者阅读别人代码的时候少说几句F**k(这个不完全保证)。
虽然Vue上手容易,但这并不代表你可以轻而易举的完全掌握它,要想真正了解并熟练这个框架,它的一些底层原理还是要了解一二的,这同样有助于开阔你的编程思路。今天我们就先介绍一下Vue最独特的特性之一--------响应式系统(这句话是抄官方的)。
Vue的响应式指的是你在一个页面中展示了一个变量的值,当这个变量的值由于一些操作发生改变时,Vue会自动在无需刷新界面的前提下帮你把新的值展示到相应的位置,当然这个过程不需要你自己写任何的dom刷新渲染的代码(我觉得我说的够通俗易懂了,再看不懂,请你去看尤雨溪的官方解说,保证你更看不懂)。
为了实现这一效果,Vue做了很多你不知道的事(不然怎么会不用你写一行代码,因为他们替你写了)。接下来的解说涉及一些Vue和JavaScript的基础知识,比如Object.defineProperty等,不太了解的同学请复制Object.defineProperty并打开浏览器粘贴到检索栏按下回车看看这到底是啥。
虽然Vue3版本弃用defineProperty改用proxy,但是响应式系统的主要思路还是没有变的,所以此处提到的defineProperty是Vue2的实现方法,这点请小伙伴们注意哦。
VUE·响应式原理
一个Vue实例具备一个名为data的数据对象,对象中包含了当前Vue实例所需要的数据,当一个Vue实例生成时,Vue的响应式系统会递归的将data的property通过Object.defineProperty转换为getter/setter。
你可以理解为响应式系统对每一个实例数据绑定了getter/setter函数,要获取数据需要通过调用getter函数,为数据写入新值则需要调用setter函数。
每一个Vue实例还对应一个watcher实例(看名字就是知道这是拿来监听的)。这个watcher实例会记录与它对应的Vue实例的所接触过的所有数据。在此之后如果某条数据发生改变,那么必将通过setter函数去设置新值,这时watcher会监听到这一变化,然后通知用到这个数据的Vue实例进行重新渲染,更新新值到页面上,整个流程如下图:
引自:
https://cn.vuejs.org/v2/guide/reactivity.html
上面那段话可能会比较晦涩难懂,因此我准备了下面这段话:我们以一个按钮为例,按钮上显示了一个由变量定义的字,当点击按钮时按钮上的文字会发生改变,代码如下:
<template> <div> <button type="button" @click="message='Do not click me!'">{{message}}</button> </div></template><script> export default { name: "demo", data() { return { message: 'Click Me!' } } }</script>
从代码中我们可以看到,这个Vue实例包含一个按钮和一个名为message的数据,在按钮上的字通过调用message来展示。
当这个Vue实例被注册时,我们的响应式系统会为message设置一对getter/setter函数,然后这个Vue实例会去一个叫做watcher的地方登记他用到的变量,这里它登记的就是message,它告诉watcher,我用到了message,当他改变的时候请及时告诉我。Watcher就在小本本上记下来了,并且和message的getter/setter函数保持联系,当我们点击按钮,按钮的click事件改变了message的值,这时会先调用setter函数,setter函数在改变message的值的同时会通知watcher,watcher收到这一消息之后就会通知Vue实例,告诉他,你用到的message变了,Vue实例收到这一消息就会重新渲染按钮,把新的message值显示在按钮上,至此,一次响应式更新完成了。
那些VUE开发遇到的坑响应式系统
Vue的响应式系统非常好用,开发者甚至可以不懂得DOM的渲染相关知识就能完成一个响应式页面的开发,但是,我们日常开发总不可能是都像教程里的demo一样简简单单清清楚楚,一个庞大的web系统会有复杂的组件嵌套引用,组件之间有着复杂的数据交互,偶尔经常就会出现bug,而且有时候你在你的代码中找不到任何问题(那是你以为),然后就会百思不得其解为什么我的数据没有及时更新到页面上!!!一定是Vue有问题,破框架!!!!
好了,吐槽完之后我们还是老老实实看看,到底那里出了问题,为什么你的代码没有按照预期的运行。
今天我就为大家分析一下,在利用Vue进行开发的时候,为什么有些数据的变化不会被及时监听到并触发相关组件从新渲染。
对象类型在JavaScript中是一个引用类型,与基本类型不同,对象是按照引用访问的。因此,如果你想在Vue中监听到一下对象类型变量的变化时,你需要一些额外的操作,就比如下面这几行代码:
<template> <div> {{message.content}} <button type="button" @click="message.content='clicked'">click message</button> </div></template><script> export default { name: "demo", data() { return { message: {} } } }</script>
以上代码渲染了一个按钮,并且声明了一个名为message的空的对象变量,意图是想要在点击按钮时,为message对象设置contact属性的值为‘clicked’。当我们开始运行我们的代码并在页面上点击按钮时,页面上并没有按照我们预期的展示出message的content属性值。然后作为一个程序员,你可能就要开始打debugger一步一步的调试,然后你会发现,你的代码并没有写错,在调试器中,message的属性确实改变了,并且按照预期被设置为‘clicked’,但是,为什么页面毫无反应,预期的‘clicked’字符串去哪里了?
其实,这是由于Vue虽然在初始化的时候向watcher注册了message, watcher中并没有记录一个后续添加的content属性,除非你重新为message赋值否则Vue是无法监听到message的content属性的。
Vue的开发者当然不可能这么无情的让你换个写法,所以他们提供了一个set函数,这个函数可以保证你为message添加的属性也是响应式的,那么就可以让代码按照你的要求执行了,具体实现如下:
<template> <div> {{message.content}} <button type="button" @click="click">click message</button> </div></template><script> export default { name: "demo", data() { return { message: {} } }, methods:{ click(){ this.$set(this.message,'content','clicked') } } }</script>
除了以上的情况,还有另外一种常见情形,就是当一个组件接收一些来自父组件的变量时,如果这个变量是一个对象,你同样无法使用Vue实例的watch去监听到他,在此情况下,可以通过设置deep为true来实现对象的深度监听,如下:
<template> <div> {{message.content}} </div></template><script> export default { name: "demo", props:{ message:{ default:null, } }, watch:{ message:{ deep:true, handler(val){ //message发生改变后的一些逻辑处理 } } } }</script>
值得提醒的是,数组类型在JavaScript中也是一个比较特殊的数据类型,与对象类型相似,数组也是引用类型,因此在开发中也会遇到和对象类型相似的问题,解决方法也是大同小异,此处就不多加说明。
END
关于作者:夏夏,前端工程师,参与普元DevOps产品开发,以及微服务、容器云等产品开发,负责前端页面设计、架构搭建等工作。善于架构搭建、组件封装及相关算法设计。
关于EAWorld:微服务,DevOps,数据治理,移动架构原创技术分享。
相关推荐
- Axure教程
-
来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。前几天看到有人介绍了axure8的图片放大原型设计步骤(http://www.woshipm.com/rp/24687...
- 保姆级教程:手把手教你用 Readdy.ai 轻松产品设计与前端开发
-
本文将为你介绍一款强大的AI工具——Readdy.ai,它不仅能自动生成精美的UI设计稿,还能直接生成可用的前端代码,极大地提升了开发效率。前几天雷神为大家介绍了一款AI设计工具莫高设计,但是...
- 前端学习保姆级教程,轻松入门 Web 开发
-
在当今数字化时代,我们每天浏览的网页、使用的各类应用,其美观的界面、流畅的交互体验背后,都离不开前端开发技术的支撑。前端开发,简单来说,就是负责将网站或应用的界面呈现给用户,它直接影响着用户对产品的第...
- 分享几个css实用技巧
-
本篇将介绍几个css小技巧,目录如下:自定义引用标签的符号重置所有标签样式禁止文本选择制作小三角形自定义<q>引用标签的符号默认q标签引用符号是浏览器根据不同语言环境自动设置的,当然我们也...
- 五步做一个高保真可交互原型-Principle教程
-
这篇教程要介绍的案例是:App界面上调整时间的可交互原型。我们先看一下效果:这个案例用的是Principle这款软件做的。Principle近段时间非常流行的一款做原型的软件。很多公司也用Princi...
- asp网站源码安装教程
-
asp网站源码安装指南1、打开控制面板并单击2、点选管理工具选项3、请单击打开Internet信息服务(IIS)管理器应用查看4、点击开始按钮5、请将项目文件移动到C:inetpubwwwr...
- web前端HTML教程——开发环境搭建下载和安装编辑器
-
html开发环境搭建有一个好的编辑器我们可以方便地的开发项目,编写代码,配置和管理我们的项目。所以我们开始编写html代码之前需要搭建开发环境。基于html项目的开发和代码编写现在网上有很多编辑器,也...
- 如何用控制台打印日历?
-
朋友们大家好,今天我给大家带来一个控制台小程序——打印当月的日历,效果如下图:笔者运行这个程序的时候是2022年7月30日,所以在日期的30后面加了一个*符号。这个程序很简单,但有些知识点我也会为大家...
- dotnet 值拷贝、浅拷贝、深拷贝详解
-
简介在.NET中,值拷贝(ValueCopy)主要指的是将一个值类型的实例或对象的值复制到另一个变量中,使两个变量之间互不影响。我们可以从几个维度来详细理解:值拷贝的本质.NET中的类型分...
- 41 基于Sentinel的限流
-
Sentinel支持对SpringCloudGateway、Zuul等主流的APIGateway进行限流。从1.6.0版本开始,Sentinel提供了SpringCloud...
- Java反射机制:神秘之门的钥匙
-
Java反射机制:神秘之门的钥匙什么是Java反射?当你第一次听说Java反射的时候,你可能会感到困惑。简单来说,Java反射就是让你在程序运行时动态地操作类和对象的能力。这就像一把钥匙,能够打开Ja...
- Java反射机制:魔法般的代码操控
-
Java反射机制:魔法般的代码操控在这个充满无限可能的编程世界里,Java反射机制就像一位神秘的魔法师,它允许程序在运行时检查类、方法、字段等信息,甚至还能动态调用这些成员。这种能力让Java开发者能...
- 自己动手从0开始实现一个分布式 RPC 框架
-
前言为什么要自己写一个RPC框架,我觉得从个人成长上说,如果一个程序员能清楚的了解RPC框架所具备的要素,掌握RPC框架中涉及的服务注册发现、负载均衡、序列化协议、RPC通信协议、Socket通信、异...
- C# 实战指南:使用 iText7 高效处理 PDF 文件
-
1.引言在现代开发中,处理PDF文件是一个常见的需求,例如生成报告、填充表单、设置权限或签名等。iText7是一个功能强大的PDF操作库,支持多种PDF操作,包括表单填充、加密、数字签...
- 手写代码生成工具实现类似Mybatis-Plus的效果-----02
-
#全新智己L6全国试驾开启#packagecom.alatus.builder;importcom.alatus.Entity.FieldInfo;importcom.alatus.Ent...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- HTML 参考手册 (28)
- JavaScript 和 HTML DOM 参考手册 (32)
- HTML 拓展阅读 (30)
- HTML常用标签 (29)
- HTML文本框样式 (31)
- HTML滚动条样式 (34)
- HTML5 浏览器支持 (33)
- HTML5 新元素 (33)
- HTML5 WebSocket (30)
- HTML5 代码规范 (32)
- HTML5 标签 (717)
- HTML5 标签 (已废弃) (75)
- HTML5电子书 (32)
- HTML5开发工具 (34)
- HTML5小游戏源码 (34)
- HTML5模板下载 (30)
- HTTP 状态消息 (33)
- HTTP 方法:GET 对比 POST (33)
- 键盘快捷键 (35)
- 标签 (226)
- HTML button formtarget 属性 (30)