1. <!DOCTYPE html>
  2. <head>
  3. <meta charset="UTF-8" />
  4. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
  5. <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  6. <title>proxyVue</title>
  7. <style>
  8. #app {
  9. margin: 100px auto 0 auto;
  10. width: 300px;
  11. }
  12. #btn {
  13. margin: 10px auto;
  14. }
  15. </style>
  16. </head>
  17.  
  18. <body>
  19. <div id="app">
  20. <input type="text" v-model="num" />
  21. <input id="btn" type="button" value="添加到Todolist" v-click="addList" /><br />
  22. <span>您输入的是:</span><span v-bind="num"></span><span>{{num}}</span>
  23. <ul id="list"></ul>
  24. </div>
  25. </body>
  26.  
  27. <script>
  28. class proxyVue {
  29. constructor(options) {
  30. this.$options = options || {};
  31. this.$methods = this._methods = this.$options.methods;
  32. const data = (this._data = this.$options.data);
  33. this.subscribe = {};
  34. this.observe(data);
  35. this.compile(options.el);
  36. }
  37. publish(watcher) {
  38. if (!this.subscribe[watcher.property])
  39. this.subscribe[watcher.property] = [];
  40. this.subscribe[watcher.property].push(watcher);
  41. }
  42. observe(data) {
  43. const that = this;
  44. let handler = {
  45. get(target, property) {
  46. return target[property];
  47. },
  48. set(target, property, value) {
  49. let res = Reflect.set(target, property, value);
  50. that.subscribe[property].map(item => {
  51. item.update();
  52. });
  53. return res;
  54. }
  55. };
  56. this.$data = new Proxy(data, handler);
  57. }
  58. compile(el) {
  59. const nodes = Array.prototype.slice.call(
  60. document.querySelector(el).children
  61. );
  62. let data = this.$data;
  63. nodes.map(node => {
  64. if (node.children.length > 0) this._complie(node);
  65. if (node.hasAttribute("v-bind")) {
  66. let property = node.getAttribute("v-bind");
  67. this.publish(new Watcher(node, "innerHTML", data, property));
  68. }
  69. if (node.hasAttribute("v-model")) {
  70. let property = node.getAttribute("v-model");
  71. this.publish(new Watcher(node, "value", data, property));
  72. node.addEventListener("input", () => {
  73. data[property] = node.value;
  74. });
  75. }
  76. /**
  77. self ...
  78. */
  79. if (/\{\{(.*?)\}\}/.test(node.innerHTML)) {
  80. let ret = /\{\{(.*?)\}\}/.exec(node.innerHTML)
  81. let property = ret[1];
  82. this.publish(new Watcher(node, "innerHTML", data, property));
  83. }
  84. // self end
  85. if (node.hasAttribute("v-click")) {
  86. let methodName = node.getAttribute("v-click");
  87. let mothod = this.$methods[methodName].bind(data);
  88. node.addEventListener("click", mothod);
  89. }
  90. });
  91. }
  92. }
  93. class Watcher {
  94. constructor(node, attr, data, property) {
  95. this.node = node;
  96. this.attr = attr;
  97. this.data = data;
  98. this.property = property;
  99. }
  100. update() {
  101. this.node[this.attr] = this.data[this.property];
  102. }
  103. }
  104.  
  105. // 渲染todolist列表
  106. const Render = {
  107. // 初始化
  108. init: function (arr) {
  109. const fragment = document.createDocumentFragment();
  110. for (let i = 0; i < arr.length; i++) {
  111. const li = document.createElement("li");
  112. li.textContent = arr[i];
  113. fragment.appendChild(li);
  114. }
  115. list.appendChild(fragment);
  116. },
  117. addList: function (val) {
  118. const li = document.createElement("li");
  119. li.textContent = val;
  120. list.appendChild(li);
  121. }
  122. };
  123.  
  124. // 实例化一个proxyVue
  125. window.onload = function () {
  126. let vm = new proxyVue({
  127. el: "#app",
  128. data: {
  129. num: 0,
  130. arr: []
  131. },
  132. methods: {
  133. addList() {
  134. this.arr.push(this.num);
  135. // Render.addList(this.num);
  136. }
  137. }
  138. });
  139. };
  140. </script>
  141.  
  142. </html>

  

