根据vue的官网介绍,可以得知vue是一个mvvm框架,且是响应式的。为了更深入了理解其内涵,本人以及理解实现了一个简单的mvvm学习的demo。下面分享给大家,欢迎大家一起讨论。

一、mvvm至少包含的内容

  1. 指令集合,如:text、model等
  2. 数据模型,与视图交互的数据
  3. 组件的支持:也就是部分html代码的动态更新

二、我的实现

1. 变量的定义与watch的实现

var directives = {}; //指令集合
var vNodes = new Array(); //解析的Dom集合 var dataModel = {
name:"name",
title: "title"
}; //数据Model var Watch = {
isInit: false,
watchs: new Array(),
run: function(newValue, expOrfn){
var self = this;
if(!self.isInit){
expOrfn.call(vModel);
}
this.watchs.map(function(data,index){
data.nodes.map(function(d,i){
if(self.isInit){
d.directive.init(newValue, d, data); //绑定初始化值, 以及初始化一些事件
}else{
d.directive.update(newValue, d, data); //只更新值,此时run的调用来值value-set
}
});
}); self.watchs = [];
},
push:function(watch){
this.watchs.push(watch);
}
} //任务管理

说明:

  1. Watch的push方法,用于依赖的添加,然后run来执行所以依赖,执行完成后,需要清理当前依赖的集合。在vue中依赖的收集是在dep中完成的,而watch提供的任务管理(不知道理解是否正确)

2. 指令的定义

directives.text = {
init: function(value, vNode){
vNode.elm.textContent = value;
},
update: function(value, vNode){
vNode.elm.textContent = value;
}
}
//需要响应事件的怎么办
directives.model ={
init: function(value, vNode, _watch){
vNode.elm.value = value; //判断自己发生的改变,不应该再改变自己
vNode.elm.addEventListener('keyup',function(evt){
vNode.model[_watch.key] = vNode.elm.value;
});
},
update:function(){ }
}

说明:

  1. 由于是demo学习示例,所以只定义了简单的text和model两个指定,text:用于数据的显示,而model用于input(输入框)的响应

3. vModel的生成

//转换vModel,暂支持一级
var properties = Object.getOwnPropertyNames(dataModel);
var vModel = {}, formSetting = false;
for( var index in properties){
(function refreshData(_index){
var key = properties[_index];
var property = Object.getOwnPropertyDescriptor(dataModel, key);
var setter = property.set;
var getter = property.get;
var _val = property.value;
var _getter = function(){
var val = getter ? getter.call(vModel) : _val;
//收集依赖,与watch要分开
Watch.push({
key: key,
nodes: vNodes.filter(function(data,index){
return data.modelKey == key ? true : false;
}),
getter: _getter
});
return val;
};
Object.defineProperty(vModel, key, {
configurable: true,
enumerable: true,
set: function(value){
if(setter){
setter.call(vModel, value);
}
//处理依赖
Watch.run(value, _getter);
//this.value = value;
},
get: _getter })
})(index);
}

说明:

  1. vModel是根据dataModel生成的,也就是自定义了每个属性的get和set方法,在es6中也可以用proxy实现(是否说对了)。
  2. 在属性set的时候,会先调用get方法来收集依赖。方便值改变后,能将所影响的内容都修改掉。

4. 解析dom为vNode

//解析vNodes
var app = document.getElementById('app');
app.childNodes.forEach(function(data,index){
if(data.nodeType != 1) return;
var hv = data.getAttribute('data-hv');
var hvs = hv.split(',');
hvs.forEach(function(item,row){
var keyValue = item.split(':'); //vNode对象上一定要有model,这是方便vNode相应时候的找vModel
vNodes.push({
directive: directives[keyValue[0]],
modelKey: keyValue[1],
model: vModel,
elm: data
});
});
});

说明:

  1. 这里说解析为vNode很是牵强,因为此只是收集了dom上data-hv指定的指令,并将对就的指令、元素、vModel等组成一个对象存储在vNodes中,以供vModel各属性的get方法收集依赖时引用。

5. 第一次初始化

//调用所有的get一次
Watch.isInit = true;
var _keys = Object.getOwnPropertyNames(vModel);
_keys.map(function(key,data){
var data = vModel[key];
Watch.run(data);
});
Watch.isInit = false;

说明:

  1. 将初始化的vModel的值渲染到Dom上,这里是主动执行每个的get,然后运行watch.run方法。
  2. 此处设计和实现本人感觉与vue的思路不对,如有高人看见,麻烦提点与指引。

6. 被解析的dom

<div id="app">
<span data-hv="text:title"></span>
<span data-hv="text:title"></span>
<input data-hv="model:title" />
</div>

