热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浅易mvvm库的设想完成

媒介mvvm形式即model-view-viewmodel形式简称,单项双向数据绑定的完成,让前端开发者们从冗杂的dom事宜中摆脱出来,很轻易的处置惩罚数据和ui之间的联动。本文将
媒介

mvvm形式即model-view-viewmodel形式简称,单项/双向数据绑定的完成,让前端开发者们从冗杂的dom事宜中摆脱出来,很轻易的处置惩罚数据和ui之间的联动。
本文将从vue的双向数据绑定入手,理会mvvm库设想的中心代码与思绪。

需求整顿与剖析

整顿

  • 数据一旦转变则更新数据对应的ui

  • ui转变则触发事宜转变ui对应的数据

剖析

  • 经由过程dom节点的指令猎取革新函数,用来革新指定的ui。

  • 完成一个桥接的要领,让革新函数和须要的数据关联起来

  • 监听数据变化,数据转变后经由过程桥接要领挪用革新函数

  • ui转变触发对应的dom事宜在转变特定的数据

完成思绪
  • 完成observer,从新定义data,为data上每一个属性增添setter,getter以监听数据的变化

  • 完成compile,扫描模版template,提取每一个dom节点中的指令信息

  • 完成directive,经由过程指令信息是实例化对应的directive实例,差别范例的directive具有差别的革新函数update

  • 完成watcher,让observer的属性监听函数与directive的update函数做一一对应,以完成数据变化后更新视图

模块分别

MVVM现在分别为observer,compile,directive,watcher四个模块

数据监听模块observer

经由过程es5范例中的object.defineProperty体式格局完成对数据的监听
完成思绪:
递归遍历data,将data下面一切属性都加上set,get要领,以完成对一切属性的阻拦.
注重:对象能够含有数组属性,数组的内置有push,pop,splice等要领转变内部数据.
此时做法是转变数组的原型链,在原型链中增添一层自定义的push,pop,splice要领做阻拦,这些要领内里加上我们本身的回调函数,然后在挪用原生的push,pop,splice等要领.
详细能够看我上一篇文章js对象监听完成
observer.js代码

export function Observer(obj) {
this.$observe = function(_obj) {
var type = Object.prototype.toString.call(_obj);
if (type == '[object Object]') {
this.$observeObj(_obj);
} else if (type == '[object Array]') {
this.$cloneArray(_obj);
}
};
this.$observeObj = function(obj) {
var t = this;
Object.keys(obj).forEach(function(prop) {
var val = obj[prop];
defineProperty(obj, prop, val);
if (prop != '__observe__') {
t.$observe(val);
}
});
};
this.$clOneArray= function(a_array) {
var ORP = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
var arrayProto = Array.prototype;
var newProto = Object.create(arrayProto);
ORP.forEach(function(prop) {
Object.defineProperty(newProto, prop, {
value: function(newVal) {
var dep = a_array.__observe__;
var re=arrayProto[prop].apply(a_array, arguments);
dep.notify();
return re;
},
enumerable: false,
configurable: true,
writable: true
});
});
a_array.__proto__ = newProto;
};
this.$observe(obj, []);
}
var addObserve = function(val) {
if (!val || typeof val != 'object') {
return;
}
var dep = new Dep();
if (isArray(val)) {
val.__observe__ = dep;
return dep;
}
}
export function defineProperty(obj, prop, val) {
if (prop == '__observe__') {
return;
}
val = val || obj[prop];
var dep = new Dep();
obj.__observe__ = dep;
var childDep = addObserve(val);
Object.defineProperty(obj, prop, {
get: function() {
var target = Dep.target;
if (target) {
dep.addSub(target);
if (childDep) {
childDep.addSub(target);
}
}
return val;
},
set: function(newVal) {
if(newVal!=val){
val = newVal;
dep.notify();
}
}
});
}

编译模块compiler

完成思绪:
1.将模版template上的dom遍历一遍,将其存入文档碎片frag
2.遍历frag,经由过程attributes猎取节点的属性信息,在经由过程正则表达式过滤属性信息,进而拿到元素节点和文档节点的指令信息

