美文网首页
MVVM原理解析1

MVVM原理解析1

作者: 增商 | 来源:发表于2019-12-26 20:30 被阅读0次

总结,第一步,确定到底有没有挂载点的模板给它编译
第二步,把模板编译一个一个的生成内存中的dom树
第三步,vm传过来的值指向data

第一步

拿到当前模板是第一步 这只是截图更形象的看到工程结构当前就两个文件,一个js一个html,后面会附代码

图片.png
图片.png
图片.png

代码

//body中即可
  <div id="app">
      <input v-model="school.name" type="text" />
      <div>{{school.name}}</div>
      <div>{{school.age}}</div>
      <ul>
        <li>1</li>
        <li>1</li>
      </ul>
    </div>

    <script src="MVVM.js"></script>
    <script>
    var vm = new Vue({
      el: '#app',
      data: {
        school:{
          name:"imycode",
          age:10
        }
      },
      methods: {},
      computed: {
        
      },
    });
//MVVM
//基础类
class Compiler {
  constructor(el, vm) {
    //判断el属性是不是一个元素,如果不是元素那就获取他
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    console.log(this.el);
  }
  isElementNode(node) {
    //是不是元素节点
    return node.nodeType === 1;
  }
}

class Vue {
  constructor(options) {
    //this.$el $data $options
    this.$el = options.el;
    console.log("options.el:  " + options.el);

    this.$data = options.data;
    console.log("options.data:  " + options.data);

    //这个元素存在编译模板
    if (this.$el) {
      new Compiler(this.$el, this);
    }
  }
}

第二步(把获取到的当前节点中的元素放到内存)

把当前模板进行编译Why?为什么要内存编译,追求性能,要做数据和dom双向绑定,如果不全部放到内存里,那么只有一个出路就是看到一个匹配一个这样的速度就慢了

图片.png
图片.png

对应代码

    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    // console.log(this.el); //dom节点
    let fragment = this.node2fragment(this.el);
  }
  //把节点移动到内存中
  node2fragment(node) {
    //把当前元素中的东西都拿到
    //一个一个拿childnode儿子节点,都拿到
    let fragment = document.createDocumentFragment();
    //创建一个文档碎片
    let firstChild;
    while ((firstChild = node.firstChild)) {
      //拿一个少一个不用担心死循环
      //appendChild具有移动性
      fragment.appendChild(firstChild);
    }
    return fragment;
  }
//放到isElementNode判断是否是元素的上面
图片.png

☠注意

createDocumentFragment()
内存中就有所有节点了,当然在内存中操作好之后再渲染给文档

图片.png
图片.png
图片.png

☠注意==>重绘和回流

第一次拿的是文本类节点文本节点,拿完之后代码会被压缩,第二次就拿的是input

图片.png
第三步

数据驱动拿到子节点=>找和数据有关系的比如{{xx}} v-model等等

图片.png
图片.png
图片.png
注意:节点text是一个文本最后一个也有文本,不包含ul下面的li
判断元素还是文本
图片.png
图片.png
图片.png
加了问号,正则,问号?❓就会匹配到下一个}截至
//基础类
class Compiler {
  constructor(el, vm) {
    // console.log(el);
    this.vm = vm;
    //判断el属性是不是一个元素,如果不是元素那就获取他
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    // console.log(this.el); //dom节点
    let fragment = this.node2fragment(this.el);
    // console.log(fragment);
    //再内存中处理好
    //节点的内容进行替换

    //编译模板数据驱动
    this.compile(fragment);
    //然后再渲染给页面
    this.el.appendChild(fragment);
  }
  //编译文本的-看看有没{}
  isDirective(attrName) {
    return attrName.startsWith("v-");
  }
  compileText(node) {
    //{{xxx}} {{aaa}}
    let content = node.textContent;
    // console.log(content, "内容");
    if (/\{\{(.+?)\}\}/.test(content)) {
      // console.log(content); //找到所有文本元素开始填充
      CompileUtil["text"](node, content, this.vm);
    }
  }
  //编译元素的-看看有没v-model
  compileElement(node) {
    //取dom元素的属性
    let attributes = node.attributes; //类数组
    // console.log(attributes);
    //判断这些属性里有没有v-model的如果有我就找到了
    [...attributes].forEach(attr => {
      //v-model="school.name" type="text"
      // console.log(attr);
      let { name, value: expr } = attr;
      //结构  - v-model="school.name"
      // console.log(name, value);
      //判断name是不是v-开头的,是不是指令
      if (this.isDirective(name)) {
        let [, directive] = name.split("-");
        // console.log(node, "element");
        //找到了
        CompileUtil[directive](node, expr, this.vm);
        //需要调用不同的指令来处理 - v-model="school.name"
      }
    });
  } //核心的编译方法
  compile(node) {
    //用来编译内存中的dom节点
    let childNodes = node.childNodes;
    // console.log(childNodes);
    [...childNodes].forEach(child => {
      //是不是元素,不是元素就是文本
      //元素有v-model 文本有{{...}}
      if (this.isElementNode(child)) {
        // console.log("element  ", child);
        this.compileElement(child);
        // 如果是元素的话再去遍历子节点
        this.compile(child);
      } else {
        // console.log("text  ", child);
        this.compileText(child);
      }
    });
  }
  //把节点移动到内存中
  node2fragment(node) {
    //把当前元素中的东西都拿到
    //一个一个拿childnode儿子节点,都拿到
    let fragment = document.createDocumentFragment();
    //创建一个文档碎片
    let firstChild;
    //node指最外层的div#app
    while ((firstChild = node.firstChild)) {
      //不停拿第一个塞到内存最后页面中的节点都没有了就为null循环自然结束
      //拿一个少一个不用担心死循环
      //appendChild具有移动性
      console.log(firstChild);

      fragment.appendChild(firstChild);
    }
    return fragment;
  }
  isElementNode(node) {
    //是不是元素节点
    return node.nodeType === 1; //undefined===1? 不相等
  } //=>#app false
}

