浅析vue中的MVVM实现原理


Posted in Javascript onMarch 04, 2019

现成MVVM

菜单教程

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>

<body>
  <div id="app">
    <input type="text" v-model="message">
    <p>{{ message }}</p>
  </div>

  <script>
    let vm = new Vue({
      el: '#app',
      data: {
        message: 'Hello Vue.js!'
      }
    })
  </script>
</body>

</html>

视图影响数据

浅析vue中的MVVM实现原理

数据影响视图

浅析vue中的MVVM实现原理

项目构架

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>

</body>

</html>
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
  <script src="./js/mvvm.js"></script>
  <script src="./js/compile.js"></script>
</head>

<body>
  <div id="app">
    <input type="text" v-model="message">
    <div>{{message}}</div>
    <ul>
      <li></li>
    </ul>
    {{message}}
  </div>

  <script>
    let vm = new MVVM({
      el: '#app',
      data: {
        message: 'Hello Vue.js!'
      }
    })
  </script>
</body>

</html>

mvvm.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>

</body>

</html>
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
  <script src="./js/mvvm.js"></script>
  <script src="./js/compile.js"></script>
</head>

<body>
  <div id="app">
    <input type="text" v-model="message">
    <div>{{message}}</div>
    <ul>
      <li></li>
    </ul>
    {{message}}
  </div>

  <script>
    let vm = new MVVM({
      el: '#app',
      data: {
        message: 'Hello Vue.js!'
      }
    })
  </script>
</body>

</html>

mvvm.js

class MVVM {
  constructor(options) {
    this.$el = options.el;
    this.$data = options.data;

    if (this.$el) {
      new Compile(this.$el);
    }

  }
}

compile把dom节点,放在内存中操作(到35分钟)

class Compile {
  constructor(el, vm) {
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    this.vm = vm;
    if (this.el) {
      let fragment = this.node2frament(this.el);
      this.compile(fragment);
    }
  }

  //辅助方法
  isElementNode(node) {
    return node.nodeType === 1;
  }

  //核心方法
  compile(fragment) {
    let childNodes = fragment.childNodes;
    console.log(childNodes)
  }
  node2frament(el) {
    let fragment = document.createDocumentFragment();
    let firstChild;
    while (firstChild = el.firstChild) {
      fragment.appendChild(firstChild);
    }
    return fragment
  }
}

分类元素节点和文本节点(52分钟)

class Compile {
  constructor(el, vm) {
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    this.vm = vm;
    if (this.el) {
      let fragment = this.node2frament(this.el);
      this.compile(fragment);
    }
  }

  //辅助方法
  isElementNode(node) {
    return node.nodeType === 1;
  }
  isDirective(name) {
    return name.includes('v-')
  }

  //核心方法
  compileElement(node) {
    let attrs = node.attributes;
    Array.from(attrs).forEach(arrt => {
      let attrName = attr.name;
      if (this.isDirective(attrName)) {
        let expr = attr.value;
      }
    })
  }
  compileText(node) {
    let text = node.textContent;
    let reg = /\{\{([^}]+)\}\}/g;
    if (reg.test(text)) {

    }
  }
  compile(fragment) {
    let childNodes = fragment.childNodes;
    Array.from(childNodes).forEach(node => {
      if (this.isElementNode(node)) {
        this.compile(node)
      } else {
        console.log('text', node)
      }
    })
  }
  node2frament(el) {
    let fragment = document.createDocumentFragment();
    let firstChild;
    while (firstChild = el.firstChild) {
      fragment.appendChild(firstChild);
    }
    return fragment
  }
}

元素节点

浅析vue中的MVVM实现原理

文本节点

浅析vue中的MVVM实现原理

把data中的数据,显示在视图上(到1:16分)

class Compile {
  constructor(el, vm) {
    this.el = this.isElementNode(el) ? el : document.querySelector(el);
    this.vm = vm;
    if (this.el) {
      let fragment = this.node2frament(this.el);
      this.compile(fragment);
      this.el.appendChild(fragment)
    }
  }

  //辅助方法
  isElementNode(node) {
    return node.nodeType === 1;
  }
  isDirective(name) {
    return name.includes('v-')
  }

  //核心方法
  compileElement(node) {
    let attrs = node.attributes;
    Array.from(attrs).forEach(attr => {
      let attrName = attr.name;
      if (this.isDirective(attrName)) {
        let expr = attr.value;
        let [, type] = attrName.split('-');
        CompileUtil[type](node, this.vm, expr)
      }
    })
  }
  compileText(node) {
    console.log(node)
    let expr = node.textContent;
    let reg = /\{\{([^}]+)\}\}/g;
    if (reg.test(expr)) {
      CompileUtil['text'](node, this.vm, expr)
    }
  }
  compile(fragment) {
    let childNodes = fragment.childNodes;
    Array.from(childNodes).forEach(node => {
      if (this.isElementNode(node)) {
        this.compileElement(node)
        this.compile(node)
      } else {
        this.compileText(node)
      }
    })
  }
  node2frament(el) {
    let fragment = document.createDocumentFragment();
    let firstChild;
    while (firstChild = el.firstChild) {
      fragment.appendChild(firstChild);
    }
    return fragment
  }
}