var complieTemplate = function (nodes, model) {
if ((nodes.nodeType == 1 || nodes.nodeType == 11) && !isScript(nodes)) {
paserNode(model, nodes);
if (nodes.hasChildNodes()) {
nodes.childNodes.forEach(node=> {
complieTemplate(node, model);
})
}
}
}; var paserNode = function (model, node) {
var attributes = node.attributes || [];
var direct_array = [];
var scope = {
parentNode: node.parentNode,
nextNode: node.nextElementSibling,
el: node,
model: model,
direct_array: direct_array
};
attributes = toArray(attributes);
var textCOntent= node.textContent;
var attrs = [];
var vfor;
attributes.forEach(attr => {
var name = attr.name;
if (isDirective(name)) {
if (name == 'v-for') {
vfor = attr;
} else {
attrs.push(attr);
}
removeAttribute(node, name);
}
});
//bug nodeType=3
var textValue = stringParse(textContent);
if (textValue) {
attrs.push({
name: 'v-text',
value: textValue
});
node.textCOntent= '';
}
if (vfor) {
scope.attrs = attrs;
attrs = [vfor];
}
attrs.forEach(function (attr) {
var name = attr.name;
var val = attr.value;
var directiveType = 'v' + /v-(\w+)/.exec(name)[1];
var Directive = directives[directiveType];
if (Directive) {
direct_array.push(new Directive(val, scope));
}
});
};
var isDirective = function (attr) {
return /v-(\w+)/.test(attr)
};
var isScript = function isScript(el) {
return el.tagName === 'SCRIPT' && (
!el.hasAttribute('type') ||
el.getAttribute('type') === 'text/Javascript'
)
}

指令模块directive

  • 指令信息如:v-text,v-for,v-model等。

  • 每种指令信息须要的初始化行动以及指令的革新函数update都能够不一样,所以我们把它笼统出来零丁做一个模块。固然也有公用的如大众属性,一致的watcher实例化,unbind.

  • update函数则详细定义所属指令怎样衬着ui

如简朴的vtext指令的update函数以下:

vt.update = function (textContent) {
this.el.textCOntent= textContent;
};

结构图

《浅易mvvm库的设想完成》

数据定阅模块watcher

watcher的功用是让directive和observer模块关联起来。
初始化的时刻做两件事:

  • 将directive模块的update函数当参数传入,并将其存入本身update属性中

  • 挪用getValue,从而猎取对象data的特定属性值,进而触发一次之前在observer定义的属性函数的getter要领。

因为在defineProperty函数中定义的dep变量在setter和getter函数里有援用,使dep变量处于闭包状况没有开释,此时在getter要领中经由过程推断Depend.target的存在,来猎取定阅者watcher,经由过程发布者dep储存起来。
数据的每一个属性都有一个唯一的的dep变量,记录著一切定阅者watcher的信息,一旦属性有变化,挪用setter函数的时刻触发dep.notify(),关照一切已定阅的watcher,进而实行一切与该属性关联的革新函数,末了更新指定的ui。

watcher 初始化部份代码:

Depend.target = this;
this.value = this.getValue();
Depend.target = null;

observer.js 属性定义代码:

export function defineProperty(obj, prop, val) {
if (prop == '__observe__') {
return;
}
val = val || obj[prop];
var dep = new Dep();
obj.__observe__ = dep;
var childDep = addObserve(val);
Object.defineProperty(obj, prop, {
get: function() {
var target = Dep.target;
if (target) {
dep.addSub(target);
if (childDep) {
childDep.addSub(target);
}
}
return val;
},
set: function(newVal) {
if(newVal!=val){
val = newVal;
dep.notify();
}
}
});
}
流程图

简朴的流程图以下:
《浅易mvvm库的设想完成》

效果图

《浅易mvvm库的设想完成》

代码地点总结

本文基础对mvvm库的需求整顿,拆分,以及对拆分模块的一一完成来到达团体双向绑定功用的完成,固然现在市场上的mvvm库功用绝不止于此,本文只是略举个人认为的中心代码。
假如思绪和完成上的题目,也请列位指正,感谢浏览!


推荐阅读
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • ASP.NET2.0数据教程之十四:使用FormView的模板
    本文介绍了在ASP.NET 2.0中使用FormView控件来实现自定义的显示外观,与GridView和DetailsView不同,FormView使用模板来呈现,可以实现不规则的外观呈现。同时还介绍了TemplateField的用法和FormView与DetailsView的区别。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • 合并列值-合并为一列问题需求:createtabletab(Aint,Bint,Cint)inserttabselect1,2,3unionallsel ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • Hibernate延迟加载深入分析-集合属性的延迟加载策略
    本文深入分析了Hibernate延迟加载的机制,特别是集合属性的延迟加载策略。通过延迟加载,可以降低系统的内存开销,提高Hibernate的运行性能。对于集合属性,推荐使用延迟加载策略,即在系统需要使用集合属性时才从数据库装载关联的数据,避免一次加载所有集合属性导致性能下降。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • Jquery 跨域问题
    为什么80%的码农都做不了架构师?JQuery1.2后getJSON方法支持跨域读取json数据,原理是利用一个叫做jsonp的概念。当然 ... [详细]
  • 本文讨论了将HashRouter改为Router后,页面全部变为空白页且没有报错的问题。作者提到了在实际部署中需要在服务端进行配置以避免刷新404的问题,并分享了route/index.js中hash模式的配置。文章还提到了在vueJs项目中遇到过类似的问题。 ... [详细]
author-avatar
D之phper
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有