对vue源码的初步认识和理解的更多相关文章

  1. VUE 源码学习01 源码入口

    VUE[version:2.4.1] Vue项目做了不少,最近在学习设计模式与Vue源码,记录一下自己的脚印!共勉!注:此处源码学习方式为先了解其大模块,从宏观再去到微观学习,以免一开始就研究细节然后 ...

  2. Vue源码后记-其余内置指令(3)

    其实吧,写这些后记我才真正了解到vue源码的精髓,之前的跑源码跟闹着玩一样. go! 之前将AST转换成了render函数,跳出来后,由于仍是字符串,所以调用了makeFunction将其转换成了真正 ...

  3. Vue源码后记-钩子函数

    vue源码的马拉松跑完了,可以放松一下写点小东西,其实源码讲20节都讲不完,跳了好多地方. 本人技术有限,无法跟大神一样,模拟vue手把手搭建一个MVVM框架,然后再分析原理,只能以门外汉的姿态简单过 ...

  4. 大白话Vue源码系列(01):万事开头难

    阅读目录 Vue 的源码目录结构 预备知识 先捡软的捏 Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的 ...

  5. 大白话Vue源码系列(02):编译器初探

    阅读目录 编译器代码藏在哪 Vue.prototype.$mount 构建 AST 的一般过程 Vue 构建的 AST 题接上文,上回书说到,Vue 的编译器模块相对独立且简单,那咱们就从这块入手,先 ...

  6. 大白话Vue源码系列(03):生成AST

    阅读目录 AST 节点定义 标签的正则匹配 解析用到的工具方法 解析开始标签 解析结束标签 解析文本 解析整块 HTML 模板 未提及的细节 本篇探讨 Vue 根据 html 模板片段构建出 AST ...

  7. 大白话Vue源码系列(03):生成render函数

    阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...

  8. 大白话Vue源码系列(04):生成render函数

    阅读目录 优化 AST 生成 render 函数 小结 本来以为 Vue 的编译器模块比较好欺负,结果发现并没有那么简单.每一种语法指令都要考虑到,处理起来相当复杂.上篇已经生成了 AST,本篇依然对 ...

  9. 大白话Vue源码系列(05):运行时鸟瞰图

    阅读目录 Vue 实例的生命周期 实例创建 响应的数据绑定 挂载到 DOM 节点 结论 研究 runtime 一边 Vue 一边源码 初看 Vue 是 Vue 源码是源码 再看 Vue 不是 Vue ...

随机推荐

  1. js浮点数的加减乘除

    ;(function(root, factory) { // Support AMD if (typeof define === 'function' && define.amd) { ...

  2. java时间处理,获取当前时间的小时,天,本周周几,本周周一的日期,本月一号的日期

    1.时间转时间戳 public static long strToTimestamp(String dateTimeStr) throws Exception { Timestamp time = T ...

  3. DOS批处理中对含有特殊字符的文件名的处理方法

    从一些网站下载的文件,文件名带有广告,典型的就是网站的名称和域名,搞得文件名很长.在一些场景下,广告看得见,真正的文件名却被...了.在以前,我是遇到就手工去掉广告,但一是麻烦,二是效率低.反正经常下 ...

  4. WPF中的ObservableCollection数据绑定

    使用时ObservableCollection必须使用get set属性声明,才能成功的绑定到控件.

  5. KMP性质小结

    跪拜_Blackjack_神犇

  6. Linux结束进程到底有多少种方法?

    我们经常在Linux里使用kill命令来结束某后台进程.但kill命令实际上是向进程发送信号,并且有多种信号.终止运行一个程序只是其中一个信号而已.kill是根据进程号发送信号的,而另一个工具kill ...

  7. python练习题目

    1.查看本机安装python版本 2.用python打印"Hello World",给出源代码和执行结果 a.命令行窗口输出(前提:python程序加入PATH系统环境变量) b. ...

  8. window下如何使用文本编辑器(如记事本)创建、编译和执行Java程序

    window下如何使用文本编辑器(如记事本)创建Java源代码文件,并编译执行 第一步:在一个英文目录下创建一个 .text 文件 第二步:编写代码 第三步:保存文件 方法一:选择 文件>另存为 ...

  9. C# datatable 重新排序

    DataTable table = distributionManageService.Tb_fund_withdrawaGetPageList(pagination, queryJson);//设置 ...

  10. MySQL之爱之初体验

    写在前言:本篇博客从mysql的安装开始说起,至于什么是数据库以及数据的由来什么的,不在详谈!!! 第一:mysql安装 linux安装:两种方式 1.apt安装 apt install mysql- ...