CompileUtil = {
  getVal(vm, expr) { // 获取实例上对应的数据
    expr = expr.split('.'); // [message,a]
    return expr.reduce((prev, next) => { // vm.$data.a
      return prev[next];
    }, vm.$data);
  },
  getTextVal(vm, expr) { // 获取编译文本后的结果
    return expr.replace(/\{\{([^}]+)\}\}/g, (...arguments) => {
      return this.getVal(vm, arguments[1]);
    })
  },
  text(node, vm, expr) { //文本处理
    let updateFn = this.updater['textUpdater'];
    let value = this.getTextVal(vm, expr);
    updateFn && updateFn(node, value)
  },

  model(node, vm, expr) {
    let updateFn = this.updater['modelUpdater'];
    updateFn && updateFn(node, this.getVal(vm, expr));
  },
  updater: {
    textUpdater(node, value) {
      node.textContent = value;
    },
    modelUpdater(node, value) {
      node.value = value;
    }
  }
}

v-model类型

modelUpdater(node, value) {
      node.value = value;
      console.log(node)
      console.log(value)
      console.log(node.value)
    }

浅析vue中的MVVM实现原理

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用jQuery向asp.net Mvc传递复杂json数据-ModelBinder篇
May 07 Javascript
Jquery Change与bind事件代码
Sep 29 Javascript
JS+DIV实现鼠标划过切换层效果的实例代码
Nov 26 Javascript
判断javascript的数据类型(示例代码)
Dec 11 Javascript
javascript实现点击提交按钮后显示loading的方法
Jul 03 Javascript
jQuery获取select选中的option的value值实现方法
Aug 29 Javascript
jQuery序列化后的表单值转换成Json
Jun 16 jQuery
基于Vue组件化的日期联动选择器功能的实现代码
Nov 30 Javascript
React 使用recharts实现散点地图的示例代码
Dec 07 Javascript
微信小程序实现获取小程序码和二维码java接口开发
Mar 29 Javascript
vue 解决数组赋值无法渲染在页面的问题
Oct 28 Javascript
如何通过vscode运行调试javascript代码
Jul 24 Javascript
JavaScript实现的九种排序算法
Mar 04 #Javascript
如何在JavaScript中优雅的提取循环内数据详解
Mar 04 #Javascript
iview tabs 顶部导航栏和模块切换栏的示例代码
Mar 04 #Javascript
Vuex mutitons和actions初使用详解
Mar 04 #Javascript
JS重学系列之聊聊new操作符
Mar 04 #Javascript
jQuery实现的导航条点击后高亮显示功能示例
Mar 04 #jQuery
ES10 特性的完整指南小结
Mar 04 #Javascript
You might like
php smarty 二级分类代码和模版循环例子
2011/06/01 PHP
朋友网关于QQ相关的PHP代码(研究QQ的绝佳资料)
2015/01/26 PHP
PHP实现阳历到农历转换的类实例
2015/03/07 PHP
PHP strip_tags保留多个HTML标签的方法
2016/05/22 PHP
PHP中的浅复制与深复制的实例详解
2017/10/26 PHP
php 的多进程操作实践案例分析
2020/02/28 PHP
这段js代码得节约你多少时间
2011/12/20 Javascript
jQuery 数据缓存模块进化史详细介绍
2012/11/19 Javascript
JS常用正则表达式总结
2013/11/12 Javascript
javascript实现数字倒计时特效
2016/03/30 Javascript
分享JS数组求和与求最大值的方法
2016/08/11 Javascript
前端弹出对话框 js实现ajax交互
2016/09/09 Javascript
JavaScript高仿支付宝倒计时页面及代码实现
2016/10/21 Javascript
浅谈Angularjs link和compile的使用区别
2016/10/21 Javascript
关于TypeScript中import JSON的正确姿势详解
2017/07/25 Javascript
JS实现简易换图时钟功能分析
2018/01/04 Javascript
Postman如何实现参数化执行及断言处理
2020/07/28 Javascript
uniapp实现可滑动选项卡
2020/10/21 Javascript
python中的yield使用方法
2014/02/11 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
Tensorflow使用tfrecord输入数据格式
2018/06/19 Python
python 多进程共享全局变量之Manager()详解
2019/08/15 Python
python-tornado的接口用swagger进行包装的实例
2019/08/29 Python
Python 列表的清空方式
2020/01/13 Python
20行Python代码实现一款永久免费PDF编辑工具的实现
2020/08/27 Python
Cpython解释器中的GIL全局解释器锁
2020/11/09 Python
沃尔玛加拿大:Walmart.ca
2020/03/02 全球购物
汉米尔顿手表官网:Hamilton
2020/09/13 全球购物
第二层交换机和路由器的区别?第三层交换机和路由器的区别?
2013/05/23 面试题
农场厂长岗位职责
2013/12/28 职场文书
高中历史教学反思
2014/02/08 职场文书
校园演讲稿汇总
2014/05/21 职场文书
西安大雁塔导游词
2015/02/10 职场文书
2015庆祝七一建党节94周年活动总结
2015/03/20 职场文书
2015年国庆节演讲稿范文
2015/07/30 职场文书
民间借贷纠纷起诉书
2015/08/03 职场文书