<强>前言强>
最近在学习vue框架的基本原理,看了一些技术博客以及一些对vue源码的简单实现,对数据代理,数据劫持,模板解析,变异数组方法,双向绑定有了更深的理解。于是乎,尝试着去实践自己学到的知识,用vue的一些基本原理实现一个简单的todo - list,完成对深度复杂对象的双向绑定以及对数组的监听,加深了对vue基本原理的印象。
github地址:todo - list
<强>学习链接强>
前排感谢以下文章,对我理解vue的基本原理有很大的帮助!
剖析vue实现原理,自己动手实现mvvm DMQ
对vue早期源码的理解,梁少峰
<>强实现效果强>
<强>数据代理
强>
1。简单介绍数据代理
正常情况下,我们都会把数据写在数据里面,如下面所示
var vm=new Vue ({ 埃尔:“#应用”, 数据:{ 标题:“hello world” } 方法:{ changeTitle:函数(){ 这一点。title=澳愫胿ue” } } }) console.log (vm.title)//癶ello world”或“你好vue” >之前如果没有数据代理,而我们又要修改数据里面的标题的话,方法里面的changeTitle只能这样修改成<代码> this.data。title=澳愫胿ue”> 代码,下面的控制台也只能改成<代码> console.log (vm.data.title) 代码>数据代理就是这样的功能。
<强> 2。实现原理强>
通过遍历数据里面的属性,将每个属性通过object.defineProperty()设置getter和setter,将数据里面的每个属性都复制到与数据同级的对象里。
(对应上面的示例代码)
,
触发这里的getter将会触发数据里面对应属性的getter,触发这里的setter将会触发数据里面对应属性的setter,从而实现代理。实现代码如下:
var自我=;//这个vue实为例,即vm 种(this.data) .forEach(函数(关键){ Object.defineProperty(关键,{//1晏?即vm.title 可列举的:假的, 可配置:没错, 得到:getter函数(){ 返回self.data(例子);//触发对应的数据(关键)的getter }, 设置:setter函数(newVal) { 自我。数据(关键)=newVal;//触发对应的数据(关键)的setter } }); } >之前对object.defineProperty不熟悉的小伙伴可以在MDN的文档(链接)学习一下
<强>双向绑定
强><李>数据变动——→李视图更新> <李>视图更新(输入、textarea)——比;数据变动
李><代码>视图更新——比;数据变动> 代码这个方向的绑定比较简单,主要通过事件监听来改变数据,比如输入可以监听输入事件,一旦触发输入事件就改变数据。下面主要来理解一下<代码>数据变动——→视图更新代码>这个方向的绑定。
<强> 1。数据劫持强>
不妨让我们自己思考一下,如何实现数据变动,对应绑定数据的视图就更新呢?
答案还是object.defineProperty,通过object.defineProperty遍历设置this.data里面所有属性,在每个属性的setter里面去通知对应的回调函数,这里的回调函数包括dom视图重新渲染的函数,使用美元看添加的回调函数等,这样我们就通过object.defineProperty劫持了数据,当我们对数据重新赋值时,如<代码> this.title='你好vue '> 代码,就会触发setter函数,从而触发dom视图重新渲染的函数,实现数据变动,对应视图更新。
<强> 2。发布-订阅模式强>
那么问题来了,我们如何在setter里面触发所有绑定该数据的回调函数呢?
既然绑定该数据的回调函数不止一个,我们就把所有的回调函数放在一个数组里面,一旦触发该数据的setter,就遍历数组触发里面所有的回调函数,我们把这些回调函数称为订阅者。数组最好就定义在setter函数的最近的上级作用域中,如下面实例代码所示。
种(this.data) .forEach(函数(关键){ var潜艇=[];//在这里放置添加所有订阅者的数组 Object.defineProperty (this.data键,{//this.data.title 可列举的:假的, 可配置:没错, 得到:getter函数(){ console.log(“访问数据啦啦啦”) 返回this.data(例子);//返回对应数据的值 }, 设置:setter函数(newVal) { 如果(newVal===this.data[主要]){ 返回;//如果数据没有变动,函数结束,不执行下面的代码 } 这一点。数据(关键)=newVal;//数据重新赋值 潜艇。forEach(函数(){//通知潜艇里面的所有的订阅者 }) } }); }用vue的双向绑定简单实现一个todo - list的示例代码