一.index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Vue双向绑定原理</title>
<script src="js/myVue.js"></script>
</head>
<body>
<div id="myApp">
<input type="text" style="width:200px" v-model="value">
<button v-on:click="fn">清空</button>
<div v-text="value"></div>
<div v-html="value"></div>
</div>
</body>
<script>
var vm = new MyVue({
el: "#myApp",
data: {
value: "<h1>VUE</h1>"
},
methods: {
fn() {
this.value = "";
}
}
})
</script>
</html>

二.myVue.js

function MyVue(options){// 创建构造函数MyVue,并接收对象结构体options
this.$el=document.querySelector(options.el);// 指定挂载元素
this.$data=options.data;// 存放你的数据内容
this.$methods=options.methods;// 存放设你的方法
this.binding={};// 所有数据相关的订阅者对象都存放于此。最终结构为{数据属性:[订阅者对象,订阅者对象……]}
this.observer();// 调用观察者,对数据进行劫持
this.compile(this.$el);// 对元素指令进行解析,订阅者也是在此处创建的
}
MyVue.prototype.observer=function(){// 观察者
let value="";// 定义用于存放数据属性值的变量value
for(let key in this.$data){ // 遍历数据对象
value=this.$data[key];// 对象属性值
this.binding[key]=[];// 数据订阅者初始化,是一个数组,
let binding=this.binding[key];// 用于存放本数据相关的所有订阅者,初始为[]
Object.defineProperty(this.$data,key,{// 开始设置劫持
get(){
return value;// 读取值为value
},
set(v){// v为设置的值
if(v!==value){// 当设置的值与当前值不相等时
value=v;// 将读取值更新为v
binding.forEach(watcher=>{
watcher.update();// 通知与本数据相关的订阅者们进行视图更新
})
}
}
})
}
}
MyVue.prototype.compile=function(el){// 解析器
let nodes=el.children;// 获得所有子节点
for(let i=0;i<nodes.length;i++){// 对子节点进行遍历
let node=nodes[i];// 具体节点
if(node.children.length>0)// 判断是否具有子节点
this.compile(node);// 如果有子点进行递归操作
if(node.hasAttribute("v-on:click")){// 该节点是否拥有v-on指令
let attrVal=node.getAttribute("v-on:click");// 得到指令对应的方法名
// 为元素绑定click事件,事件方法为$methods下的方法,并将其this指向this.$data
node.addEventListener("click",this.$methods[attrVal].bind(this.$data))
}
if(node.hasAttribute("v-model")){// 该节点是否拥有v-model指令
let attrVal=node.getAttribute("v-model");// 获得指令对应的数据属性
node.addEventListener("input",((i)=>{// 为指令添加input事件
this.binding[attrVal].push(new Watcher(node,"value",this,attrVal));// 为该数据添加订阅者
return ()=>{
this.$data[attrVal]=nodes[i].value;// 更新$data的属性值,会在观察者中进行劫持
}
})(i))
}
if(node.hasAttribute("v-html")){// 该节点是否拥有v-html指令
let attrVal=node.getAttribute("v-html");// 获得指令对应的数据属性
this.binding[attrVal].push(new Watcher(node,"innerHTML",this,attrVal));
}
if(node.hasAttribute("v-text")){// 该节点是否拥有v-text指令
let attrVal=node.getAttribute("v-text");// 获得指令对应的数据属性
this.binding[attrVal].push(new Watcher(node,"innerText",this,attrVal));
}
}
}
function Watcher(el,attr,vm,val){// 观察者
this.el=el; // 指令所在的元素
this.attr=attr;// 绑定的属性名
this.vm=vm; // 指令所在实例
this.val=val; // 指令的值
this.update(); // 更新视图view
}
Watcher.prototype.update=function(){
this.el[this.attr]=this.vm.$data[this.val];
}

三.效果图

