vue双向数据绑定简易demo

  1 <!DOCTYPE html>
  2 <html lang="en">
  3   <head>
  4     <meta charset="UTF-8" />
  5     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  6     <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  7     <title>双向数据绑定demo</title>
  8   </head>
  9   <style>
 10     input {
 11       border: 1px solid #636336;
 12       margin-right: 10px;
 13     }
 14   </style>
 15   <body>
 16     <div id="app">
 17       <input type="text" v-model="text" />
 18       {{ text }}
 19     </div>
 20     <script>
 21       // 遍历data添加数据劫持
 22       function observe(obj, vm) {
 23         console.log(vm);
 24         Object.keys(obj).forEach(function(key) {
 25           defineReactive(vm, key, obj[key]);
 26         });
 27       }
 28       // 数据劫持
 29       function defineReactive(obj, key, val) {
 30         var dep = new Dep();
 31         Object.defineProperty(obj, key, {
 32           get: function() {
 33             // 添加订阅者 watcher 到主题对象 Dep
 34             if (Dep.target) {
 35               dep.addSub(Dep.target);
 36             }
 37             return val;
 38           },
 39           set: function(newVal) {
 40             if (newVal === val) return;
 41             val = newVal;
 42             // 作为发布者发出通知
 43             dep.notify();
 44           }
 45         });
 46       }
 47       // 劫持dom节点
 48       function nodeToFragment(node, vm) {
 49         var nodes = document.createDocumentFragment();
 50         var child;
 51         // appendChild 方法有个隐蔽的地方,就是调用以后 child 会从原来 DOM 中移除
 52         // 所以,第二次循环时,node.firstChild 已经不再是之前的第一个子元素了
 53         while (child = node.firstChild) {
 54           compile(child, vm);
 55           nodes.appendChild(child); // 将子节点劫持到文档片段中
 56         }
 57         /*let nodeList = node.childNodes;
 58         for (var i = 0; i < nodeList.length; i++) {
 59           compile(nodeList[i], vm);
 60           nodes.appendChild(nodeList[i]);
 61         }*/
 62         return nodes;
 63       }
 64       // 遍历节点,找出v-model和双花括号
 65       function compile(node, vm) {
 66         // 节点类型为元素
 67         if (node.nodeType === 1) {
 68           var attr = node.attributes;
 69           // 解析属性
 70           for (var i = 0; i < attr.length; i++) {
 71             if (attr[i].nodeName == ‘v-model‘) {
 72               var name = attr[i].nodeValue; // 获取 v-model 绑定的属性名
 73               node.addEventListener(‘input‘, function(e) {
 74                 // 给相应的data属性赋值,进而触发该属性的set方法
 75                 vm[name] = e.target.value;
 76               });
 77               node.value = vm[name]; // 将data的值赋给该node
 78               node.removeAttribute(‘v-model‘); // 移除v-model属性
 79             }
 80           }
 81           new Watcher(vm, node, name, ‘input‘); // 输入框节点
 82         }
 83         var reg = /\{\{(.*)\}\}/; // 匹配双花括号
 84         // 节点类型为文本内容
 85         if (node.nodeType === 3) {
 86           if (reg.test(node.nodeValue)) {
 87             var name = RegExp.$1; // 获取匹配到的字符串
 88             name = name.trim();
 89             new Watcher(vm, node, name, ‘text‘); // 展示节点
 90           }
 91         }
 92       }
 93       class Watcher {
 94         constructor (vm, node, name, nodeType) {
 95           Dep.target = this;
 96           this.name = name;
 97           this.node = node;
 98           this.vm = vm;
 99           this.nodeType = nodeType;
100           this.update();
101           Dep.target = null;
102         }
103         update () {
104           this.get();
105           if (this.nodeType === ‘text‘) {
106             this.node.nodeValue = this.value;
107           }
108           if (this.nodeType === ‘input‘) {
109             this.node.value = this.value;
110           }
111         }
112         // 获取 data 中的属性值
113         get () {
114           this.value = this.vm[this.name]; // 触发相应属性的 get
115         }
116       }
117       /*
118       // 观察者对象
119       function Watcher(vm, node, name, nodeType) {
120         Dep.target = this;
121         this.name = name;
122         this.node = node;
123         this.vm = vm;
124         this.nodeType = nodeType;
125         this.update();
126         Dep.target = null;
127       }
128       Watcher.prototype = {
129         update: function() {
130           this.get();
131           if (this.nodeType === ‘text‘) {
132             this.node.nodeValue = this.value;
133           }
134           if (this.nodeType === ‘input‘) {
135             this.node.value = this.value;
136           }
137         },
138         // 获取 data 中的属性值
139         get: function() {
140           this.value = this.vm[this.name]; // 触发相应属性的 get
141         }
142       };
143       */
144       class Dep {
145         constructor () {
146           this.subs = [];
147         }
148         addSub (sub) {
149           this.subs.push(sub);
150         }
151         notify () {
152           this.subs.forEach(function(sub) {
153             sub.update();
154           });
155         }
156       }
157       /*
158       function Dep() {
159         this.subs = [];
160       }
161       Dep.prototype = {
162         addSub: function(sub) {
163           this.subs.push(sub);
164         },
165         notify: function() {
166           this.subs.forEach(function(sub) {
167             sub.update();
168           });
169         }
170       };
171       */
172       // 创建Vue
173       function Vue(options) {
174         this.data = options.data;
175         var data = this.data;
176         observe(data, this);
177         var id = options.el;
178         var dom = nodeToFragment(document.getElementById(id), this);
179         // 编译完成后,将 dom 返回到 app 中
180         document.getElementById(id).appendChild(dom);
181       }
182       // 实例化Vue
183       var vm = new Vue({
184         el: ‘app‘,
185         data: {
186           text: ‘hello world‘
187         }
188       });
189     </script>
190   </body>
191 </html>

