zoukankan      html  css  js  c++  java
  • 基于vue 看mvvm 框架设计基本思路

    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整个库整合掉了。

     

  • 相关阅读:
    spring5 源码深度解析----- Spring事务 是怎么通过AOP实现的?(100%理解Spring事务)
    spring5 源码深度解析----- @Transactional注解的声明式事物介绍(100%理解事务)
    spring5 源码深度解析----- AOP目标方法和增强方法的执行(100%理解AOP)
    spring5 源码深度解析----- AOP代理的生成
    spring5 源码深度解析----- 创建AOP代理之获取增强器
    spring5 源码深度解析----- AOP的使用及AOP自定义标签
    spring5 源码深度解析-----ApplicationContext容器refresh过程
    Netty源码分析 (十二)----- 心跳服务之 IdleStateHandler 源码分析
    Netty源码分析 (十一)----- 拆包器之LengthFieldBasedFrameDecoder
    Netty源码分析 (十)----- 拆包器之LineBasedFrameDecoder
  • 原文地址:https://www.cnblogs.com/breakdown/p/15159427.html
Copyright © 2011-2022 走看看