从零写一个类似Vue的Mvvm框架 01

MVVM框架网上都能找到好多说明的,比如Vue是当下最火之一,俗话说没吃过猪肉还没见过猪跑吗?我今天非但要吃还要挑好的吃、吃到爽,嘿嘿!

于是乎我最近就花了不少时间来学习vue的源码,然后自己写来试试,说实话直接看源码比较难受,因为源码处理各种逻辑、涉及到各种情况,条条框框一大堆,我就抓住它的主线把代码先写出来,也算是半抄半写了,费了不少时间,但好歹是写了个雏形出来,也算安慰吧,放到网上大家一起交流!

至于mvvm的原理网上有一大堆,我也就不复制了,没劲!

这次主要完成了什么东西呢?向大家汇报一下(首先要肯定的是基本功能有了

1.初始化各种变量(data、methods,computed等)

2.数据代理

3.数据劫持

4.用文档碎片编译模板(后面改成虚拟dom)

5.实现观察者模式

6.数据驱动页面更新

7.双向绑定

8.计算属性的处理

9.事件绑定(目前还没有处理参数以及绑定多个的情况)

10.mounted等前面几个生命周期钩子的处理

下面来看看是代码怎么写的:

我们看到 Vue是通过构造函数的方式来实例化的,我这个也是,然后通过调用Mvvm的原型方法_init来进入。

_init 方法做了一些什么事情呢?

1.给当前实例_uid,设置_isMvvm属性这个属性后面与组件作为区分的属性

2.初始化一些必要的参数  vm.initLifecycle();

3.调用beforeCreate、create、mounted等生命周期钩子函数

4.数据代理、数据劫持、处理data、methods ==> vm.initState()

5.编译模板 new Compile(vm);

    Mvvm.prototype={
    	_init:function (options) {
		      var vm = this;
		      //给mvvm设定一个id
		      vm._uid = uid$1++;
		      vm._isMvvm = true;
		      
		   	  vm.$options = options;
		      vm._self = vm;
		      //初始化生命周期
		      vm.initLifecycle();
		      //初始化事件
		      vm.initEvents();
		      //执行beforeCreate钩子
		      callHook(vm,'beforeCreate');
		      //数据代理、数据劫持、处理data、methods等
		      vm.initState();
		      //执行created钩子
		      callHook(vm,'created');
		      //编译
		      new Compile(vm);
		      //执行mounted钩子
			  callHook(vm,'mounted');//编译完成后的钩子
     	}

进入到 vm.initState()的initState函数里面,看它做的事情:

initState:function(){
     		var vm = this;
			var opts = vm.$options;
				
			//data的处理
		    opts.data = vm.initData(opts.data);
			   
			//将data代理到vm下
	   	  	vm.initProxy();
		      //数据劫持
		    vm.initInjections();
		     //处理props
		    if(opts.props){vm.initProps(opts.props)};
		     //处理methods
		    if(opts.methods){vm.initMethods(opts.methods)};
		     //处理计算属性computed
		    if(opts.computed){vm.initComputed(opts.computed)};
		     //处理filters(过滤器,暂不支持)
		    if(opts.filters){vm.initFilters(opts.filters)};
		}

  1.数据代理、数据劫持 主要用到了Object.defineProperty 也不多说了,要注意的3个地方如图:

  2.处理计算属性computed

initComputed:function(computed){
			//处理计算属性
		 	var me=this;
		 	var computedKeys=[];
		 	var cObj;
		 	_.eachObj(computed,function(key,value){
				 cObj = value ;
				 var getter = _.isFunction(cObj)? cObj : (_.isObject(cObj)?cObj.get:function(){});
				 var setter = _.isFunction(cObj)? function(){} : (_.isObject(cObj)?cObj.set:function(){});
				 
				 Object.defineProperty(me, key, {
				 	enumerable: true,
	     			configurable: true,
				 	get:getter,
				 	set:setter
				 });
				 
				 me[key]= getter.bind(me);
				 
				 computedKeys.push(key);
			 })
		 	me.$computedKeys = computedKeys;
		}

  3.处理methods,就是把方法代理到mvvm实例对象中。

  

找到  new Compile(vm) 进入编译,这里需要关注的两个事情:

1.将el对应dom元素的子节点全部插入到文档碎片当中,到编译完成、数据处理完成后在重新添加回来。

2.处理文档碎片(编译及数据处理等)

 

编译的过程就是循环每一个节点,处理节点里面的我们需要处理的属性,比如m-text文本属性、m-html,m-on:click事件属性等

当匹配到对应的属性就去compileUtil对象中寻找到处理逻辑,将从data里面获取到数据更新到对应的节点上,并且添加观察者

 

当全部编译完成,就会重新设置回页面当中,至此整个页面编译完成(下面这段模板可以看到编译前后的对比):

  <div id="app">
        	<p>{{first}}-{{second}}</p>
        	<p m-text='first'>{{second}}</p>
        	<p m-text='second'></p>
       	 	computed:<p m-text='fullName'></p>
       	 	<p>ha:<input m-model='first'></input></p>
          
       	 	 <button m-on:click="test">test</button>
        </div>

未编译前是这个样子的:

编译完成后

成功的将data、computed 包含方法都映射到页面上了,测试一下,在文本框输入内容看什么效果:

因为文本框绑定的是data的first,可以通过文本修改来修改数据,同时再次更新到页面上,页面上多次绑定了first的都自动更新了,这就是我们想要的双向绑定。

然后点击test按钮,效果如下,说明了什么?

1.点击事件已经实现

2.可以看到绑定的函数 test里面执行了一句话    this.second=(Math.random()*1000).toFixed(0);就是设置随机3位数给second,页面绑定second的也自动更新了(这里就是观察者的体现)

 

至此已经通过代码来实现mvvm的雏形了,所谓万事开头难,有了开头,我们就可以一步步的完善了。

 

接下来要完善的是哪些需求呢

1.对象的观察,目前对于对象的观察还未处理(data里面的数据是对象)

2.列表的处理 m-for指令

3.虚拟dom(包含 虚拟语法树、diff算法、局部更新)

4.事件的带参数调用,以及支持多个绑定(还包括 @click方式的处理

5.表达式计算属性的处理   {{a+b+c}}

6.组件的支持

7.过滤器的处理(全局,局部过滤器)

8.http的处理

9.动画的支持

10.属性的绑定 (m-bind以及简易模式  :bind 、:class 、:disabled 等)

11.if、elseif、else等条件语法支持

12.show、hide的支持

13.自定义属性的处理

14.事件修饰符、按键修饰符

 

目前就先考虑以上的处理吧,与君共勉!!

完整代码 点这里下载!!

大家回复一波呗!

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程界小明哥

请博主喝瓶水,博主持续输出!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值