• 周六. 10月 8th, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

基于vue 看mvvm 框架设计基本思路

admin

11月 28, 2021

MVVM(model<->viewmodel<->view)

数据双向绑定(data-binding)是mvvm的核心思想,View 和 Model 之间没有联系,通过 ViewModel 进行交互。用户操作 View,ViewModel 感知到变化,通知 Model 发生相应改变;反之当 Model 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。

 

vue mvvm基本流程

 模板引擎 生成render函数(首次渲染), 响应式 (reactive data)监听数据改变,触发 渲染(render函数调用)

 

1.通过模板生成render函数

<div id='app'>
    <p>{{age}}</p>  
</div>


<script src="https://cdn.jsdelivr.net/npm/vue"></script>
    <script type="text/javascript">
        var vm = new Vue({
        el:'#app',
        data: {
              age:18
        }
  })
  </script>


//此模板生成的render函数体如下:
with(this) {//this即vm
    return _c(
        'div',
        {
            attrs:{"id":"app"}
        },
        [
            _c('p',[_v(_s(age))])//age即this.age,即vm.age,即data中的age;_c 即 this._c,即vm._c
        ]
    )
}
  •   _ c:创建html标签的方法。类似createElement,生成的是vnode, 
  •     – _v:创建文本的vnode。对应源码中的方法createTextVNode
  •     – _s:转字符串的方法

 生成html

   render 函数生成的是vnode,vnode 转html, 参考snabbdom中的patch

响应式

  通过es6 proxy  拦截 set和get方法实现监听,然后在set方法 触发trigger 实现re-render。

  

//多层递归监听
const defaultData = { a1: { a2: 1, }, }; function createGetter(data){ return new Proxy(data, { get: function(target, prop, receiver) { const res = Reflect.get(target, prop, receiver); console.log('get', res); if (typeof a === 'object') { return createGetter(res); } return res; }, set: function(target, prop, value, receiver) { console.log('set', prop, value); // 缺省行为时返回默认操作 return Reflect.set(target, prop, value, receiver); }, }); } const obj = createGetter(defaultData); obj.a1.a2 = 2; // get {a2: 1} // set a2 2

  

Virtual DOM

  Virtual DOM是用JavaScript模拟DOM结构

<ul id='list'>
  <li class='item'>Item 1</li>
  <li class='item'>Item 2</li>
  <li class='item'>Item 3</li>
</ul>

//对应的JavaScript写法
var element = {
  tagName: 'ul', // 节点标签名
  props: { // DOM的属性,用一个对象存储键值对
    id: 'list'
  },
  children: [ // 该节点的子节点
    {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]},
    {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]},
  ]
}

  

Diff算法

diff是Linux的基础命令,git中也有,是一个独立的算法。Virtual DOM里面用到了diff算法比较节点更新

开始经典的深度优先遍历DFS算法,其复杂度为O(n^3),存在高昂的diff成本,然后是cito.js的横空出世,它对今后所有虚拟DOM的算法都有重大影响。它采用两端同时进行比较的算法,将diff速度拉高到几个层次。紧随其后的是kivi.js,在cito.js的基出提出两项优化方案,使用key实现移动追踪及基于key的编辑长度距离算法应用(算法复杂度 为O(n^2))。但这样的diff算法太过复杂了,于是后来者snabbdom将kivi.js进行简化,去掉编辑长度距离算法,调整两端比较算法。速度略有损失,但可读性大大提高。再之后,就是著名的vue2.0 把snabbdom整个库整合掉了。

 

发表回复

您的电子邮箱地址不会被公开。