我们都知道,Vue是一套用户构建用户界面的渐进式框架,是目前前端领域的主流框架之一,作为前端的框架它有两大核心:
1.数据双向绑定:当数据发生改变,试图可以自动更新,可以不同关心dom操作,而专心数据操作;
2.可组合的试图组件:吧试图按照功能切成若干基本单元,组件可以一级一级组合整个应用形成倒置组件树,可维护,可重用,可测试。
接下来我们先讨论Vue2和Vue3版本的数据双向绑定原理的区别其各自的优缺点。
由于本篇长较长,咋们次先讨论Vue2的数据双向数据绑定原理,Vue3的数据双向数据绑定咋们在最下面聊:
一、什么是MVVM模式?
在讨论Vue的数据双向数据绑定原理之前,我们还得知道咋们平时工作中用Vue开发的开发模式是什么?那就是MVVM模式。
大多数的开发模式,可能通过最多的是MVC开发模式,当然还有更多的MVP模式,发布订阅者等等,那么Vue为什么要采用MVVM的开发模式,其实主要还是因为MVVM模式可以实现数据的双向数据绑定,它是如何实现的呢?
MVVM可以分为:模型层、视图层、视图模型层,模型层主要干的事情就是负责与业务数据相关的操作,就像我们data函数中返回的数据一样,主要负责数据方面的工作,view层顾名思义就是主要负责试图相对应的操作,神秘的vm层也就是视图模型层主要是是什么的?
视图模型层就是类似一座桥梁,连接模型(数据层) 和视图层,它的工作是双向的一边监听数据,一边观测试图,无论是数据层发生变化还是视图层发生变化,他都会同步给对方,让视图层和数据层保持一致。实现数据的双向绑定。
View -> ViewModel -> Model 互顺的
二、Vue2数据双向绑定原理的实现 Vue2采用数据劫持并结合发布者-订阅者模式的方式,通过ES6的object.defineProperty()方法去劫持各个属性的setter/getter方法,在数据发生变化的时候,发布信息给订阅者,触发相应的监听回调。
具体步骤如下:
1、需要observe(观察者)的数据对象进行遍历,包括子属性对象的属性,都加上setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到数据的变化。
2、compile(解析)模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
3、watcher(订阅者)是observer和compile之间通信的桥梁,主要做的事情是:
1、在实例化时往属性订阅器(dep)里添加自己;
11、自身必须有一个update()方法;
111、待属性变动dep.notice()通知时,能够调用自身的update()方法,并触发compile中绑定的回调;
4.MVVM作为数据绑定入口:
observer,compile和watcher来监听自己的model数据变化,通过compile来解析模板,最终利用watcher搭起observer和compile之间的通信桥梁,达成数据变化-》更新视图:视图交互变化-》数据model变更的双向绑定效果。
三、源码分析:
那么Vue2的源码是如何具体实现它的数据双向绑定原理的呢?我们对源码进行剖析,发现它的代码实现步骤如下:
1. observer实现对vue各个属性进行监听
js
function defineReactive(obj, key, val) {
// 每个属性建立个依赖收集对象,get中收集依赖,set中触发依赖,调用更新函数
var dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function () {
// 收集依赖 Dep.target标志
Dep.target && dep.addSub(Dep.target)
return val
},
set: function (newVal) {
if (newVal === val) return
// 触发依赖
dep.notify()
val = newVal
}
})
}
二、dep的实现
js
function Dep() {
this.subs = []
}
Dep.prototype = {
constructor: Dep,
addSub: function (sub) {
this.subs.push(sub)
},
notify: function () {
this.subs.forEach(function (sub) {
sub.update() // 调用的Watcher的update方法
})
}
}
3. compiler实现对各个指令模板的解析器
通过compiler实现对vue各个指令模板的解析器,生成抽象语法树,编译成Virtual Dom,渲染视图。
js
function compiler(node, vm) {
var reg = /\{\{(.*)\}\}/;
// 节点类型为元素
if (node.nodeType === 1) {
var attr = node.attributes;
// 解析属性
for (var i = 0; i < attr.length; i++) {
if (attr[i].nodeName == 'v-model') {
var _value = attr[i].nodeValue
node.addEventListener('input', function (e) {
//给相应的data属性赋值,触发修改属性的setter
vm[_value] = e.target.value
})
node.value = vm[_value] // 将data的值赋值给node
node.removeAttribute('v-model')
}
}
new Watcher(vm, node, _value, 'input')
}
// 节点类型为text
if (node.nodeType === 3) {
if (reg.test(node.nodeValue)) {
var name = RegExp.$1;
name = name.trim()
new Watcher(vm, node, name, 'input')
}
}
}
4.Watcher连接observer和compiler
通过他们之间的连接,接受每个属性变动的通知,绑定更新函数,更新视图。
js
function Watcher(vm, node, name, nodeType) {
Dep.target = this; // this为watcher实例
this.name = name
this.node = node
this.vm = vm
this.nodeType = nodeType
this.update() // 绑定更新函数
Dep.target = null //绑定完后注销 标志
}
Watcher.prototype = {
get: function () {
this.value = this.vm[this.name] //触发observer中的getter监听
},
update: function () {
this.get()
if (this.nodeType == 'text') {
this.node.nodeValue = this.value
}
if (this.nodeType == 'input') {
this.node.value = this.value
}
}
}
总结:以上是vue2源码的分析
以下是vue3的底层原理分析
Vue3底层原理:
Vue3是Vue.js的最新版本,它在底层原理上进行了重大改进。Vue3的底层原理主要包括响应式系统、虚拟DOM、编辑器和渲染器等方面。
响应式系统
Vue3的响应式系统采用了Proxy代理对象来实现。Proxy是ES6中新增的一个特征,它可以拦截对象的读取、赋值、删除等操作。Vue3利用Proxy代理对象来监听数据的变化,从而实现响应式。
虚拟DOM
Vue3的虚拟DOM采用了模板编译的方式,将模板编译成渲染函数,然后再将渲染函数换成虚拟DOM。这种方式比Vue2的模板解析方式更加高效,因为模板编译只需要进行一次,而模板解析需要每次都进行。
编辑器
Vue3的编辑器采用了基于插件的架构,可以通过插件来扩展编辑器的功能。编辑器的主要作用是将模板编译成渲染函数,同时还可以进行静态优化和代码生成等操作。
Vue3的渲染器采用了基于函数的渲染器,将渲染函数转换成真实的DOM节点。这种方式比Vue2的基于类的渲染器更加高效,因为函数调用比类实例化更加快速。
总结:Vue3的底层原理采用了一系列新的技术和优化,使得Vue3在性能和扩展性方面都有了很大的提升。Vue3的响应式系统采用了Proxy代理对象,虚拟DOM采用了模板编译的方式,编辑器采用了基于插件的架构,渲染器采用了基于函数的渲染器。这些技术的应用使得Vue3成为了一个更加高效、灵活和可扩展的框架。
Vue3双向数据绑定的原理
Vue.js是一款流行的前端框架,它采用了MVVM(Model-View-ViewModel)架构模式,并实现了双向数据绑定。在Vue3中,双向数据绑定是通过Proxy对象实现的。
在Vue3中,双向数据绑定的核心是ViewModel层。ViewModel是Vue框架中的一个重要概念,它负责连接视图层和数据层。在Vue3中,Vue对象被替换为了一个Proxy对象,这个Proxy对象可以代理原始数据对象,实现对数据的劫持和监听。
Proxy对象的代理机制是通过使用get和set方法来实现的。当我们读取数据对象的属性时,Proxy会调用get方法,并返回属性的值。而当我们修改数据对象的属性时,Proxy会调用set方法,并更新属性的值。
双向数据绑定实现流程如下:
- 首先,我们需要创建一个数据对象,并使用Proxy对象对其进行代理。
- 接着,我们需要在视图中使用插值表达式或指令来绑定数据对象的属性。当视图渲染时,Vue会读取数据对象的属性,并显示在视图中。
- 当用户在视图中修改输入框的值时,Vue会自动检测到变化,并调用Proxy对象的set方法来更新数据对象的属性值。
- 当数据对象的属性值发生变化时,Vue会自动检测到变化,并重新渲染视图,从而实现双向数据绑定。
双向数据绑定的优点在于可以简化开发过程,提高开发效率。通过双向数据绑定,我们可以在视图中直接操作数据,而不需要手动更新数据。这样可以减少开发人员的工作量,并提高代码的可读性和可维护性。
然而,双向数据绑定也存在一些问题。首先,双向数据绑定会增加代码的复杂性,特别是在处理复杂的数据逻辑时。其次,双向数据绑定会带来一定的性能损耗,特别是在处理大量数据时。因此,在使用双向数据绑定时,需要合理使用,避免滥用。
总结起来,Vue3通过使用Proxy对象实现了双向数据绑定。双向数据绑定可以简化开发过程,提高开发效率。然而,双向数据绑定也存在一些问题,需要合理使用。在实际开发中,我们可以根据具体的需求来选择是否使用双向数据绑定,以达到最佳的开发效果。