vue3双向数据绑定原理_demo的更多相关文章

  1. vue双向数据绑定原理探究(附demo)

    昨天被导师叫去研究了一下vue的双向数据绑定原理...本来以为原理的东西都非常高深,没想到vue的双向绑定真的很好理解啊...自己动手写了一个. 传送门 双向绑定的思想 双向数据绑定的思想就是数据层与 ...

  2. vue的双向数据绑定原理

    原理. vue是采用数据劫持结合发布者-订阅者模式的方式, 通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回 ...

  3. 深入vue源码,了解vue的双向数据绑定原理

    大家都知道vue是一种MVVM开发模式,数据驱动视图的前端框架,并且内部已经实现了双向数据绑定,那么双向数据绑定是怎么实现的呢? 先手动撸一个最最最简单的双向数据绑定 <div> < ...

  4. Vue双向数据绑定原理深度解析

    首先,什么是双向数据绑定?Vue是三大MVVM框架之一,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化. 在分析其原理和代码的时候,大家首先了解如下几个j ...

  5. Vue双向数据绑定原理分析(转)

    add by zhj: 目前组里使用的是前端技术是jQuery + Bootstrap,后端使用的Django,Flask等,模板是在后端渲染的.前后端没有分离,这种做法有几个缺点 1. 模板一般是由 ...

  6. 手写MVVM框架 之vue双向数据绑定原理剖析

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 16、前端知识点--Object.defineProperty 的用法+双向数据绑定原理解析

    一.Object.defineProperty 的用法 Object.defineProperty 可以用于给对象添加更新属性. <script> // Object.defineProp ...

  8. Vue双向数据绑定原理解析

    基本原理 Vue.采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter和getter,数据变动时发布消息给订阅者,触发相应函数的回调 ...

  9. Vue的双向数据绑定原理是什么?

    vue.js是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调. ...

随机推荐

  1. kubeadm方式搭建K8S集群

    一.kubeadm介绍 二.安装要求 三.集群规划 四.环境初始化(在每个服务器节点操作) 1.关闭防火墙 2.关闭selinux 3.关闭swap 4.根据规划设置主机名 5.在Master添加ho ...

  2. 测试开发【提测平台】分享9-DBUntils优化数据连接&实现应用搜索和分页功能

    微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. 从本期开始知识点讲以思维导图的形式给出,内容点会按照讲解-应用-展示的形式体现,这样会更清晰些. DBUntils连接池 在项目中链接数据 ...

  3. 判断input radio选中那个

    var _sex=$("input[name='sex']:checked").val(); if(_sex==null){ layer.msg("请选择性别" ...

  4. vue从mock数据过渡到使用后台接口

    说明: 最近在搭建一个前端使用vue-element-admin,后端使用springBoot的项目. 由于vue-element-admin使用的是mock的模拟数据跑起来的项目,所以在开发过程中难 ...

  5. RSA及其证明 [原创]

    描述RSA的实现步骤介绍文章非常多,但说明并证明其原理,并进而讨论为什么这样设计的文章不多.本人才疏学浅,不敢说理解了R.S.A.三位泰斗的设计初衷,简单就自己的理解写一写,博大家一笑. 以下原创内容 ...

  6. linux下分卷压缩,合并解压的3种方法

    我们上传东西的时候,由于文件过大而不能上传,或者不给上传,最明显的就是发邮件了,附件最大5M,有的10M.如果超过了就郁闷了.这个时候,如果能把压缩的东西,分割开来就比较爽了,windows下面我想大 ...

  7. 面试官:MySQL的幻读是怎么被解决的?

    大家好,我是小林. 我之前写过一篇数据库事务的文章「 事务.事务隔离级别和MVCC」,这篇我说过什么是幻读. 在这里插入图片描述 然后前几天有位读者跟我说,我这个幻读例子不是已经被「可重复读」隔离级别 ...

  8. easyx实现小球移动

    easyx是一个针对VC++编译器的图形化插件.使用它,可以使得在C++中编写图形程序. 小球移动代码: #include"stdafx.h" #include<graphi ...

  9. CSS linear-gradient() 函数

    用于背景颜色渐变或画线条等场景 linear-gradient() 函数用于创建一个表示两种或多种颜色线性渐变的图片. 创建一个线性渐变,需要指定两种颜色,还可以实现不同方向(指定为一个角度)的渐变效 ...

  10. Shell系列(2)- 脚本执行方式

    创建shell脚本 [root@localhost sh]# vim hello.sh  shell脚本必须用.sh,同时方便文件管理 #!/bin/bash:shell文件第一行必须是这个,声明这个 ...