Vue双向绑定实现原理demo的更多相关文章

  1. vue双向绑定的原理及实现双向绑定MVVM源码分析

    vue双向绑定的原理及实现双向绑定MVVM源码分析 双向数据绑定的原理是:可以将对象的属性绑定到UI,具体的说,我们有一个对象,该对象有一个name属性,当我们给这个对象name属性赋新值的时候,新值 ...

  2. 最近老是有兄弟问我,Vue双向绑定的原理,以及简单的原生js写出来实现,我就来一个最简单的双向绑定,原生十行代码让你看懂原理

    废话不多说直接看效果图 代码很好理解,但是在看代码之前需要知道Vue双向绑定的原理其实就是基于Object.defineProperty 实现的双向绑定 官方传送门 这里我们用官方的话来说Object ...

  3. vue双向绑定的原理

    什么是双向数据绑定?Vue是一个MVVM框架,数据绑定简单来说,就是当数据发生变化时,相应的视图会进行更新,当视图更新时,数据也会跟着变化. 实现数据绑定的方式大致有以下几种: - 1.发布者-订阅者 ...

  4. vue双向绑定原理分析

    当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/jiangzhenf ...

  5. Vue双向绑定原理及其实现

    在之前面试的时候被面试官问到是否了解Vue双向绑定的原理,其实自己之前看过双向绑定的原理,但也就是粗略的了解,但是没有深入.面试官当时让我手写一个原理,但是就蒙了

  6. vue双向绑定原理源码解析

    当我们学习angular或者vue的时候,其双向绑定为我们开发带来了诸多便捷,今天我们就来分析一下vue双向绑定的原理. 简易vue源码地址:https://github.com/maxlove123 ...

  7. 关于网上大量对Vue双向绑定的错误理解

    对于Vue的双向绑定,现在基本是个前端都听说过,面试官也喜欢问这个问题.但对于Vue双向绑定的原理,掘金.博客园和segmentfault等技术社区充斥着大量的错误文章.这些文章的题目基本样子如下 “ ...

  8. [Vue源码]一起来学Vue双向绑定原理-数据劫持和发布订阅

    有一段时间没有更新技术博文了,因为这段时间埋下头来看Vue源码了.本文我们一起通过学习双向绑定原理来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫 ...

  9. Vue双向绑定原理,教你一步一步实现双向绑定

    当今前端天下以 Angular.React.vue 三足鼎立的局面,你不选择一个阵营基本上无法立足于前端,甚至是两个或者三个阵营都要选择,大势所趋. 所以我们要时刻保持好奇心,拥抱变化,只有在不断的变 ...

随机推荐

  1. spring MVC--配置注解

    <context-param> 作用:该元素用来声明应用范围(整个WEB项目)内的上下文初始化参数 param-name 设定上下文的参数名称.必须是唯一名称 param-value 设定 ...

  2. ffmpeg捕捉摄像头发送rtmp

    打印 DirectShow 支持的设备列表(true 可用1替换): ffmpeg -list_devices true -f dshow -i dummy 本计算机打印出的信息如下:[dshow @ ...

  3. luogu1776宝物筛选

    多重背包问题 一开始我们的转移方程是 ;i<=n;i++) for(int j=m;j>=w[i];j--) ;k<=c[i];k++) )dp[j]=max(dp[j],dp[j- ...

  4. ACM学习历程—HDU4969 Just a Joke(物理题)

    Just a Joke Description Here is just a joke, and do not take it too seriously. Guizeyanhua is the pr ...

  5. [转] jquery操作select(取值,设置选中)

    每一次操作select的时候,总是要出来翻一下资料,不如自己总结一下,以后就翻这里了. 比如<select class="selector"></select&g ...

  6. (转)python set 用法

    转载自:http://hi.baidu.com/����_xu/blog/item/5b9650c513bd3f049d163d8b .html python的set和其他语言类似, 是一个 基本功能 ...

  7. Azure PIP (Instance Level Public IP)

    微软的Azure平台已经支持Instance Level Public IP功能.当有复杂协议的情况下,需要开启多个端口的情况下,可以考虑开启PIP功能. 先介绍几个概念: VIP – virtual ...

  8. netty中的引导Bootstrap客户端

    一.Bootstrap Bootstrap 是 Netty 提供的一个便利的工厂类, 我们可以通过它来完成 Netty 的客户端或服务器端的 Netty 初始化.下面我以 Netty 源码例子中的 E ...

  9. Java父类构造器的讲解

    众所周知,对于Java中的所有类而言,它们有一个根父类,即java.lang.Object类. 对于Java中构造器执行的顺序而言,程序执行的顺序为,先执行父类的非静态代码块,然后执行父类的相应的构造 ...

  10. C# 利用委托和事件 传入一个参数进行进行计算并返回结果

    一.委托定义 1: public class TestData 2: { 3: //定义委托 4: public delegate void Get_TestDataEventHandler(Get_ ...