那些Vue开发遇到的坑---响应式系统
zhezhongyun 2025-05-08 08:04 21 浏览
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,数据治理,移动架构原创技术分享。
相关推荐
- 激光手术矫正视力对眼睛到底有没有伤害?
-
因为大家询问到很多关于“基质不能完全愈合”的问题,有必要在这里再详细解释一下。谢谢@珍惜年少时光提出的疑问:因为手头刚好在看组织学,其中提到:”角膜基质约占角膜的全厚度的90%,主要成分是胶原板层,...
- OneCode核心概念解析——View(视图)
-
什么是视图?在前面的章节中介绍过,Page相关的概念,Page是用户交互的入口,具有Url唯一性。但Page还只是一个抽象的容器,而View则是一个具备了具体业务能力的特殊的Page,它可以是一个...
- 精品博文图文详解Xilinx ISE14.7 安装教程
-
在软件安装之前,得准备好软件安装包,可从Xilinx官网上下载:http://china.xilinx.com/support/download/index.html/content/xilinx/z...
- 卡片项目管理(Web)(卡片设计的流程)
-
简洁的HTML文档卡片管理,简单框架个人本地离线使用。将个人工具类的文档整理使用。优化方向:添加图片、瀑布式布局、颜色修改、毛玻璃效果等。<!DOCTYPEhtml><html...
- GolangWeb框架Iris项目实战-JWT和中间件(Middleware)的使用EP07
-
前文再续,上一回我们完成了用户的登录逻辑,将之前用户管理模块中添加的用户账号进行账号和密码的校验,过程中使用图形验证码强制进行人机交互,防止账号的密码被暴力破解。本回我们需要为登录成功的用户生成Tok...
- sitemap 网站地图是什么格式?有什么好处?
-
sitemap网站地图方便搜索引擎发现和爬取网页站点地图是一种xml文件,或者是txt,是将网站的所有网址列在这个文件中,为了方便搜索引擎发现并收录的。sitemap网站地图分两种:用于用户导...
- 如何在HarmonyOS NEXT中处理页面间的数据传递?
-
大家好,前两天的Mate70的发布,让人热血沸腾啊,不想错过,自学的小伙伴一起啊,今天分享的学习笔记是关于页面间数据伟递的问题,在HarmonyOSNEXT5.0中,页面间的数据传递可以有很多种...
- 从 Element UI 源码的构建流程来看前端 UI 库设计
-
作者:前端森林转发链接:https://mp.weixin.qq.com/s/ziDMLDJcvx07aM6xoEyWHQ引言由于业务需要,近期团队要搞一套自己的UI组件库,框架方面还是Vue。而业界...
- jq+ajax+bootstrap改了一个动态分页的表格
-
最近在维护一个很古老的项目,里面是用jq的dataTable方法实现一个分页的表格,不过这些表格的分页是本地分页。现在想要的是点击分页去请求数据。经过多次的修改,以失败告终。分页的不准确,还会有这个错...
- 学习ES6- 入门Vue(大量源代码及笔记,带你起飞)
-
ES6学习网站:https://es6.ruanyifeng.com/箭头函数普通函数//普通函数this指向调用时所在的对象(可变)letfn=functionfn(a,b){...
- 青锋微服务架构之-Ant Design Pro 基本配置
-
青锋(msxy)-Gitee.com1、更换AntDesignPro的logo和名称需要修改文件所在位置:/config/defaultSetting.jsconstproSett...
- 大数据调度服务监控平台(大数据调度服务监控平台官网)
-
简介SmartKettle是针对上述企业的痛点,对kettle的使用做了一些包装、优化,使其在web端也能具备基础的kettle作业、转换的配置、调度、监控,能在很大一定程度上协助企业完成不同...
- Flask博客实战 - 实现博客首页视图及样式
-
本套教程是一个Flask实战类教程,html/css/javascript等相关技术栈不会过多的去详细解释,那么就需要各位初学者尽可能的先去掌握这些基础知识,当然本套教程不需要你对其非常精通,但最起码...
- Web自动化测试:模拟鼠标操作(ActionChains)
-
在日常的测试中,经常会遇到需要鼠标去操作的一些事情,比如说悬浮菜单、拖动验证码等,这一节我们来学习如何使用webdriver模拟鼠标的操作首页模拟鼠标的操作要首先引入ActionChains的包fro...
- DCS F-16C 中文指南 16.9ILS仪表降落系统教程
-
10–ILS教程我们的ILS(仪表着陆进近)将到达Batumi巴统机场。ILS频率:110.30跑道航向:120磁航向/126真航向无线电塔频率:131.0001.设置雷达高度表开关打开(前)并...
- 一周热门
- 最近发表
- 标签列表
-
- HTML 教程 (33)
- HTML 简介 (35)
- HTML 实例/测验 (32)
- HTML 测验 (32)
- 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)
- CSS 水平对齐 (Horizontal Align) (30)