原文地址:https://www.cnblogs.com/xinsir/p/12161377.html

时间: 2024-11-10 12:26:04

vue双向数据绑定简易demo的相关文章

Vue双向数据绑定简易实现

一.vue中的双向数据绑定主要使用到了Object.defineProperty(新版的使用Proxy实现的)对Model层的数据进行getter和setter进行劫持,修改Model层数据的时候,在setter中可以知道对那个属性进行修改了,然后修改View的数据. 二.简易版双向数据绑定 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> &

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

昨天被导师叫去研究了一下vue的双向数据绑定原理...本来以为原理的东西都非常高深,没想到vue的双向绑定真的很好理解啊...自己动手写了一个. 传送门 双向绑定的思想 双向数据绑定的思想就是数据层与UI层的同步,数据再两者之间的任一者发生变化时都会同步更新到另一者. 双向绑定的一些方法 目前,前端实现数据双向数据绑定的方法大致有以下三种: 1.发布者-订阅者模式(backbone.js) 思路:使用自定义的data属性在HTML代码中指明绑定.所有绑定起来的JavaScript对象以及DOM元

angular和vue双向数据绑定

angular和vue双向数据绑定的原理(重点是vue的双向绑定) 我在整理javascript高级程序设计的笔记的时候看到面向对象设计那章,讲到对象属性分为数据属性和访问器属性,我们平时用的js对象90%以上都只是用到数据属性;我们向来讲解下数据属性和访问器属性到底是什么? 数据属性:数据属性包含一个数据值的位置,在这个位置可以读取和写入值. 访问器属性:访问器属性不包含数据值;他们包含一对getter和setter函数在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值,在写

vue 双向数据绑定的实现学习(二)- 监听器的实现

废话:上一篇https://www.cnblogs.com/adouwt/p/9928278.html 提到了vue实现的基本实现原理:Object.defineProperty() -数据劫持 和 发布订阅者模式(观察者),下面讲的就是数据劫持在代码中的具体实现. 1.先看如何调用 new一个对象,传入我们的参数,这个Myvue ,做了啥? 上面看到了在实例化一个Myvue 对象的时候,会执行init方法, init 方法做了两个事,调用了observer 方法,和 实例化调用了 compil

React 事件对象、键盘事件、表单事件、ref获取dom节点、react实现类似Vue双向数据绑定

1.案例实现代码 import React, { Component } from 'react'; /** * 事件对象.键盘事件.表单事件.ref获取dom节点.react实现类似Vue双向数据绑定 * 事件对象: 在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息 * 表单事件: 获取表单的值 * 1.监听表单的改变事件 ---onChange * 2.在改变的事件里面获取表单输入的值 ---event * 3.把表单输入的值赋值给username

Vue双向数据绑定的手动实现

class Asarua { // 传入一个对象,也就是实例化的时候的参数 constructor(options) { this.$data = options.data; // 获取挂载的dom this.$el = document.querySelector(options.el); this.$methods = options.methods; this.$options = options; // 定义一个容器,来存放所有的订阅者 this.observable = {}; thi

vue双向数据绑定

父组件引用子组件时,可以使用 v-model="params"  绑定一个变量, 在子组件中,需要使用props去接收一个value变量,即父组件绑定到的params的值 在子组件中,使用this.$emit("input" , someData); 可以触发父组件的input事件,someData是参数,它的值会赋给父组件的params的变量. 这种写法是一种简化的写法,是vue的语法糖.他也可以写成 <v-children v-bind:value=&qu

vue 双向数据绑定原理

采用defineProperty的两个方法get.set 示例 1 <!-- 表单 --> 2 <input type="text" id="input"> 3 <!-- 展示 --> 4 <p id="desc"></p> 1 let obj = {}; 2 let temp = {};//采用临时变量代理obj 3 Object.defineProperty(obj,'name',{

vue双向数据绑定原理

1.实现一个数据监听器Observer,能够对数据对象的所有属性进行监听,如有变动可拿到最新值通知订阅者2.实现一个指令解析器Compile,对每个元素节点的指令进行扫描和解析,以及绑定相应的更新函数3.实现一个Watcher,作为连接Observer和Compile的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数,从而更新视图4.mvvm入口,整合以上三者 原文地址:https://blog.51cto.com/13550695/2467904