写点什么

3 分钟带你搞懂 Vue 双向绑定原理及问题剖析

作者:Bug终结者
  • 2022 年 3 月 26 日
  • 本文字数:4310 字

    阅读完需:约 14 分钟

3分钟带你搞懂Vue双向绑定原理及问题剖析

📢📢📢📣📣📣<br>哈喽!大家好,我是【Bug 终结者,【CSDN 新星创作者】🏆,阿里云技术博主🏆,51CTO 人气博主🏆,INfoQ 写作专家🏆 <br/>一位上进心十足,拥有极强学习力的【Java 领域博主】😜😜😜 <br/>🏅【Bug 终结者】博客的领域是【面向后端技术】的学习,未来会持续更新更多的【后端技术】以及【学习心得】。 偶尔会分享些前端基础知识,会更新实战项目,面向企业级开发应用!🏅 如果有对【后端技术】、【前端领域】感兴趣的【小可爱】,欢迎关注【Bug 终结者】💞💞💞<br>❤️❤️❤️ 感谢各位大可爱小可爱! ❤️❤️❤️


一、什么是 Vue 双向绑定?

所谓双向绑定,指的是 vue 实例中的 data 与其渲染的 DOM 元素的内容保持一致,无论谁被改变,另一方会相应的更新为相同的数据。

二、Vue 的双向绑定

⌚双向绑定的原理

Vue 数据双向绑定原理是通过数据劫持结合发布者-订阅者模式的方式来实现的,首先是对数据进行监听,然后当监听的属性发生变化时则告诉订阅者是否要更新,若更新就会执行对应的更新函数从而更新视图


通过Object.defineProperty()来劫持各个属性的settergetter,在数据发生变动时通知 Vue 实例,触发相应的​getter​和​setter​回调函数。


当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时, Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 ​getter/setter​。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

⚡双向绑定的核心

关于 VUE 双向数据绑定,其核心是 Object.defineProperty() 方法

⌚介绍 Object.defineProperty() 方法

Object.defineProperty(obj, prop, descriptor)
复制代码


这个方法内有三个参数,分别为 obj(要定义其上属性的对象)、prop(要定义或修改的属性)、descriptor(具体的改变方法)


简单来说,就是用这个方法定义一个值,当调用时我们使用了它里面的 get 方法,当我们给这个属性赋值时,同时又调用了里面的 set 方法



运行效果


三、单向绑定与双向绑定的区别,适合的场景?

❇️单向绑定

单向绑定的优点是相应的可以带来单向数据流,这样做的好处是所有状态变化都可以被记录、跟踪,状态变化通过手动调用通知,源头易追溯,没有“暗箱操作”。同时组件数据只有唯一的入口和出口,使得程序更直观更容易理解,有利于应用的可维护性


缺点则是代码量会相应的上升,数据的流转过程变长,从而出现很多类似的样板代码。同时由于对应用状态独立管理的严格要求(单一的全局 store),在处理局部状态较多的场景时(如用户输入交互较多的“富表单型”应用),会显得啰嗦及繁琐。

♻️双向绑定

优点是在表单交互较多的场景下,会简化大量业务无关的代码


缺点就是由于都是“暗箱操作”,我们无法追踪局部状态的变化(虽然大部分情况下我们并不关心),潜在的行为太多也增加了出错时 debug 的难度。同时由于组件数据变化来源入口变得可能不止一个,新手玩家很容易将数据流转方向弄得紊乱,如果再缺乏一些“管制”手段,最后就很容易因为一处错误操作造成应用雪崩。

四、简单实现一个 JS 双向绑定

⏳效果图

✅核心源码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>Document</title></head><body>    <div id="app">        <h1>演示JS实现Vue双向绑定</h1>        <p>            <label>请输入内容:</label>            <input type="text" id="txt">        </p>        <p>            <label>显示的内容:</label>            <span id="show"></span>        </p>    </div></body></html><script type="text/javascript">    var obj = {};    Object.defineProperty(obj, 'txt', {        get: function() {            return obj;        },        set: function(val) {            document.getElementById("txt").value = val;            document.getElementById("show").innerText = val;        }    })    document.addEventListener("keyup", function (e) {        obj.txt = e.target.value;    })</script>
复制代码

五、Vue.js 实现简单双向绑定

⏰效果图

