如何使用代理来实现一个简单而完整的MVVM库示例代码
前言
MVVM是必不可少的模式(相关框架如react、vue、angular等。)在当前时代的前端日常业务发展。使用MVVM可以将开发人员的精力集中在业务逻辑上,而不是如何操作dom。虽然现在已经9012了,mvvm相关原理的介绍也泡汤了,但是为了学习基础知识(代理实现的vue3.0还在开发中),参考了之前vue.js的整体思路后,我自己实现了一个简单的代理实现的mvvm。
本项目代码已在github开放,项目正在不断完善中。欢迎交流学习。喜欢请点一颗星!最终效果
html body div id=' app ' div { { title } }/div/div/body/html import MVVM来自' @ Fe _ korey/mvvm ';新MVVM({ view : document . getelementbyid(' app '),model : { title : ' hello mvvm!'},mounted() {console.log('主程序已编译,欢迎来到MVVM!');}});结构概述
组件模块实现解析和收集指令,初始化view Observer模块实现数据监控,包括添加订阅者和通知订阅者Parser模块实现解析指令,提供更新指令视图的更新方法,Watcher模块实现建立指令和数据的关联,Dep模块实现订阅中心,负责收集, 触发数据模型各值订阅列表的过程如下:compiles收集编译指令后,根据不同的指令选择不同的解析器,并根据Watcher中解析器订阅数据的变化更新初始视图。 观察者监视数据变化,然后通知观察者,观察者通知相应解析器中的更新刷新函数刷新视图。
详细的模块说明
依从者
整个数据模型数据被传输到观察者模块进行数据监控
这个。$data=新观察者(option.model)。getData();循环遍历整个dom,扫描并提取每个dom元素的所有指令
函数collectDir(element){ const children=element . childnodes;const children len=children . length;for(设I=0;一、童装;I){ const node=children[I];const nodeType=node.nodeTypeif (nodeType!==1 nodeType!==3) {继续;} if (hasDirective(node)) { this。$queue.push(节点);} if (node.hasChildNodes()!hasLateCompileChilds(节点)){ collectDir(元素);}}}编译每条指令并选择相应的Parser
const parser=this . selectparser({ node,dirName,dirValue,cs : this });将获得的解析器传递到Watcher,并初始化dom节点的视图
const watcher=new Watcher(解析器);parser . update({ new val : watcher . value });解析完所有指令后,触发MVVM编译完成回调$ mounted()
这个。$ mounted();使用document fragment document . createdocument fragment()而不是real dom节点片段,然后在编译完所有指令后将文档片段追加回real dom节点。
让孩子;const fragment=document . createdocumentfragment();while ((child=this。$ element . first child)){ fragment . appendchild(child);}//解析后,这。$ element.appendchild(片段);删除$ fragment句法分析程序
选择不同的监听解析器解析指令compiler by Component模块,目前包括类解析器、显示解析器、For解析器、IfParser、样式解析器、文本解析器、模型解析器、OnParser、其他解析器等解析模块。
switch(name){ case ' text ' : parser=new TextParser({ node,dirValue,cs });打破;case ' style ' : parser=new style parser({ node,dirValue,cs });打破;case ' class ' : parser=new class parser({ node,dirValue,cs });打破;case ' for ' : parser=new for arser({ node,dirValue,cs });打破;case 'on':解析器=new OnParser({ node,dirName,dirValue,cs });打破;case ' display ' : parser=new display parser({ node,dirName,dirValue,cs });打破;case ' if ' : parser=new IfParser({ node,dirValue,cs });打破;case ' model ' : parser=new model parser({ node,dirValue,cs });打破;default : parser=new other parser({ node,dirName,dirValue,cs });}不同的解析器提供不同的视图刷新函数update()来通过update更新dom视图
//text . jsfunction update(NewVal){ this . El . text content=_ toString(NewVal);}OnParser解析事件绑定,对应于数据模型中的methods字段
//详见https://github.com/zhaoky/mvvm/blob/master/src/core/parser/on . tsel . addeventlistener(handler type,e={handlerfn (scope,e))。});ForParser解析数组
详见https://github.com/zhaoky/mvvm/blob/master/src/core/parser/for . ts
ModelParser解析双向绑定,目前在四种情况下支持双向绑定和双绑定原则:输入[文本/密码] textarea,输入[单选],输入[复选框]并选择:
使用数据更改更新表单:与更新视图的其他指令一样,通过Update方法更新表单的值
函数更新({ NewVal }){ this . model . El . value=_ ToString(NewVal);}表单变更更新数据:监控输入、变更等表单变更事件,并在回调中设置数据模型
this . model . El . addeventlistener(' input ',e={ model . watcher . set(e . target . value);});观察者
MVVM模型的核心是通过Object.defineProperty的get和set方法监控数据,在get中添加订阅者,并通知订阅者更新set中的视图。在这个项目中,代理用于监控数据,它有三个优点:
代理可以直接监听对象而不是属性
代理可以直接监控数组的变化
代理最多有13种拦截方法,请参考
缺点是兼容性,不能用polyfill抹平。查找兼容性
请注意,代理将只监听其自身的每个属性。如果属性是一个对象,该对象将不会被监听,因此它需要递归监听
设置侦听后,返回一个代理,而不是原始数据对象
Varproxy=newproxy(数据,{get: function (target,key,receiver){//Add subscriber dep . adddep(curWatcher))如果条件满足;return Reflect.get(目标、键、接收器);},set:function (target,key,value,receiver){//如果条件满足,通知订阅者dep . not fiy();返回Reflect.set(目标、键、值、接收器);}});看守人
在Componenter模块中,每个解析后的Parser的指令都直接绑定到数据模型,并且会触发Observer的get监控来添加一个Watcher
这个。_ getter(this . parser . DirValue)(this . scope | | this . parser . cs . $ data);当数据模型改变时,它将触发-观察者的集合监听-Dep的notfiy方法(通知订阅者所有订阅列表)-执行订阅列表中所有观察者的更新方法-执行相应解析器的更新-完成视图更新
Watcher中的set方法用于设置双向绑定值,注意访问级别
资料执行防止
收集数据模型的每个属性的订阅列表的MVVM订阅中心包括添加订阅者、通知订阅者等。该方法本质上是发布/订阅模式,classdep {constructor () {this。dependlist=[];} addDeP(){ this . DependList . push(DeP);} not fiy(){ this . dependlist . foreach(item={ item . update();});}}后记
目前,mvvm项目只实现了数据绑定和视图更新功能。通过这个简单轮子的实现,对dom操作、代理、发布和订阅模式等一些基础知识进行了重新理解,找到了差距。同时也欢迎大家一起讨论交流,以后会继续改进!
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。
版权声明:如何使用代理来实现一个简单而完整的MVVM库示例代码是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。