//编译工具
CompileUtil = {
  getVal(vm, expr) {
    //vm.$data 'school.name' 根据表达式取到最终的数据
    return expr.split(".").reduce((data, current) => {
      return data[current];
    }, vm.$data);
  },
  model(node, expr, vm) {
    //给输入框赋予value属性 node.value=xx
    // vm[expr]=vm.$data['...']错误
    let fn = this.updater["modelUpdater"];
    let value = this.getVal(vm, expr); //返给我imycode
    fn(node, value);
  }, //node节点expr表达式school.name, vm当前实例
  html() {
    //node.innerHTML=xx
  },
  text(node, expr, vm) {
    let fn = this.updater["textUpdater"];
    //expr=>{{a}} {{b}} {{c}}
    let content = expr.replace(/\{\{(.+?)\}\}/g, (...args) => {
      return this.getVal(vm, args[1]);
    });
    //最终文本内容
    fn(node, content);
  },
  updater: {
    //把数据插入到节点中
    modelUpdater(node, value) {
      node.value = value;
    },
    htmlUpdater() {},
    //处理文本节点
    textUpdater(node, value) {
      node.textContent = value;
    }
  }
};
class Vue {
  constructor(options) {
    //this.$el $data $options
    this.$el = options.el;
    // console.log("options.el:  " + options.el);

    this.$data = options.data;
    // console.log("options.data:  " + options.data);

    //这个根元素存在编译模板
    if (this.$el) {
      new Compiler(this.$el, this);
    }
  }
}

前三步合集,取到数据渲染页面但是是单项的


相关文章

  • MVVM原理解析1

    总结,第一步,确定到底有没有挂载点的模板给它编译第二步,把模板编译一个一个的生成内存中的dom树第三步,vm传过来...

  • 学习清单

    HTTP原理解析 RxJava使用和原理,并应用到BaseLib库,还有Dragger MVVM 多线程和线程池使...

  • 数据代理 、 模板解析、 数据绑定

    7.1. 说明 1)分析 vue 作为一个 MVVM 框架的基本实现原理 数据代理 模板解析 数据绑定 2)不直接...

  • Vue的34道题

    1、如何理解MVVM原理? MVVM的实现原理 2、响应式数据的原理是什么? 响应式数据与数据依赖基本原理vue双...

  • 解构赋值-MVVM原理解析1.2_12-27

    接着昨天mvvm原理解析1后面的数据并未实现双向绑定看以看到的是图片.png我们需要监控数据改变=>数据劫持,我们...

  • vue的mvvm原理解析及手写一个

    # 手写vue的mvvm实现原理 ## 1:mvc和mvvm的区别? MVC:modal-view-control...

  • MVVM原理解析下

    首先看效果截图图片.png 这里需要注意的是,现在只做到了数据驱动视图,视图无法更改model

  • 2019-10-31

    手写vue的mvvm实现原理 1:mvc和mvvm的区别? MVC:modal-view-controller,比...

  • xml解析

    一、解析方式:DOM解析,SAX解析 1)解析工具 基于DOM解析原理的: 1)JAXP (o...

  • iOS架构篇-4 架构模式MVVM

    @[TOC](iOS架构篇-4 架构模式MVVM) MVVM原理 MVVM(Model–View–Viewmode...

网友评论

      本文标题:MVVM原理解析1

      本文链接:https://www.haomeiwen.com/subject/sreloctx.html