✅核心源码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <div id="app">      <h1>演示Vue实现双向绑定</h1>      <p>          <label>请输入内容:</label>          <input type="text" v-model="msg">      </p>      <p>          <label>显示的内容:</label>          <span>{{msg}}</span>      </p>    </div></body><!-- 引入vue --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><!-- 引入axios--><script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script><!-- 引入样式 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script type="text/javascript">    new Vue({        el:"#app",        data() {            return {              msg:''            }        },        mounted(){        },        methods: {                    }    })
</script></html>
复制代码

六、某些情况下对象或数组无法双向绑定的解决方案

♨️数组无法双向绑定的解决方案

修改数组中的内容,数组中的元素发生了变化,而页面没有发生变化

✨数组双向绑定解决效果图

♻️核心源码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <div id="app">      <h1>修改数组的内容后,数组发生了变化,而页面没有发生变化</h1>      <div v-for="item in testArr">        {{item}}      </div>      <button @click="clk1">点击1</button>      <button @click="clk2">点击2</button>    </div></body><!-- 引入vue --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><!-- 引入axios--><script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script><!-- 引入样式 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script type="text/javascript">    new Vue({        el:"#app",        data() {            return {              testArr : [1,2,3],            }        },        mounted(){        },        methods: {            clk1() {              console.log("修改第一个数字,页面没有修改");              this.testArr[0] = 20;              console.log("testArr:" + this.testArr)            },            clk2() {              console.log("修改了数字,页面发生了修改")              this.$set(this.testArr, 0, 12);              console.log("testArr:" + this.testArr)            }        }    })
</script></html>
复制代码

✅问题解决

第一个按钮修改后无法显示是因为直接用下标赋值会出现数据不一致情况,可见,数组中的元素已经修改,但页面元素无法显示


解决方案如下


解决方案是通过 $set 方法来设置数组的值,该方法有三个参数,第一个是要被设置值的目标对象,第二个是设置值在数组中的索引,第三个是设置的值


this.$set(obj, index, value)
复制代码


第二个按钮就是这样实现了数组的内容修改以及双向绑定的正确显示

♨️对象无法双向绑定的解决方案

✨对象双向绑定解决效果图

♻️核心源码

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <div id="app">      <h1>修改对象的属性,但页面中没有发生改变</h1>      {{obj.name}}      <button @click="clk1">修改对象的属性1</button>      <button @click="clk2">修改对象的属性2</button>    </div></body><!-- 引入vue --><script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script><!-- 引入axios--><script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script><!-- 引入样式 --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"><!-- 引入组件库 --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script type="text/javascript">    new Vue({        el:"#app",        data() {            return {              obj:{                //初始化属性                name: ''              }            }        },        mounted(){
}, methods: { clk1() { console.log("修改对象的属性,未发生变化!"); this.obj.name = 'zhangsan'; console.log(this.obj); }, clk2() { this.$set(this.obj, "name", "zhangsan"); console.log("属性添加成功~") console.log(this.obj); } } })
</script></html>
复制代码

✅问题解决

由于在 data 函数中未定义对象的属性,所以导致双向绑定失败!


解决方案如下


  1. 在 data 函数中的对象初始化对象的属性



  1. 使用 $set 设置属性



至此双向绑定完美解决

♨️往期精彩热文回顾

✈️ Netty进阶 -- WebSocket长连接开发✈️ Netty进阶 -- 非阻塞网络编程 实现群聊+私聊+心跳检测系统


✈️ Postman测试工具调试接口详细教程【向后端发送Json数据并接收返回的Json结果】


✈️ Java面向对象 --- 吃货联盟订餐系统(完整版)✈️ 一分钟教你快速 搭建Vue脚手架(Vue-Cli)项目并整合ElementUI

⛵小结

以上就是【Bug 终结者】对 Vue 双向绑定及详解简单的概述,Vue 双向绑定原理就是如此,也是很常见的面试题,大家多看上几遍,并结合自己的理解,相信你很快就可以掌握的~


如果这篇【文章】有帮助到你,希望可以给【Bug 终结者】点个赞👍,创作不易,如果有对【后端技术】、【前端领域】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【Bug 终结者】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💝💝💝!

发布于: 刚刚阅读数: 2
用户头像

Bug终结者

关注

励志成为一个优秀的开发者~ 2021.12.09 加入

星星之火,可以燎原

评论

发布
暂无评论
3分钟带你搞懂Vue双向绑定原理及问题剖析_CSS_Bug终结者_InfoQ写作平台