文档章节

Vue.js双向绑定的实现原理

别人说我名字很长
 别人说我名字很长
发布于 2016/12/10 00:08
字数 359
阅读 37
收藏 0
<!DOCTYPE html>
<html>
<head>
	<title>Vue.js双向绑定的实现原理</title>
</head>
<body>
<div id="app">
	<input type="text" v-model="text">
	{{ text }}
</div>

<script type="text/javascript">


//订阅者
function Dep(){
	this.subs = [];
}

Dep.prototype = {
	addSub:function(sub){
		this.subs.push(sub);
	},
	notify:function(){
		this.subs.forEach(function(sub){
			sub.update();
		});
	}
}

//发布者
function Watcher (vm, node, name) {
	Dep.target = this;	
	this.name = name;
	this.node = node;
	this.vm = vm;
	this.update();
	Dep.target = null;
}

Watcher.prototype = {
	update: function () {
		this.get();
		this.node.nodeValue = this.value;
	},
	// 获取data中的属性值
	get: function () {
		this.value = this.vm[this.name]; // 触发相应属性的get
	}
}


//对象访问器
function defineReactive(obj,key,val) {
	var dep = new Dep();
	Object.defineProperty(obj,key,{
		get:function(){
			// 添加订阅者watcher到主题对象Dep
			if(Dep.target)dep.addSub(Dep.target);
			console.log(dep.subs)
			return val;
		},
		set:function(newVal){
			if(newVal === val) return;
			val=newVal;
			//作为发布者发布通知
			dep.notify();
			console.log(val);
		}
	})
}

//观察者,观察data对象的变更,使用Object.defineProperty添加订阅者和发布通知
function observe(obj,vm){
	Object.keys(obj).forEach(function(key){
		defineReactive(vm,key,obj[key]);
	});
}

//编译方法
function compile(node,vm){
	var reg = /\{\{(.*)\}\}/;

	//节点类型为元素
	if(node.nodeType === 1){
		var attr = node.attributes;
		for(var i=0;i<attr.length;i++){
			if(attr[i].nodeName == 'v-model'){
				var name = attr[i].nodeValue;
				node.addEventListener('input',function(e){
					vm[name] = e.target.value;
				});
				node.value = vm[name];
				node.removeAttribute('v-model');
			}
		}
	}

	//节点类型为text
	if(node.nodeType ===3){
		if(reg.test(node.nodeValue)){
			var name = RegExp.$1;
			name = name.trim();
			new Watcher(vm,node,name);
		}
	}
}

//使用DocumentFragment劫持挂载的目标节点
function nodeToFragment(node,vm){
	var flag = document.createDocumentFragment();
	var child;
	while(child = node.firstChild){
		compile(child,vm);
		flag.append(child);
	}
	return flag;
}

function Vue(options){
	this.data = options.data;
	var data = this.data;

	observe(data,this);

	var id = options.el;
	var dom = nodeToFragment(document.getElementById(id),this);
	//编译完成后将dom返回到app中
	document.getElementById(id).appendChild(dom);
}

var vm = new Vue({
	el:'app',
	data:{
		text:'hello world'
	}
})
</script>
</body>
</html>

 

本文转载自:http://www.cnblogs.com/kidney/p/6052935.html?utm_source=gold_browser_extension

共有 人打赏支持
别人说我名字很长
粉丝 55
博文 250
码字总数 101239
作品 0
济南
程序员
深入理解Vue的watch实现原理及其实现方式

理解Vue中Watch的实现原理和方式之前,你需要深入的理解MVVM的实现原理,如果你还不是很理解,推荐你阅读我之前的几篇文章: 彻底搞懂Vue针对数组和双向绑定(MVVM)的处理方式 vue.js源码解读...

wangweianger
05/14
0
0
Vue和React数据绑定对比

在数据绑定上来说,vue的特色是双向数据绑定,而在react中是单向数据绑定。 一 单向和双向数据绑定其实不是完全没关系的 表单的双向绑定,说到底不过是 (value 的单向绑定 + onChange 事件侦...

pattyzzh
05/14
0
0
西安电话面试:谈谈Vue数据双向绑定原理,看看你的回答能打几分

最近我参加了一次来自西安的电话面试(第二轮,技术面),是大厂还是小作坊我在这里按下不表,先来说说这次电面给我留下印象较深的几道面试题,这次先来谈谈Vue的数据双向绑定原理。 情景再现...

闰土大叔
04/25
0
0
关于Vue和React区别的一些笔记

这篇文章记录我在使用Vue和React的时候,对他们的不同之处的一些思考,不仅局限于他们本身,也会包括比如 等经常搭配使用的工具。因为涉及到的内容很多,可能下面的每一个点都能写成一篇文章...

言川
07/30
0
0
160行代码仿Vue实现极简双向绑定[详细注释]

前言 现在的前端面试不管你用的什么框架,总会问你这个框架的双向绑定机制,有的甚至要求你现场实现一个双向绑定出来,那对于没有好好研究过这方面知识的同学来说,当然是很难的,接下来本文...

OBKoro1
06/25
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

又一个centos文件顺序导致的问题

背景 新的centos似乎对于文件顺序做了特别的优化 和文件顺序出现的问题确实多了不少 centos7导致的spring循环依赖【实际上和这个问题不一样 不过由此衍生出的问题】 某应用放在新的系统开始报...

Mr_Qi
11分钟前
0
0
阿里云国际版香港CN2测评 月付9美元/30M带宽/1T流量

市面上很多家香港VPS服务商,一直都说阿里云国际版香港CN2线路好,延迟低,速度快,价格便宜流量还多,那么这个香港线路到底怎么样呢?本文从性能、延时、路由、速度方面来全方面测评一下阿里...

flyzy2005
54分钟前
0
0
撤销git commit --amend

it commit -amend之后想撤销 git reset HEAD@{1}

xiaomge
59分钟前
0
0
有意思的TimeUnit

java.util.concurrent.TimeUnit 这个类,相信童鞋们都不陌生。它是一个enum: public enum TimeUnit 好吧,我一直把它当做一个枚举类来用。偶然看到还有别的用法,大吃一斤,原来 TimeUnit 并...

polly
今天
10
0
生成pyc

Python生成pyc文件 pyc文件是py文件编译后生成的字节码文件(byte code)。pyc文件经过python解释器最终会生成机器码运行。所以pyc文件是可以跨平台部署的,类似Java的.class文件。一般py文件改...

Mr_Tea伯奕
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部