我是靠谱客的博主 尊敬音响,最近开发中收集的这篇文章主要介绍手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

最近学习vue,网上的手写双向绑定原理都是极简版的,读了很多源码解析,决定手写个复杂版的双向绑定!
html部分

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	<script src="双向绑定原理.js" ></script>
	<div class="test">
		<div h-html='a'></div>
		<div @click='test'>{{a}}</div>
		<input type="text" h-model='a'>
	</div>
	<script>
		new he({
			el:'.test',
			data: {
				a: 1,
				b: 2
			},
			methods:{
				test(){
					alert('test')
				}
			}
		})
	</script>
</body>
</html>

js部分

//用es6写的,这样感觉更便于理解,这个he就相当于Vue啦!
class he {
	constructor(options={}){//这里就是你new Vue()的时候传的对象
		this.$options = options;
		if (options.el) //vue里一大堆$开头的玩意都是这样挂上去的,不一一列举,重点说一下$data
			this.$el = document.querySelector(options.el);
		if (options.data) //有没有奇怪为什么vue开发时,this.xxx就可以访问data下的xxx属性?就是因为接下来这一坨代码!
			this.$data = options.data;
			const arr = Object.keys(this.$data);//遍历$data生成一个包含所有data属性的数组
			let len = arr.length;
			while(len--){//这里遍历数组给每个属性添加代理
				let key = arr[len];
				Object.defineProperty(this, key, {
					get(){
						return this.$data[key];
					},
					set(v){
						this.$data[key] = v;
					}
				})
			}
		if (options.methods) 
			this.$methods = options.methods;
		this.observer = {};//订阅中心:{str: []}属性为this.$data中被订阅的属性,值为订阅者形成的数组
		this.createObServer();//创建订阅中心
		this.compile(this.$el);//编译dom元素到浏览器
	}

	createObServer(){
		let _this = this//set时this指向不对,这里先保存一下
		for(let key in this.$data){
			//为this.$data中每一个属性生成发布者
			this.observer[key] = [];
			let value = this.$data[key]
			Object.defineProperty(this.$data, key, {
				get(){
					return value;
				},
				set(v){
					value = v;
					//当数据被改变时,通知所有订阅者更新数据
					_this.observer[key].forEach(v=>{
						v.update();
					})
				}
			})
		}
	}
	//编译器
	compile(el){
		const nodes = el.children;
		for(let i = 0;i<nodes.length;i++){
			const node = nodes[i];
			this.compile(node);//这里递归遍历出所有节点
			if (node.hasAttribute('@click')) {//添加事件都这样
				const attrValue = node.getAttribute('@click');
				node.addEventListener('click', this.$methods[attrValue]);
			}
			if(node.hasAttribute('h-html')){//添加指令都这样
				 const attrValue = node.getAttribute("h-html");
				this.observer[attrValue].push(new Watcher(node, 'innerHTML', this.$data, attrValue))
			}
			if(node.hasAttribute(':value')){
				 const attrValue = node.getAttribute(":value");
				this.observer[attrValue].push(new Watcher(node, 'value', this.$data, attrValue))
			}
			if(node.hasAttribute('h-model')){//特殊指令,v-model
				const attrValue = node.getAttribute('h-model');
				node.addEventListener('input', (e)=>{
					this.$data[attrValue] = e.target.value
				})
				this.observer[attrValue].push(new Watcher(node, 'value', this.$data, attrValue))
			}
			if(/{{(.*)}}/.test(node.textContent)){//这里是双大括号{{}}的特殊指令,不要吐槽我没有把正则保存成变量,懒得改了!
				this.observer[/{{(.*)}}/.exec(node.textContent)[1]].push(new Watcher(node, 'innerText', this.$data, /{{(.*)}}/.exec(node.textContent)[1]))
			}
		}
	}
}
//订阅者
class Watcher{
	constructor(el, props, data, key){
		this.el = el;
		this. props = props;
		this.data = data;
		this.key = key;
		this.update()
	}

	update(){//订阅者更新数据
		this.el[this.props] = this.data[this.key];
	}
}

最后

以上就是尊敬音响为你收集整理的手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理的全部内容,希望文章能够帮你解决手写vue源码,包括双向绑定原理(基于发布订阅模式的复杂版),指令原理,this.$data代理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部