vue框架出现之初,就以mvvm模式,双向绑定让人眼前一亮,同样的,从开始使用vue,vue双向绑定的原理也一直是面试的高热话题,那么我们今天来聊聊关于双向数据绑定原理。
MVVM
首先要聊的是MVVM,在这个概念之前,我们经历过最对的应该是MVC,也就是模型,视图,控制器,就是把一次数据渲染看出是由控制器指挥的从模型到视图的过程,在这个基础上,我们再看MVVM,为了理解他是这样读的,MVVM,也就是说是三部分,M依然是模型,V依然是视图,但是VM是一个整体,就是视图模型,作为前端小伙伴,编写代码的过程当中可以把所有业务逻辑放到这个VM层当中。基于上面的描述,我们总结:
1、MVVM也是一种类似MVC的设计模式。
2、M是模型代表的是数据,vue是视图,在前端代表展示的UI层(有后端基础的小伙伴一定要注意这个区分,这里并不是视图函数),而VM这是视图模型,通过他来讲M的数据渲染到V上面。
3、M和V不会直接沟通,M会直接国通VM,并且是双向的,同样VM还会沟通V,所以我们了解MVVM或者双向绑定,还是需要侧重在VM这个概念上。
4、作为中间的传输工具,VM必须知道M和V任何一个的变化,并且可以通知到另一端。
Object.defineProperty
上面聊了大概的概念,那么下面来聊聊实现双向绑定的核心
js当中的Object.defineProperty(obj, prop, descriptor) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象,其中参数:
obj:要定义属性的对象
prop:要定义或修改的属性的名称或 Symbol
descriptor:要定义或修改的属性描述符
返回值:被传递给函数的对象
<!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>双向绑定</title>
</head>
<body>
<input type="text" id="app">
<span id="text"></span>
</body>
<script>
var obj = {};
var init_value='a'; //这里一定要用var
Object.defineProperty(obj,'init_value',{
get(){ // 获取值的时候触发
console.log('获取obj最新的值');
return init_value
},
set(new_value){ // 设置值的时候触发
init_value = new_value;
console.log('设置最新的值');
document.getElementById('text').innerHTML = init_value;
console.log(obj.initValue);
}
});
//这里和双向绑定的关系已经不是很大了,只是一个监听事件,当文本框里面的值发生修改
// 获取最新的值 然后赋值给obj
document.addEventListener('keyup', function (e) {
obj.init_value = e.target.value;
})
</script>
</html>
总结
那么回头来总结,在vue当中也是如此,先将vue当中的初始值渲染到页面上,然后如果页面上数据发生修改,在同步到vue实例当中,然后如果vue实例当中的数据发生了变化再同步回来。这个过程就是js当中的数据劫持。
当然vue再实现双向绑定的过程当中,除了上面的数据劫持还使用了很多技术,比如DocuemntFragment 拦截,发布订阅模式等等,我们之后再做详细的解释,这里还是欢迎各位大佬多多指定。