MVP模式
P代表Presenter,与Controller有些类似,但是不同的是,在用户进行DOM修改操作时将通过View上的行为进行触发,然后将修改的通知告诉给Presenter来完成对Model与其他View的更新;而MVC模式下,用户的操作是直接通过Controller进行。
通常,Presenter与View的操作是双向绑定的,即View的操作会触发Presenter,Presenter的操作会触发View。
MVVM模式
MVVM是一种自动化的MVP框架,使用ViewModel代替Presenter,并使用ViewModel自动完成对数据Model的调用和模板内容的渲染。
当用户进行操作时,ViewModel会捕获数据变化,直接将变化反映到View层。在MVVM模式下,通过使用Directive来管理ViewModel的数据操作。
什么是Directive呢?例如模板数据的渲染和数据绑定可以通过q-html或q-click(不同框架前缀不同)等特殊的属性来控制完成,这些特殊的元素标签属性就是我们所说的Directive。
具体说来,Directive是指定,简单地说是自定义的执行函数。
有如下代码:
<form action="#" id="form"> <label for="text" q-html="label"></label> <input type="text" q-value="value" q-model="value" q-mydo="number | getValue"> <button q-on="click: submit"></button> </form> let viewModel = new VM({ $el: document.getElementById('form'), data:{ label:'用户名', value:'输入初始值', number:0 }, method:{ submit(){ //todo } }, directive:{ mydo(value){ console.log(value); } }, filter:{ getValue(){ return ++ value; } } });
代码解释:首先js会找到document.getElementById(‘form’)这个元素并开始扫描元素节点,对这个元素的属性节点attribute和所有子节点中的attribute进行遍历,一旦遍历到民名称中含有q-开头的属性,就认为是MVVM框架自定义的Directive,此时会执行相对应的操作。例如遍历到q-html="label"时,就将ViewModel初始化时默认的数据对象data中的label值赋予这个元素的innerHtml,遍历到q-on="click: submit"时,就在这个元素上绑定click事件,事件触发的函数为submit;而自定义的q-mydo指令,当遍历到该节点的q-mydo属性时,调用Directive中的mydo方法,输入参数为data中getValue方法的返回值。用户在View层操作时会自定改变ViewModel的数据,然后ViewModel会检测数据的变化,重新遍历扫描节点属性,执行对应的Directive。
数据变更检测方法
- 手动触发绑定
通过在数据对象上定义get()方法和set()方法,调用时手动触发get()或set()函数来获取、修改数据,改变数据后会主动触发get()和set()函数中View层的重新渲染功能。
- 脏检测
在ViewModel对象的某个属性值发生变化时找到与这个属性值相关的所有元素,然后再比较数据变化,如果变化则进行Directive指令调用,对这个元素进行重新扫描渲染。与手动绑定不同的是,脏检测只针对可能修改的元素进行扫描,从而提高ViewModel内容变化后扫描视图并渲染的效率。
- 数据劫持
使用Object.defineProperty
和 Object.defineProperies
对ViewModel数据对象进行属性get()和Set()的监听,当有数据读取和赋值操作时,则扫描节点,运行指定对应节点的Directive指令。
- ES6 Proxy
用于在已有的对象基础上重新定义一个对象,并重新定义对象原型上的方法,包括get()和set()方法。